Optimierung der Flask-Anwendungsleistung

Flask ist ein leichtgewichtiges und flexibles Web-Framework zur Entwicklung von kleinen bis mittelgroßen Anwendungen. Entwickler nutzen es häufig für Projekte, die von einfachen persönlichen Blogs bis hin zu komplexen Anwendungen reichen, darunter REST-APIs, SaaS-Plattformen, E-Commerce-Websites und datengesteuerte Dashboards.

Steigt der Datenverkehr oder wächst die Komplexität der Anwendung, treten oft Leistungsengpässe auf. Unabhängig davon, ob Sie ein Content-Management-System (CMS), eine API für eine mobile App oder ein Echtzeit-Datenvisualisierungstool entwickeln – die Optimierung der Flask-Leistung spielt eine zentrale Rolle für eine reaktionsschnelle und skalierbare Benutzererfahrung.

Dieses Tutorial zeigt Ihnen verschiedene Techniken und bewährte Methoden zur Optimierung der Leistung einer Flask-Anwendung.

Voraussetzungen

  • Ein Server mit Ubuntu sowie ein nicht-root Benutzer mit sudo-Rechten und aktivierter Firewall. Bitte stellen Sie sicher, dass Sie eine unterstützte Version von Ubuntu verwenden.
  • Grundkenntnisse in der Linux-Kommandozeile.
  • Grundlegendes Verständnis der Python-Programmierung.
  • Python 3.7 oder höher auf Ihrem Ubuntu-System.

Einrichtung Ihrer Flask-Umgebung

Ubuntu 24.04 wird standardmäßig mit Python 3 ausgeliefert. Öffnen Sie das Terminal und führen Sie den folgenden Befehl aus, um die Installation von Python 3 zu überprüfen:

root@ubuntu:~# python3 --version
Python 3.12.3

Falls Python 3 bereits auf Ihrem System installiert ist, gibt der obige Befehl die aktuelle Version der Python 3-Installation zurück. Falls es nicht installiert ist, können Sie den folgenden Befehl ausführen, um Python 3 zu installieren:

root@ubuntu:~# sudo apt install python3

Als Nächstes müssen Sie den Paketmanager pip auf Ihrem System installieren:

root@ubuntu:~# sudo apt install python3-pip

Sobald pip installiert ist, können Sie Flask installieren.

Es wird empfohlen, Flask in einer virtuellen Umgebung zu installieren, um Konflikte mit anderen Paketen auf Ihrem System zu vermeiden.


root@ubuntu:~# python3 -m venv myprojectenv
root@ubuntu:~# source myprojectenv/bin/activate


root@ubuntu:~# pip install Flask

Erstellen einer Flask-Anwendung

Der nächste Schritt besteht darin, den Python-Code für die Flask-Anwendung zu schreiben. Navigieren Sie dazu in das Verzeichnis Ihrer Wahl:

root@ubuntu:~# cd ~/path-to-your-script-directory

Erstellen Sie in diesem Verzeichnis eine neue Python-Datei app.py und importieren Sie Flask. Initialisieren Sie dann eine Flask-Anwendung und erstellen Sie eine grundlegende Route.

root@ubuntu:~# nano app.py

Dadurch wird ein leerer Texteditor geöffnet. Schreiben Sie Ihre Logik oder kopieren Sie den folgenden Code:

app.py

from flask import Flask, jsonify, request 

app = Flask(__name__) 

# Simulieren eines langsamen Endpunkts 
@app.route('/slow') 
def slow(): 
    import time 
    time.sleep(2) # Simulation einer langsamen Antwort 
    return jsonify(message="Diese Anfrage war langsam!") 

# Simulieren einer intensiven Datenbankoperation 
@app.route('/db') 
def db_operation(): 
    # Dies ist eine Dummy-Funktion zur Simulation einer Datenbankabfrage 
    result = {"name": "Benutzer", "email": "benutzer@example.com"} 
    return jsonify(result) 

# Simulieren der Bereitstellung einer statischen Datei 
@app.route('/') 
def index(): 
   return "<h1>Willkommen zur Beispiel-Flask-Anwendung</h1>" 

if __name__ == '__main__': 
    app.run(debug=True)

Nun starten Sie die Flask-Anwendung:

Testen des /-Endpunkts (liefert statischen Inhalt)

Sie können die Endpunkte mit den folgenden curl-Befehlen testen:

root@ubuntu:~# curl http://127.0.0.1:5000/

Ausgabe

[secondary_lebel Output] <h1>Willkommen zur Beispiel-Flask-Anwendung</h1>%

Testen des /slow-Endpunkts (simuliert eine langsame Antwort)

root@ubuntu:~# time curl http://127.0.0.1:5000/slow

