Skip to Content
Low-CodeTips and TricksPerformance-Optimierung

Performance-Optimierung

Diese Seite beschreibt Strategien, um die Performance von LowCode-Flows zu verbessern. Von der Identifikation von Engpaessen bis hin zu konkreten Optimierungstechniken.

Engpaesse identifizieren

Zeitstempel-Methode

Fuegen Sie an kritischen Stellen Zeitstempel hinzu, um langsame Abschnitte zu finden:

// Function Node: Zeitmessung starten msg._startTime = Date.now(); return msg;
// Function Node: Zeitmessung auswerten const elapsed = Date.now() - msg._startTime; if (elapsed > 1000) { node.warn(`Langsame Ausfuehrung: ${elapsed}ms`); } msg._executionTime = elapsed; return msg;

Node-RED Status nutzen

Zeigen Sie die Ausfuehrungszeit direkt im Editor an:

// Function Node: Status mit Ausfuehrungszeit setzen const start = Date.now(); // ... Verarbeitung ... msg.payload = await processData(msg.payload); const elapsed = Date.now() - start; node.status({ fill: elapsed > 500 ? "red" : "green", shape: "dot", text: `${elapsed}ms - ${new Date().toLocaleTimeString()}` }); return msg;

Async vs. Sync in Function Nodes

Synchron (blockierend)

Synchroner Code blockiert den gesamten Node-RED-Prozess:

// SCHLECHT: Blockiert den Event-Loop const data = heavyComputation(msg.payload); // 2 Sekunden blockiert msg.payload = data; return msg;

Asynchron (nicht-blockierend)

Asynchroner Code laesst andere Messages parallel verarbeiten:

// GUT: Non-blocking mit async/await const response = await fetch("https://api.example.com/data"); msg.payload = await response.json(); return msg;

Schwere Berechnungen aufteilen

Wenn rechenintensive Operationen unvermeidbar sind, teilen Sie diese auf:

// Function Node: Daten in Chunks verarbeiten const items = msg.payload; const chunkSize = 100; const results = []; for (let i = 0; i < items.length; i += chunkSize) { const chunk = items.slice(i, i + chunkSize); const processed = chunk.map(item => transformItem(item)); results.push(...processed); // Event-Loop zwischen Chunks freigeben if (i + chunkSize < items.length) { await new Promise(resolve => setImmediate(resolve)); } } msg.payload = results; return msg;

Caching-Strategien mit Context

Einfacher Cache im Flow-Context

// Function Node: Daten aus Cache oder API laden const cacheKey = "userList"; const cacheTTL = 60000; // 60 Sekunden const cached = flow.get(cacheKey); if (cached && (Date.now() - cached.timestamp) < cacheTTL) { // Aus dem Cache laden msg.payload = cached.data; msg._fromCache = true; return msg; } // Frisch laden const response = await fetch(env.get("API_URL") + "/users"); const data = await response.json(); // Im Cache speichern flow.set(cacheKey, { data: data, timestamp: Date.now() }); msg.payload = data; msg._fromCache = false; return msg;

Cache invalidieren

// Function Node: Cache bei Aenderungen leeren flow.set("userList", null); node.warn("Cache invalidiert: userList"); return msg;

Globaler Cache fuer tabuebergreifende Daten

// Function Node: Konfiguration im globalen Cache halten const config = global.get("appConfig"); if (!config) { // Beim ersten Aufruf laden und global cachen const response = await fetch(env.get("CONFIG_URL")); const data = await response.json(); global.set("appConfig", data); msg.payload = data; } else { msg.payload = config; } return msg;

Rate Limiting mit Delay Node

Delay Node konfigurieren

Der Delay Node kann die Nachrichtenrate begrenzen:

EinstellungWertBeschreibung
ActionRate LimitNachrichten drosseln
Rate10 msg/sMaximal 10 Nachrichten pro Sekunde
Drop intermediateJaUeberschuessige Nachrichten verwerfen

Manuelles Rate Limiting

// Function Node: Rate Limiting mit Zeitstempel const rateLimitMs = 1000; // Mindestens 1 Sekunde zwischen Aufrufen const lastCall = flow.get("lastApiCall") || 0; const now = Date.now(); if (now - lastCall < rateLimitMs) { node.warn("Rate Limit erreicht, Nachricht verworfen"); return null; // Nachricht nicht weitergeben } flow.set("lastApiCall", now); return msg;

Message Queuing

Einfache Warteschlange mit Context

// Function Node: Nachricht in Warteschlange einreihen let queue = flow.get("messageQueue") || []; queue.push({ payload: msg.payload, timestamp: Date.now() }); flow.set("messageQueue", queue); node.status({ fill: "blue", shape: "ring", text: `${queue.length} in Warteschlange` }); return null; // Nachricht nicht sofort weiterleiten
// Function Node: Warteschlange abarbeiten (mit Inject Node im Intervall) let queue = flow.get("messageQueue") || []; if (queue.length === 0) { return null; } const item = queue.shift(); flow.set("messageQueue", queue); msg.payload = item.payload; node.status({ fill: "green", shape: "dot", text: `${queue.length} verbleibend` }); return msg;

Allgemeine Optimierungstipps

TippBeschreibung
JSON.parse vermeidenNutzen Sie msg.payload direkt, wenn es bereits ein Objekt ist
Payload-Groesse reduzierenEntfernen Sie unbenoetigte Properties mit delete msg.largeData
Debug Nodes deaktivierenDeaktivierte Debug Nodes haben keinen Overhead
Subflows sparsam nutzenJeder Subflow-Aufruf erzeugt einen kleinen Overhead
HTTP Keep-Alive nutzenVerwenden Sie persistente Verbindungen bei haeufigen API-Aufrufen
Context-Store waehlenNutzen Sie memory fuer temporaere und file nur fuer persistente Daten

Speicherverbrauch reduzieren

// Function Node: Grosse Payloads frueh reduzieren // Nur benoetigte Felder behalten msg.payload = msg.payload.map(item => ({ id: item.id, name: item.name, status: item.status // Alle anderen Felder werden nicht weitergeleitet })); return msg;

Weiterführende Informationen