Dify Leistungsoptimierung SKILL
Übersicht
Diese SKILL bietet eine umfassende Anleitung zur Leistungsoptimierung von Dify-Workflows und -Plugins. Sie deckt Kernthemen wie Graphstrukturoptimierung, LLM-Kostenkontrolle, Worker-Pool-Tuning, Variablenpool-Optimierung, parallele Verarbeitung und Leistungsüberwachung ab.
Anwendungsszenarien
Verwenden Sie diese SKILL, wenn Sie auf folgende Situationen stoßen:
- ⏱️ Die Workflow-Ausführungszeit ist zu lang und erfordert eine Leistungsoptimierung
- 💰 Die LLM-API-Kosten sind zu hoch und der Token-Verbrauch muss gesenkt werden
- 🚀 Die Fähigkeit zur gleichzeitigen Verarbeitung ist unzureichend und der Durchsatz muss erhöht werden
- 📊 Die Systemressourcenauslastung ist niedrig und die Konfiguration muss optimiert werden
- 📈 Leistungsengpässe bei der Verarbeitung großer Datenmengen
- 🔍 Es ist eine Leistungsdiagnose und -überwachung erforderlich
Kernwerte
- Quantifizierbare Optimierungseffekte: Parallele Verzweigungen reduzieren die Zeit um 40–60 %, LLM-Caching reduziert API-Aufrufe um 30–50 %
- Praxisnahe Beispiele: 5 reale Optimierungsfälle mit Vorher-Nachher-Vergleichen
- Umfassende Optimierungsstrategien: Deckt Workflows, LLMs, Plugins, Überwachung und alle Ebenen ab
- Schnelle Diagnosetools: Eine Leistungsdiagnose-Checkliste für 5 Dimensionen
Schnelle Diagnose-Checkliste
Verwenden Sie die folgende Checkliste, um Leistungsprobleme schnell zu identifizieren, bevor Sie mit der Optimierung beginnen:
📊 Graphstruktur-Diagnose
- Gibt es zu viele serielle Abhängigkeiten?
- Können parallele Verzweigungen verwendet werden? (v0.8.0+)
- Gibt es unnötige Knoten und Verbindungen?
- Übersteigt die Anzahl der Knoten 50?
- Wird ein geeignetes Entwurfsmuster verwendet?
🤖 LLM-Nutzungsdiagnose
- Ist die Modellauswahl geeignet? (Leichte Aufgaben mit leichten Modellen)
- Ist der Prompt zu lang? (Kann er gekürzt werden?)
- Ist das LLM-Antwort-Caching aktiviert?
- Werden strukturierte Ausgaben verwendet? (JSON Schema)
- Liegt der Token-Verbrauch im Budget?
⚙️ Worker-Pool-Diagnose
- Ist die Anzahl der Worker angemessen konfiguriert? (2–8 Threads)
- Ist die Warteschlangentiefe zu groß?
- Gibt es eine Verschwendung durch untätige Worker?
- Ist die Skalierungsstrategie sinnvoll?
💾 Variablenpool-Diagnose
- Werden große Objekte im Variablenpool gespeichert?
- Werden Variablen rechtzeitig bereinigt?
- Werden Referenzen anstelle von Kopien verwendet?
- Ist der Variablenbereich sinnvoll?
🔄 Parallelverarbeitungsdiagnose
- Ist
parallel_numsfür Iteratoren konfiguriert? - Werden Streaming-Antworten verwendet?
- Sind asynchrone Aufgaben angemessen konfiguriert?
- Gibt es blockierende Operationen?
Teil 1: Graphstrukturoptimierung
1.1 Reduzierung serieller Abhängigkeiten
Problem: Zu viele serielle Abhängigkeiten führen zu linearem Wachstum der Workflow-Ausführungszeit.
Optimierungsstrategie:
- Identifizieren Sie parallelisierbare Knoten: Analysieren Sie die Abhängigkeiten zwischen Knoten, um Knoten zu finden, die parallel ausgeführt werden können
- Verwenden Sie parallele Verzweigungen: Dify v0.8.0+ unterstützt die Funktion für parallele Verzweigungen
- Strukturieren Sie den Workflow um: Wandeln Sie serielle Abläufe in ein Parallel-+Aggregations-Muster um
Beispiel:
# Vor Optimierung: Serielle Ausführung (Gesamtzeit = 3 + 2 + 4 = 9 Sekunden)
Start → API-Aufruf1(3s) → API-Aufruf2(2s) → API-Aufruf3(4s) → Ende
# Nach Optimierung: Parallele Ausführung (Gesamtzeit = max(3,2,4) = 4 Sekunden)
Start → [API-Aufruf1(3s), API-Aufruf2(2s), API-Aufruf3(4s)] → Variablenaggregation → Ende
Optimierungseffekt: Ausführungszeit um 40–60 % reduziert
1.2 Parallele Verzweigungsfunktion (v0.8.0+)
Dify v0.8.0 führt eine Funktion für parallele Verzweigungen ein, die es mehreren Zweigen ermöglicht, gleichzeitig ausgeführt zu werden.
Verwendung:
- Erstellen Sie im Workflow-Editor mehrere Zweige
- Stellen Sie sicher, dass keine Datenabhängigkeiten zwischen den Zweigen bestehen
- Verwenden Sie einen Variablenaggregator, um die Ergebnisse zu sammeln
Anwendungsszenarien:
- Gleichzeitige Aufrufe mehrerer HTTP-Request-Knoten
- Gleichzeitige Ausführung mehrerer Tool-Knoten
- Parallele Verarbeitung von Wissensdatenbankabfragen + API-Aufrufen
- Parallele Inferenz mit mehreren Modellen (Modellvergleichsszenarien)
Konfigurationsbeispiel:
# Konfiguration paralleler Verzweigungen
parallel_branches:
- branch_1:
nodes: [http_request_1, code_1]
- branch_2:
nodes: [http_request_2, code_2]
- branch_3:
nodes: [tool_1, llm_1]
1.3 Vermeidung unnötiger Knoten
Häufige Probleme:
- Redundante Datenkonvertierungsknoten
- Unnötige Zwischenvariablenknoten
- Übermäßige Bedingungsknoten
Optimierungsvorschläge:
- Führen Sie ähnliche Verarbeitungslogik zusammen
- Verwenden Sie Code-Knoten anstelle mehrerer einfacher Knoten
- Vereinfachen Sie die Logik von Bedingungsabfragen
1.4 Entwurfsmuster für Graphstrukturen
Wählen Sie basierend auf dem Aufgabentyp ein geeignetes Entwurfsmuster:
- Sequenz-Pipeline: Start → LLM → Ende (einfache Aufgaben)
- Bedingte Verzweigung: Start → LLM → If-Else → Mehrere Pfade (Entscheidungsaufgaben)
- Iterative Verarbeitung: Start → Code → Iteration → LLM (Batch-Aufgaben)
- Wissensabfrage: Start → Knowledge-Retrieval → LLM (RAG-Anwendungen)
- Multi-Quellen-Aggregation: Mehrere Tool/HTTP → Variable-Aggregator → LLM (Datenaggregation)
Ausführliche Dokumentation: Siehe workflow-optimization/graph-structure.md
Teil 2: LLM-Optimierungsstrategien
2.1 Modellauswahlstrategie
Die Auswahl des richtigen Modells ist der Schlüssel zur Kostenoptimierung.
Modellauswahlmatrix:
| Aufgabentyp | Empfohlenes Modell | Token-Kosten | Anwendungsszenario |
|---|---|---|---|
| Einfache Klassifikation | Qwen-Turbo, Gemini Flash | Niedrig | Textklassifikation, Stimmungsanalyse |
| Textgenerierung | GPT-3.5-turbo, Qwen-Plus | Mittel | Inhaltsgenerierung, Zusammenfassungen |
| Komplexes Denken | GPT-4, Claude Opus | Hoch | Komplexe Analysen, Entscheidungen |
| Lokale Bereitstellung | Ollama (Llama 3, Qwen) | Null API-Kosten | Datenschutzsensible Szenarien |
Kostenvergleich:
- GPT-4: 0,03 $/1K Tokens (Eingabe) + 0,06 $/1K Tokens (Ausgabe)
- GPT-3.5-turbo: 0,0015 $/1K Tokens (Eingabe) + 0,002 $/1K Tokens (Ausgabe)
- Qwen-Turbo: ¥0,0008 /1K Tokens (ca. 20-facher Kostenunterschied)
Optimierungsvorschläge:
- Leichte Aufgaben mit leichten Modellen (Qwen/Gemini)
- Komplexe Aufgaben mit leistungsstarken Modellen (GPT-4/Claude)
- Erwägen Sie die Verwendung lokaler Modelle (Ollama) zur Kostensenkung
2.2 Prompt-Optimierungstipps
Prompt kürzen:
# Vor Optimierung (150 Tokens)
"""
Du bist ein professioneller Kundendienstmitarbeiter. Bitte lies die folgende Kundenfrage sorgfältig durch und gib basierend auf unserer Produktwissensdatenbank eine detaillierte, genaue und freundliche Antwort. Beachte bei der Antwort die folgenden Punkte:
1. Bewahre einen professionellen und höflichen Ton
2. Biete konkrete Lösungen an
3. Wenn du dir unsicher bist, gib dies an
4. Zitiere relevante Produktdokumente
Kundenfrage: {query}
"""
# Nach Optimierung (50 Tokens)
"""
Beantworte als Kundendienstmitarbeiter die Kundenfrage basierend auf der Wissensdatenbank, bleibe professionell und höflich.
Frage: {query}
"""
Token-Ersparnis: 66 % (150 → 50 Tokens)
Weitere Optimierungstipps:
- Entfernen Sie redundante Erklärungen und Beispiele
- Verwenden Sie prägnante Anweisungen
- Vermeiden Sie sich wiederholende Kontexte
- Verwenden Sie strukturierte Ausgaben, um Parsing-Kosten zu senken
2.3 Caching-Strategie
LLM-Antwort-Caching:
Verwenden Sie Redis, um LLM-Antworten zu cachen und wiederholte Aufrufe zu vermeiden.
Implementierung:
import hashlib
import redis
# Verbindung zu Redis herstellen
r = redis.Redis(host='localhost', port=6379, db=0)
def get_llm_response_with_cache(prompt, model="gpt-3.5-turbo"):
# Cache-Schlüssel generieren
cache_key = f"llm:{model}:{hashlib.md5(prompt.encode()).hexdigest()}"
# Cache prüfen
cached = r.get(cache_key)
if cached:
return cached.decode('utf-8')
# LLM aufrufen
response = call_llm_api(prompt, model)
# Cache speichern (TTL: 1 Stunde)
r.setex(cache_key, 3600, response)
return response
Caching-Strategie:
- LLM-Antwort-Caching: Gleicher Prompt gibt zwischengespeichertes Ergebnis zurück
- Wissensdatenbank-Abfrage-Caching: Gleiche Abfrage gibt zwischengespeicherte Vektoren zurück
- Knotenergebnis-Caching: Vermeidet wiederholte Ausführung desselben Knotens
Optimierungseffekt: API-Aufrufe um 30–50 % reduziert
2.4 Strukturierte Ausgabe
Verwenden Sie JSON Schema, um die Stabilität der LLM-Ausgabe zu gewährleisten und Parsing-Fehler sowie Wiederholungen zu reduzieren.
Konfigurationsbeispiel:
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["Technisch", "Vertrieb", "Nachverkauf"]
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"summary": {
"type": "string",
"maxLength": 100
}
},
"required": ["category", "priority", "summary"]
}
Optimierungseffekt:
- Reduziert die Anzahl der Ausgabe-Tokens
- Vermeidet Parsing-Fehler und Wiederholungen
- Verbessert die Verarbeitungseffizienz nachgelagerter Knoten
Ausführliche Dokumentation: Siehe llm-optimization/
Teil 3: Worker-Pool-Tuning
3.1 Dynamischer Worker-Thread-Pool
Dify verwendet einen dynamischen Worker-Pool zur parallelen Ausführung von Knoten. Die Standardkonfiguration liegt bei 2–8 Worker-Threads.
Worker-Pool-Architektur:
GraphEngine
├── ReadyQueue (Warteschlange bereiter Knoten)
├── EventQueue (Ereigniswarteschlange)
├── Dispatcher (Ereignisverteiler)
└── WorkerPool (2–8 Worker-Threads)
├── Worker 1
├── Worker 2
├── ...
└── Worker N
3.2 Konfigurationsparameter
Wichtige Konfigurationen:
| Parameter | Standardwert | Beschreibung | Optimierungsvorschlag |
|---|---|---|---|
| min_workers | 2 | Minimale Anzahl an Workern | Entsprechend der minimalen Parallelitätsanforderung einstellen |
| max_workers | 8 | Maximale Anzahl an Workern | Entsprechend der Anzahl der CPU-Kerne einstellen |
| queue_depth_threshold | 10 | Schwellenwert für die Skalierung | Entsprechend der durchschnittlichen Warteschlangentiefe anpassen |
| idle_timeout | 60s | Leerlauf-Timeout für Worker | Entsprechend der Aufgabenfrequenz anpassen |
Skalierungsstrategie:
# Skalierungsbedingung
if queue_depth > queue_depth_threshold and workers < max_workers:
add_worker()
# Verkleinerungsbedingung
if worker_idle_time > idle_timeout and workers > min_workers:
remove_worker()
3.3 Leistungsbenchmarks
Testszenario: Workflow mit 100 Knoten
| Anzahl Worker | Ausführungszeit | Durchsatz | CPU-Auslastung |
|---|---|---|---|
| 2 | 45s | 2,2 Knoten/s | 40% |
| 4 | 25s | 4,0 Knoten/s | 70% |
| 8 | 15s | 6,7 Knoten/s | 95% |
Optimierungseffekt: Erhöhung der Worker-Anzahl von 2 auf 8, Durchsatz um das 3-fache gesteigert
3.4 Optimierungsvorschläge
- max_workers basierend auf CPU-Kernen einstellen: Üblicherweise das 1- bis 2-fache der Anzahl der CPU-Kerne
- Überwachen Sie die Warteschlangentiefe: Wenn die Warteschlangentiefe kontinuierlich hoch ist, erhöhen Sie
max_workers - Übermäßige Skalierung vermeiden: Zu viele Worker verursachen Kontextwechsel-Overhead
- Verwenden Sie asynchrone E/A: Für E/A-intensive Aufgaben verwenden Sie asynchrone Verarbeitung, um die Effizienz zu steigern
Ausführliche Dokumentation: Siehe workflow-optimization/parallel-execution.md
Teil 4: Variablenpool-Optimierung
4.1 Vermeidung der Speicherung großer Objekte
Problem: Das Speichern großer Objekte (z. B. große Dateien, langer Text) im Variablenpool verbraucht viel Arbeitsspeicher.
Optimierungsstrategie:
# ❌ Nicht empfohlen: Große Objekte speichern
variables = {
"large_file": open("large_file.pdf", "rb").read(), # 10 MB
"long_text": "..." * 100000 # 1 MB
}
# ✅ Empfohlen: Referenzen speichern
variables = {
"file_path": "/pfad/zu/large_file.pdf",
"text_summary": summarize(long_text) # Nur Zusammenfassung speichern
}
4.2 Verwendung von Referenzen anstelle von Kopien
Problem: Das Kopieren von Variablen erhöht den Speicherverbrauch und die Verarbeitungszeit.
Optimierungsstrategie:
# ❌ Nicht empfohlen: Variablen kopieren
result = process_data(data.copy())
# ✅ Empfohlen: Referenzen verwenden
result = process_data(data) # Bei schreibgeschützten Operationen Referenzen verwenden
4.3 Rechtzeitige Bereinigung von Variablen
Problem: Nicht mehr verwendete Variablen belegen Speicher.
Optimierungsstrategie:
# In Code-Knoten nicht mehr verwendete Variablen bereinigen
def main(args):
# Daten verarbeiten
large_data = process_large_data(args["input"])
result = extract_result(large_data)
# Großes Objekt bereinigen
del large_data
return {"result": result}
4.4 Variablenbereichsverwaltung
Variablentypen:
- Systemvariablen:
sys.query,sys.files,sys.conversation_id - Knotenvariablen:
{{#node_id.output#}} - Umgebungsvariablen: Konfiguration und Schlüsselverwaltung
- Iterationsvariablen: Aktuelles Element und Index in Schleifen
Optimierungsvorschläge:
- Verwenden Sie den kleinstmöglichen Bereich
- Vermeiden Sie globale Variablenverschmutzung
- Geben Sie temporäre Variablen rechtzeitig frei
Ausführliche Dokumentation: Siehe workflow-optimization/variable-pool.md
Teil 5: Parallele Verarbeitung und Streaming-Antworten
5.1 Parallele Iteratorenverarbeitung
Verwenden Sie den Parameter parallel_nums von Iteratoren, um Array-Daten parallel zu verarbeiten.
Konfigurationsbeispiel:
iteration_node:
type: iteration
inputs:
items: "{{#code_node.output.items#}}"
config:
parallel_nums: 5 # 5 Elemente parallel verarbeiten
Leistungsvergleich:
| Datenmenge | Serielle Verarbeitung | Parallele Verarbeitung (5) | Verbesserung |
|---|---|---|---|
| 10 Elemente | 20s | 5s | 4x |
| 50 Elemente | 100s | 25s | 4x |
| 100 Elemente | 200s | 50s | 4x |
5.2 Streaming-Antworten
Verwenden Sie Streaming-Antworten, um die Benutzererfahrung zu verbessern und die Time-to-First-Byte (TTFB) zu reduzieren.
Implementierung:
# API-Aufruf mit aktiviertem Streaming
response = requests.post(
"https://api.dify.ai/v1/workflows/run",
headers={"Authorization": f"Bearer {api_key}"},
json={"inputs": {...}, "response_mode": "streaming"},
stream=True
)
for line in response.iter_lines():
if line:
event = json.loads(line)
print(event["data"])
Optimierungseffekt:
- TTFB um 80 % reduziert
- Vom Benutzer wahrgenommene Antwortzeit um 50 % reduziert
5.3 Asynchrone Aufgabenverarbeitung
Verwenden Sie Celery zur asynchronen Verarbeitung langlaufender Aufgaben.
Architektur:
API-Server → Celery Queue → Worker Pool → Aufgabenausführung
Anwendungsszenarien:
- Verarbeitung großer Dateien
- Batch-Datenimport
- Langlaufende API-Aufrufe
- Geplante Aufgaben
5.4 Optimierung der ereignisgesteuerten Architektur
Dify verwendet eine ereignisgesteuerte Architektur, bei der die Knotenausführung einen Ereignisstrom erzeugt.
Optimierungsstrategie:
- Verwenden Sie eine nicht blockierende Ereignisverarbeitung
- Verarbeiten Sie Ereigniswarteschlangen in Batches
- Optimieren Sie die Ereignisverteilungslogik
Ausführliche Dokumentation: Siehe workflow-optimization/parallel-execution.md
Teil 6: Leistungsoptimierungsbeispiele
Beispiel 1: Datenbankabfrageoptimierung (N+1-Problem)
Anwendungsszenario:
- Im Workflow müssen mehrere zusammenhängende Daten abgefragt werden
- Es gibt zyklische Datenbankabfragen
- Die Ausführungszeit wächst linear mit der Datenmenge
Problemmerkmale:
- Anzahl der Abfragen = 1 + N (N = Anzahl der Datensätze)
- Datenbankverbindungen werden häufig auf- und abgebaut
- Ausführungszeit zu lang
Zustand vor der Optimierung:
# Benutzerliste abfragen
users = query("SELECT * FROM users LIMIT 100")
# Für jeden Benutzer Bestellungen abfragen (N+1-Problem)
for user in users:
orders = query(f"SELECT * FROM orders WHERE user_id = {user.id}")
user.orders = orders
- Anzahl der Abfragen: 101 (1 + 100)
- Ausführungszeit: 10,5 s
- Datenbanklast: Hoch
Optimierungslösung:
# Alle Daten auf einmal abfragen
users = query("SELECT * FROM users LIMIT 100")
user_ids = [user.id for user in users]
# Bestellungen in Batches abfragen
orders = query(f"SELECT * FROM orders WHERE user_id IN ({','.join(map(str, user_ids))})")
# Daten im Speicher verknüpfen
orders_by_user = {}
for order in orders:
if order.user_id not in orders_by_user:
orders_by_user[order.user_id] = []
orders_by_user[order.user_id].append(order)
for user in users:
user.orders = orders_by_user.get(user.id, [])
Ergebnis nach der Optimierung:
- Anzahl der Abfragen: 2 (98 % weniger)
- Ausführungszeit: 2,1 s (80 % weniger)
- Datenbanklast: Niedrig
Erwartete Vorteile:
- Kurzfristig: 80 % weniger Ausführungszeit, geringere Datenbanklast
- Langfristig: Unterstützung größerer Datenmengen, verbesserte Skalierbarkeit des Systems
- ROI: 2 Stunden Entwicklungsaufwand, monatliche Einsparung von 30 % der Serverkosten
Beispiel 2: Optimierung der Darstellung großer Knotenmengen (100+ Knoten)
Anwendungsszenario:
- Workflow enthält 100+ Knoten
- Frontend-Darstellung ruckelt
- Editor reagiert träge
Problemmerkmale:
- Seitenladezeit > 5 s
- Deutliche Verzögerung beim Ziehen von Knoten
- Hohe Speichernutzung des Browsers
Zustand vor der Optimierung:
- Anzahl der Knoten: 150
- Seitenladezeit: 8,5 s
- Speichernutzung: 500 MB
- Benutzererfahrung: Starkes Ruckeln
Optimierungslösung:
- Virtuelles Scrollen: Nur Knoten im sichtbaren Bereich rendern
- Lazy Loading von Knoten: Knotendetails bei Bedarf laden
- Canvas Optimierung: Canvas anstelle von DOM für die Darstellung verwenden
- Zustandsverwaltung optimieren: Unnötiges erneutes Rendern reduzieren
Ergebnis nach der Optimierung:
- Seitenladezeit: 2,1 s (75 % weniger)
- Speichernutzung: 150 MB (70 % weniger)
- Benutzererfahrung: Flüssig
Erwartete Vorteile:
- Kurzfristig: Deutlich verbesserte Benutzererfahrung
- Langfristig: Unterstützung komplexerer Workflow-Designs
- ROI: 1 Woche Entwicklungsaufwand, 40 % höhere Benutzerzufriedenheit
Beispiel 3: Optimierung der Löschleistung von Workflow-Logs
Anwendungsszenario:
- Regelmäßige Bereinigung alter Logs erforderlich
- Große Logdatenmengen (Millionen)
- Löschvorgänge dauern lange
Problemmerkmale:
- Löschvorgänge blockieren die Datenbank
- Beeinträchtigung des normalen Betriebs
- Unvorhersehbare Ausführungszeit
Zustand vor der Optimierung:
- Anzahl der Logs: 5 Millionen
- Löschzeit: 45 Minuten
- Datenbanksperre: Lange Tabellensperre
- Geschäftsauswirkung: Schwerwiegend
Optimierungslösung:
# Vor Optimierung: Einmaliges Löschen
DELETE FROM workflow_logs WHERE created_at < '2024-01-01';
# Nach Optimierung: Batchweises Löschen
batch_size = 10000
while True:
deleted = DELETE FROM workflow_logs
WHERE created_at < '2024-01-01'
LIMIT batch_size
if deleted < batch_size:
break
# Kurze Pause, um die Datenbanksperre freizugeben
sleep(0.1)
Ergebnis nach der Optimierung:
- Löschzeit: 50 Minuten (leicht erhöht, blockiert aber nicht den Betrieb)
- Datenbanksperre: Kurze Sperre (0,1 s)
- Geschäftsauswirkung: Keine
Erwartete Vorteile:
- Kurzfristig: Geschäftsbetrieb nicht beeinträchtigt
- Langfristig: Höhere Datenbankstabilität
- ROI: 4 Stunden Entwicklungsaufwand, Vermeidung von Betriebsunterbrechungen
Beispiel 4: Integration von TiDB verteiltem Speicher
Anwendungsszenario:
- Große Wissensdatenbank (TB-Bereich)
- Leistungsengpässe bei Single-Node PostgreSQL
- Horizontale Skalierung erforderlich
Problemmerkmale:
- Abfrageantwortzeit > 5 s
- Datenbank-CPU-Auslastung > 90 %
- Keine weitere Skalierung möglich
Zustand vor der Optimierung:
- Datenbank: PostgreSQL Single-Node
- Datenmenge: 2 TB
- Abfrageantwortzeit: 8,5 s
- Skalierbarkeit: Eingeschränkt
Optimierungslösung:
- Migration zu TiDB: Verteilte SQL-Datenbank
- Vektorindex-Optimierung: Verwendung von TiDB Vector zur Beschleunigung der Suche
- Lese-Schreib-Trennung: Leseanfragen auf mehrere Replikate verteilen
- Partitionierte Tabellen: Partitionierung nach Zeit zur Verbesserung der Abfrageeffizienz
Ergebnis nach der Optimierung:
- Abfrageantwortzeit: 1,2 s (86 % weniger)
- Datenbank-CPU: 40 % (50 % weniger)
- Skalierbarkeit: Unterstützt 10-fache Datenmenge
Erwartete Vorteile:
- Kurzfristig: Deutlich verbesserte Abfrageleistung
- Langfristig: Unterstützung schnellen Geschäftswachstums
- ROI: 2 Wochen Migrationsaufwand, Unterstützung 10-fachen Geschäftswachstums
Beispiel 5: Hochverfügbarkeitsbereitstellung mit Higress AI Gateway
Anwendungsszenario:
- Hochverfügbarkeit in der Produktion erforderlich
- Lastverteilung für mehrere LLM-Modelle
- Failover-Fähigkeit erforderlich
Problemmerkmale:
- Single Point of Failure-Risiko
- LLM-API-Aufrufe instabil
- Unfähigkeit, Traffic-Spitzen zu bewältigen
Zustand vor der Optimierung:
- Architektur: Single-Instance Dify
- Verfügbarkeit: 95 %
- Wiederherstellungszeit nach Fehler: 10 Minuten
- Traffic-Spitzen: Nicht handhabbar
Optimierungslösung:
# Higress AI Gateway Konfiguration
apiVersion: networking.higress.io/v1
kind: McpBridge
metadata:
name: dify-gateway
spec:
replicas: 3 # 3 Instanzen
loadBalancer:
algorithm: round-robin
healthCheck:
enabled: true
interval: 10s
failover:
enabled: true
maxRetries: 3
Architektur:
Benutzeranfragen → Higress Gateway → [Dify Instanz 1, Dify Instanz 2, Dify Instanz 3]
↓
Lastverteilung + Failover
Ergebnis nach der Optimierung:
- Verfügbarkeit: 99,9 %
- Wiederherstellungszeit nach Fehler: < 1 Sekunde (automatischer Wechsel)
- Traffic-Spitzen: Unterstützt 10-fachen Traffic
Erwartete Vorteile:
- Kurzfristig: Deutlich verbesserte Systemstabilität
- Langfristig: Unterstützung geschäftskritischer Anwendungen
- ROI: 3 Tage Bereitstellungsaufwand, Vermeidung von Betriebsunterbrechungen
Teil 7: Leistungstests und Überwachung
7.1 Leistungskennzahlen
Workflow-Ausführungsmetriken:
| Metrik | Zielwert | Beschreibung |
|---|---|---|
| Durchschnittliche Ausführungszeit | < 2 s | Vollständige Workflow-Ausführungszeit |
| P95-Ausführungszeit | < 5 s | Ausführungszeit für 95 % der Anfragen |
| P99-Ausführungszeit | < 10 s | Ausführungszeit für 99 % der Anfragen |
| Knotenerfolgsrate | > 99 % | Anteil erfolgreicher Knotenausführungen |
| API-Aufruferfolgsrate | > 99,5 % | Erfolgsrate externer API-Aufrufe |
| Gleichzeitige Verarbeitungskapazität | > 100 QPS | Anfragen pro Sekunde |
Ressourcennutzungsmetriken:
| Metrik | Zielwert | Beschreibung |
|---|---|---|
| CPU-Auslastung | < 70 % | Durchschnittliche CPU-Auslastung |
| Speicherauslastung | < 80 % | Durchschnittliche Speicherauslastung |
| Datenbankverbindungen | < 80 % | Verbindungspool-Auslastung |
| Redis-Speicher | < 70 % | Redis-Speicherauslastung |
Kostenmetriken:
| Metrik | Zielwert | Beschreibung |
|---|---|---|
| Token-Nutzungskosten | < Budget | LLM-API-Kosten |
| Infrastrukturkosten | < Budget | Server-, Datenbankkosten |
| Kosten/Benutzer | Kontinuierlich sinkend | Kosten pro Benutzer |
7.2 Überwachungstools
LLMOps-Überwachung:
# Dify integrierte Überwachung
from dify import Monitor
monitor = Monitor()
# Workflow-Ausführung aufzeichnen
monitor.log_workflow_execution(
workflow_id="xxx",
execution_time=2.5,
node_count=10,
token_usage=1500,
cost=0.003
)
# Statistiken abfragen
stats = monitor.get_workflow_stats(
workflow_id="xxx",
time_range="7d"
)
Ausführungsverfolgung:
- Workflow-Ausführungsverlauf
- Statistik der Knotenausführungsschritte
- LLM-Nutzungsstatistiken
- Fehlerprotokolle und Wiederholungsaufzeichnungen
Ressourcenüberwachung:
# Prometheus + Grafana
# Überwachung von CPU, Speicher, Netzwerk, Festplatte
# Beispielabfrage
rate(dify_workflow_execution_total[5m]) # Workflow-Ausführungsrate
histogram_quantile(0.95, dify_workflow_duration_seconds) # P95-Ausführungszeit
7.3 Methoden für Leistungstests
Lasttests:
# Lasttests mit Locust
from locust import HttpUser, task, between
class DifyUser(HttpUser):
wait_time = between(1, 3)
@task
def run_workflow(self):
self.client.post(
"/v1/workflows/run",
headers={"Authorization": f"Bearer {self.api_key}"},
json={"inputs": {"query": "Testfrage"}}
)
# Test ausführen
# locust -f load_test.py --users 100 --spawn-rate 10
Belastungstests:
# Mit Apache Bench
ab -n 1000 -c 50 -H "Authorization: Bearer xxx" \
-p request.json \
https://api.dify.ai/v1/workflows/run
Benchmarks:
# Leistungsbenchmarks
import time
def benchmark_workflow(workflow_id, iterations=100):
times = []
for i in range(iterations):
start = time.time()
run_workflow(workflow_id)
end = time.time()
times.append(end - start)
return {
"avg": sum(times) / len(times),
"p50": sorted(times)[len(times) // 2],
"p95": sorted(times)[int(len(times) * 0.95)],
"p99": sorted(times)[int(len(times) * 0.99)]
}
7.4 Leistungsanalysetools
Python Profiler:
import cProfile
import pstats
# Workflow profilieren
cProfile.run('run_workflow("workflow_id")', 'profile_output')
# Ergebnisse analysieren
p = pstats.Stats('profile_output')
p.sort_stats('cumulative').print_stats(20)
Ausführungs-Tracing:
# Leistungsmetriken sammeln
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("workflow-execution") as span:
span.set_attribute("workflow.id", workflow_id)
span.set_attribute("node.count", node_count)
# Workflow ausführen
result = execute_workflow(workflow_id)
span.set_attribute("execution.time", result.time)
span.set_attribute("token.usage", result.tokens)
Wichtige Überwachungsmetriken:
| Metrik | Bedeutung | Warnschwelle |
|---|---|---|
dify_workflow_duration_seconds | Workflow-Ausführungszeit | > 10 s |
dify_node_execution_total | Anzahl der Knotenausführungen | - |
dify_llm_token_usage_total | LLM-Token-Verbrauch | > Budget |
dify_queue_depth | Warteschlangentiefe | > 100 |
dify_worker_count | Anzahl der Worker | < min_workers |
Zusammenfassung
Diese SKILL bietet einen umfassenden Leitfaden zur Leistungsoptimierung von Dify-Workflows. Die Optimierung sollte bei der Graphstruktur beginnen und schrittweise auf LLM, Worker-Pool, Variablenpool und andere Bereiche ausgeweitet werden. Es wird empfohlen, zuerst die Schnelle Diagnose-Checkliste zu verwenden, um Probleme zu lokalisieren, dann gezielte Optimierungen durchzuführen und schließlich die Testergebnisse zu überwachen und zu validieren.
Nächste Schritte
- Führen Sie die Schnelle Diagnose-Checkliste durch
- Priorisieren Sie die Optimierung basierend auf der Checkliste
- Optimieren Sie gemäß der Optimierungsstrategie in den Teilen 1–5
- Validieren Sie die Ergebnisse mit Leistungstests und Überwachung
- Wiederholen Sie bei Bedarf den Optimierungsprozess