Um diesen langsamen Endpunkt zu überprüfen, verwenden Sie den Befehl time in Linux. Dieser Befehl misst die Ausführungszeit eines bestimmten Befehls oder Programms. Er liefert drei Hauptinformationen:

  • Reale Zeit: Die tatsächlich verstrichene Zeit vom Start bis zum Ende des Befehls.
  • User-Zeit: Die Menge der CPU-Zeit, die im Benutzermodus verbracht wurde.
  • System-Zeit: Die Menge der CPU-Zeit, die im Kernel-Modus verbracht wurde.

Dies hilft dabei, die tatsächliche Zeit zu messen, die von unserem langsamen Endpunkt benötigt wird. Die Ausgabe könnte wie folgt aussehen:

Ausgabe

{"message":"Diese Anfrage war langsam!"} 
curl http://127.0.0.1:5000/slow 0.00s user 0.01s system 0% cpu 2.023 total

Diese Anfrage benötigt etwa 2 Sekunden, um zu antworten, da der Befehl time.sleep(2) eine langsame Antwort simuliert.

Testen des /db-Endpunkts (Simulation einer Datenbankoperation)

root@ubuntu:~# curl http://127.0.0.1:5000/db

Ausgabe

{"email":"benutzer@example.com","name":"Benutzer"}

Mit curl testen Sie die Endpunkte und stellen sicher, dass Ihre Flask-Anwendung korrekt läuft und die erwarteten Antworten liefert.

Der nächste Abschnitt zeigt Ihnen, wie Sie die Leistung der Anwendung mit verschiedenen Optimierungstechniken verbessern.

Verwenden eines produktionsbereiten WSGI-Servers

Der in Flask integrierte Entwicklungsserver eignet sich nicht für Produktionsumgebungen. Um parallele Anfragen effizient zu verarbeiten, empfiehlt sich ein produktionsbereiter WSGI-Server wie Gunicorn.

Installation und Einrichtung von Gunicorn

Installieren Sie Gunicorn mit folgendem Befehl:

root@ubuntu:~# pip install gunicorn

Starten Sie die Flask-Anwendung mit Gunicorn unter Verwendung von vier Worker-Prozessen:

root@ubuntu:~# gunicorn -w 4 -b 0.0.0.0:8000 app:app

Ausgabe

% /Library/Python/3.9/bin/gunicorn -w 4 -b 0.0.0.0:8000 app:app 
[2024-09-13 18:37:24 +0530] [99925] [INFO] Starting gunicorn 23.0.0 
[2024-09-13 18:37:24 +0530] [99925] [INFO] Listening at: http://0.0.0.0:8000 (99925) 
[2024-09-13 18:37:24 +0530] [99925] [INFO] Using worker: sync 
[2024-09-13 18:37:24 +0530] [99926] [INFO] Booting worker with pid: 99926 
[2024-09-13 18:37:25 +0530] [99927] [INFO] Booting worker with pid: 99927 
[2024-09-13 18:37:25 +0530] [99928] [INFO] Booting worker with pid: 99928 
[2024-09-13 18:37:25 +0530] [99929] [INFO] Booting worker with pid: 99929 
[2024-09-13 18:38:51 +0530] [99925] [INFO] Handling signal: int 
[2024-09-13 18:38:51 +0530] [99927] [INFO] Worker exiting (pid: 99927) 
[2024-09-13 18:38:51 +0530] [99926] [INFO] Worker exiting (pid: 99926) 
[2024-09-13 18:38:51 +0530] [99928] [INFO] Worker exiting (pid: 99928) 
[2024-09-13 18:38:51 +0530] [99929] [INFO] Worker exiting (pid: 99929) 
[2024-09-13 18:38:51 +0530] [99925] [INFO] Shutting down: Master

Vorteile der Verwendung von Gunicorn

  • Gleichzeitige Anfragenbearbeitung: Gunicorn verarbeitet mehrere Anfragen parallel durch den Einsatz mehrerer Worker-Prozesse.
  • Lastverteilung: Worker-Prozesse übernehmen die eingehenden Anfragen effizient, um die Server-Ressourcen optimal zu nutzen.
  • Asynchrone Worker: Asynchrone Worker wie Gevent ermöglichen die Verarbeitung langlaufender Prozesse, ohne andere Anfragen zu blockieren.
  • Skalierbarkeit: Durch zusätzliche Worker-Prozesse lässt sich Gunicorn an eine höhere Anzahl gleichzeitiger Anfragen anpassen.
  • Fehlertoleranz: Fehlerhafte oder abgestürzte Worker werden automatisch ersetzt, um eine hohe Verfügbarkeit sicherzustellen.
  • Produktionsreife: Im Gegensatz zum Flask-Entwicklungsserver bietet Gunicorn mehr Sicherheit, Stabilität und Leistung für den produktiven Einsatz.

