Cloudflare hat die bedarfsgesteuerte Profilierung der CPU- und Speichernutzung für Workers und Durable Objects verfügbar gemacht. Entwickler können damit Profile direkt aus der Produktionsumgebung erfassen und als interaktive Flamegraphs anzeigen. Die Funktion ermöglicht es, Funktionen zu identifizieren, die besonders viel CPU-Zeit verbrauchen oder den meisten Speicher reservieren, anstatt sich ausschließlich auf Protokolle und aggregierte Metriken zu stützen.
Das Profiling kann über die Seite „Workers Observability“ im Cloudflare-Dashboard oder über die Befehlszeilenschnittstelle gestartet werden. Entwickler legen den Profiltyp – CPU oder Speicher – und die Erfassungsdauer fest und können außerdem verschiedene Versionen eines Workers auswählen. Nach Ende der Sitzung lässt sich das interaktive Diagramm anzeigen und die Profildatei zur Analyse mit anderen Tools herunterladen.
Was zeigen Flamegraphs?
Jedes Rechteck im Diagramm stellt einen Funktionsaufruf dar, während seine Breite die damit verbundene CPU-Zeit oder Speichernutzung widerspiegelt. Funktionen können angeklickt werden, um den Fokus auf sie zu erweitern. Alternativ lässt sich die Tabellenansicht verwenden, um die Ergebnisse nach der Anzahl der Samples zu sortieren. Cloudflare empfiehlt, mehr als ein Profil zu erfassen und nach den breitesten Funktionen zu suchen. In TypeScript-Projekten sollten außerdem Source Maps aktiviert werden, damit Funktionsnamen nicht unverständlich dargestellt werden.
Für das Profiling muss eine veröffentlichte Version ausgewählt werden, die ausreichend Datenverkehr erhält. Der Dienst erstellt keine neue Isolation zu Messzwecken, da die tatsächliche Ausführung in der Produktion überwacht werden soll. Mit dem folgenden Befehl kann ein fünf Sekunden langes CPU-Profil erfasst werden:
cf workers versions profile latest --worker-id "$WORKER_ID_OR_NAME" --duration-ms 5000 --profile-type cpu > worker-cpu.pprof
Von Cloudflare vorgestellte praktische Ergebnisse
Cloudflare nutzte das Tool zur Analyse eines Workers, der eine R2-Anbindung implementiert. Das Profiling zeigte, dass die Funktion genericR2JsonReplacer den JSON-Baum während der Ausführung von JSON.stringify erneut durchlief, wodurch ein verschachtelter Wert in manchen Fällen fünfmal verarbeitet wurde. Durch die Behebung dieses Problems wurde die Funktion 2,7-mal schneller. Das Profiling deckte außerdem einen wiederholten Aufruf von metrics auf. Das Speichern und Wiederverwenden des Ergebnisses reichte aus, um den CPU-Verbrauch zu senken.
In einem anderen Fall überschritt einer der Workers das Speicherlimit von 128 Megabyte. Der P999-Verbrauch erreichte etwa 133 Megabyte, was zu „Exceeded Memory“-Fehlern führte. Das Heap-Profil zeigte, dass der für etwa 66,7 % der Allokationen verantwortliche Prometheus-Code teilweise weiterhin ausgeführt wurde, obwohl man davon ausging, dass er deaktiviert sei. Nach der vollständigen Entfernung des Codepfads sank der P999-Wert von 133 auf 118 Megabyte, während der P50-Wert von 70 auf 54 Megabyte zurückging.
Was ändert sich praktisch?
Die Funktion verschafft Entwicklungsteams direkten Einblick in die Ausführung von Workers unter realen Bedingungen, unter denen sich Datenverkehr und die Verteilung der Isolationsumgebungen von der lokalen Entwicklungsumgebung unterscheiden können. Die Plattform bewältigt die Komplexität, Workers auf mehrere Rechenzentren und Geräte zu verteilen. Bei Durable Objects kann der Entwickler das Objekt anhand seines Namens bestimmen, um ein Profil genau für die Isolation zu erhalten, in der es ausgeführt wird.
Der Ausführungsmechanismus stellt sicher, dass während der Erfassung weiterhin Anfragen empfangen werden. Eine Sperre der Isolation wird nur beim Start und beim Beenden des Profilings gehalten. Anschließend werden während der festgelegten Dauer CPU-Samples im Abstand von einer Millisekunde erfasst. Durable Objects profitieren von ihrer zustandsbehafteten Natur, um die Profiling-Anfrage an die Isolation und den Besitzer des angegebenen Objekts weiterzuleiten.
Einschränkungen und der nächste Schritt
Das Profiling startet nicht automatisch. Daher können kurze oder seltene Zeiträume, in denen der Fehler auftritt, von der Sitzung verpasst werden. Der Speicherprofiler zeigt nur die Allokationen, die innerhalb des Messfensters stattgefunden haben, und erfasst möglicherweise nicht den durch den Start verursachten Verbrauch. Cloudflare erklärt, dass an kontinuierlichem Profiling gearbeitet wird. Dieses soll Samples automatisch erfassen und ihre spätere Anzeige im Dashboard ermöglichen.