Gunicorn verbessert die Leistung und Reaktionsfähigkeit Ihrer Flask-Anwendung erheblich und macht sie fit für echten Datenverkehr.

Caching aktivieren, um die Serverlast zu reduzieren

Caching optimiert die Leistung von Flask, indem redundante Prozesse vermieden werden. In diesem Beispiel kommt Flask-Caching zum Einsatz, um das Ergebnis des /slow-Endpunkts zwischenzuspeichern.

Installation und Konfiguration von Flask-Caching mit Redis

Installieren Sie die benötigten Pakete:

root@ubuntu:~# pip install Flask-Caching redis

Öffnen Sie den Editor und aktualisieren Sie die Datei app.py mit folgendem Code:

app.py

from flask_caching import Cache 

app = Flask(__name__) 

# Konfiguration von Flask-Caching mit Redis 
app.config['CACHE_TYPE'] = 'redis' 
app.config['CACHE_REDIS_HOST'] = 'localhost' 
app.config['CACHE_REDIS_PORT'] = 6379 

cache = Cache(app) 

@app.route('/slow') 
@cache.cached(timeout=60) 
def slow(): 
    import time 
    time.sleep(2) # Simulieren einer langsamen Antwort 
    return jsonify(message="Diese Anfrage war langsam!")

Nach der ersten Anfrage an /slow liefert der Cache alle weiteren Anfragen innerhalb von 60 Sekunden direkt aus. Dadurch sinkt die Serverlast, und die Antwortzeiten verbessern sich.

Überprüfung der gecachten Daten

Führen Sie die folgenden Befehle für den /slow-Endpunkt aus, um zu prüfen, ob die Daten zwischengespeichert werden.

Erste Anfrage an den /slow-Endpunkt

Diese Anfrage speichert das Ergebnis der Route /slow zwischen.

root@ubuntu:~# time curl http://127.0.0.1:5000/slow

Ausgabe

{"message":"Diese Anfrage war langsam!"} 
curl http://127.0.0.1:5000/slow 0.00s user 0.01s system 0% cpu 2.023 total

Folgende Anfrage an den /slow-Endpunkt innerhalb von 60 Sekunden

root@ubuntu:~# time curl http://127.0.0.1:5000/slow

Ausgabe

{"message":"Diese Anfrage war langsam!"} 
curl http://127.0.0.1:5000/slow 0.00s user 0.00s system 0% cpu 0.015 total

Datenbankabfragen optimieren

Datenbankabfragen können häufig zu einem Leistungsengpass werden. In diesem Abschnitt wird die Optimierung von Datenbankabfragen mit SQLAlchemy und Connection Pooling simuliert.

Simulieren einer Datenbankabfrage mit Connection Pooling

Zunächst wird SQLAlchemy installiert:

root@ubuntu:~# pip install Flask-SQLAlchemy

Aktualisieren von app.py zur Konfiguration von Connection Pooling

app.py

from flask_sqlalchemy import SQLAlchemy 
from sqlalchemy import text 

# Simulieren einer intensiven Datenbankoperation 
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db' 
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 
app.config['SQLALCHEMY_POOL_SIZE'] = 5 # Größe des Connection Pools 

db = SQLAlchemy(app) 

@app.route('/db1') 
def db_operation_pooling(): 
    # Simulieren einer Datenbankabfrage 
    result = db.session.execute(text('SELECT 1')).fetchall() 
    return jsonify(result=str(result))

Führen Sie eine Curl-Anfrage an die Route /db1 aus

root@ubuntu:~# curl http://127.0.0.1:5000/db1

Ausgabe

Gzip-Komprimierung aktivieren

Durch die Komprimierung der Antworten kann die übertragene Datenmenge zwischen Ihrem Server und den Clients erheblich reduziert und die Leistung verbessert werden.

Installation und Konfiguration von Flask-Compress

Installieren Sie das Flask-Compress-Paket:

root@ubuntu:~# pip install Flask-Compress

Aktualisieren von app.py, um die Komprimierung zu aktivieren

app.py

from flask_compress import Compress 

# Aktivieren der Gzip-Komprimierung für die Flask-App 
# Die Antworten werden vor dem Senden an die Clients komprimiert, 
# wodurch der Datenverkehr reduziert und die Leistung verbessert wird 
Compress(app) 

@app.route('/compress') 
def compress_response(): 
    return "<h1>Willkommen zur Beispiel-Flask-Anwendung</h1>"

Auslagerung ressourcenintensiver Aufgaben an Celery

Für ressourcenintensive Operationen wie das Senden von E-Mails oder die Verarbeitung großer Datenmengen ist es am besten, diese in Hintergrundaufgaben mit Celery auszulagern. Dadurch wird verhindert, dass lang andauernde Aufgaben eingehende Anfragen blockieren.

Warum Celery verwenden?

  • Verbesserte Antwortzeiten: Benutzeranfragen werden schneller abgeschlossen, da rechenintensive Aufgaben an Worker ausgelagert werden.
  • Bessere Skalierbarkeit: Celery kann Aufgaben auf mehrere Maschinen verteilen.
  • Bearbeitung komplexer Aufgaben: Nützlich für umfangreiche Berechnungen und lang andauernde Hintergrundprozesse.
  • Task-Scheduling: Eingebaute Unterstützung für periodische Aufgaben und Wiederholungsversuche.
  • Integration mit Message-Brokern: Unterstützt Redis, RabbitMQ und andere für asynchrone Verarbeitung.

Durch die Nutzung von Celery können Sie sicherstellen, dass Ihre Flask-Anwendung reaktionsschnell bleibt, selbst bei der Verarbeitung von komplexen oder I/O-intensiven Aufgaben.

Einrichtung von Celery für Hintergrundaufgaben

Installieren Sie Celery mit folgendem Befehl:

root@ubuntu:~# pip install Celery

Aktualisieren von app.py, um Celery für asynchrone Aufgaben zu konfigurieren

app.py

from celery import Celery

celery = Celery(app.name, broker='redis://localhost:6379/0')

@celery.task
def long_task():
    import time
    time.sleep(10)  # Simulation einer lang andauernden Aufgabe
    return "Task Complete"

@app.route('/start-task')
def start_task():
    long_task.delay()
    return 'Task gestartet'

Starten des Celery-Workers in einem separaten Terminal

root@ubuntu:~# celery -A app.celery worker --loglevel=info

Ausgabe

------------- celery@your-computer-name v5.2.7 (dawn-chorus)
--- ***** ----- 
-- ******* ---- Linux-x.x.x-x-generic-x86_64-with-glibc2.xx 2023-xx-xx
- *** --- * --- 
- ** ---------- [config]
- ** ---------- .> app:         app:0x7f8b8c0b3cd0
- ** ---------- .> transport:   redis://localhost:6379/0
- ** ---------- .> results:     disabled://
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery

[tasks]
  . app.long_task

[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] Connected to redis://localhost:6379/0
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] mingle: searching for neighbors
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] mingle: all alone
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] celery@your-computer-name ready.

Auslösen der Aufgabe per Curl-Befehl

root@ubuntu:~# curl http://127.0.0.1:5000/start-task

Ausgabe

Verständnis der Funktion start_task()

  • long_task.delay() startet die Celery-Aufgabe asynchron und setzt sie in die Warteschlange. Die Funktion wartet nicht auf die Fertigstellung.
  • 'Task gestartet' wird sofort als Antwort zurückgegeben.

Celery führt die lang andauernde Aufgabe (simuliert durch das 10-sekündige sleep()) im Hintergrund aus. Die Flask-Route sendet die Antwort sofort, ohne auf den Abschluss der Aufgabe zu warten.

Nach 10 Sekunden erscheint eine Ausgabe ähnlich der folgenden:

[2024-xx-xx xx:xx:xx,xxx: INFO/MainProcess] Task app.long_task[task-id] received
[2024-xx-xx xx:xx:xx,xxx: INFO/ForkPoolWorker-1] Task app.long_task[task-id] succeeded in 10.xxxs: 'Task Complete'

Celery in der Produktion

In einer Produktionsumgebung erfordert die Implementierung von Celery:

  • Einen zuverlässigen Message-Broker wie RabbitMQ.
  • Ein dediziertes Ergebnis-Backend (z. B. PostgreSQL).
  • Eine effiziente Verwaltung der Worker mit Prozesskontrollsystemen (z. B. Supervisor).
  • Monitoring-Tools wie Flower zur Überwachung der Aufgaben.
  • Eine verbesserte Fehlerbehandlung und detailliertes Logging.
  • Eine Priorisierung der Aufgaben zur optimalen Ressourcennutzung.
  • Eine skalierbare Architektur mit mehreren Workern auf verschiedenen Maschinen.
  • Robuste Sicherheitsmaßnahmen für einen sicheren Betrieb.

Fazit

Dieses Tutorial hat gezeigt, wie Sie eine Flask-Anwendung mit verschiedenen leistungssteigernden Techniken optimieren. Mit diesen Schritten steigern Sie die Leistung, Skalierbarkeit und Reaktionsfähigkeit Ihrer Anwendung und stellen sicher, dass sie auch unter hoher Last effizient arbeitet.

Jetzt 200€ Guthaben sichern

Registrieren Sie sich jetzt in unserer ccloud³ und erhalten Sie 200€ Startguthaben für Ihr Projekt.

Das könnte Sie auch interessieren: