NEWS
Skriptausführung ioBroker.javascript: CPU-Grundlast 40 %
-
Hallo zusammen,
kürzlich habe ich meine iobroker-Installation von einem RPi 4 (nativ, älterer und durchwachsener Versionsstand) auf einen RPi 5 (docker, latest, zentrale Komponenten wie admin, javascript, vis1 auch alle gehoben) migriert, dazu habe ich backitup genutzt.
Soweit funktioniert auch alles. Bloß hat mein RPi 5 einen Lüfter, den mein RPi 4 nicht hatte. Und dieser Lüfter wollte mit vertretbaren Temperaturschwellwerten nie so wirklich ausgehen. Das hat mich veranlasst, mir mal die Grundlast meines Systems anzuschauen.
Dabei ist mir aufgefallen, dass mein javascript-Adapter permanent für eine exorbitant hohe Grundlast von 20-40 % CPU (ein Kern) sorgt. Ca. 4 mal so viel wie das Kernsystem (js-controller) und zehnmal mehr als jeder andere Adapter. Ich habe wirklich viele Scripts laufen, wir sprechen hier von rund 50 Skripten, insgesamt knapp 10.000 Zeilen Code und sicherlich auch so 500 parallelen subscriptions. Mit dem Code werden auch durchaus rechenintensive numerische Berechnungen durchgeführt (z. B. um den Tagesertrag der Solaranlage aus der Momentanleistungshistorie mit irregulären Zeitintervallen korrekt zu ermitteln), alle paar Minuten gibt es solche komplexe Berechnungen.
Also dachte ich: Ok, ich habe es wohl übertrieben. Aber die Ergebnisse meiner Tests, um diese Hypothese zu belegen, kann ich mir nicht erklären:
Wenn ich alle (!) laufenden Skripte stoppe, bleibt die CPU-Last auf dem gleichen Niveau. Keinerlei Änderung. Auch ein Neustart des javascript-Adapters mit gestoppten Skripten führt direkt wieder in diese Auslastung. Neuinstallieren (= entfernen und frisch installieren) kann ich nicht machen, weil historisch bedingt ca. 500 zwingend benötigte Datenpunkte unter javascript.0.* liegen.
Ich weiß mir keinen Rat mehr. Ist das normal, hat der javascript-Adapter tatsächlich so eine hohe Idle-Last? Oder ist bei mir ggf. irgend etwas zerschossen?
Viele Grüße
ceram
-
@ceram wenn ich das jetzt richtig verstanden habe, hast du jetzt allerdings eine weitere Schicht dazwischen, die es zuvor nicht gab - Docker. Hast du da die Compose oder den Stack korrekt eingestellt und auf dein System ggfs. (CPU, RAM) angepasst?
Ro75.
-
@ro75 hm, bei docker stellt man eigentlich weder cpu noch ram ein.
das wird alles dynamisch zugeteilt.
alle prozesse in einem container laufen ja nativ auf dem prozessor, genau so wie wenn sie ohne container ausgeführt werden. -
also habe ich das richtig verstanden?
der javascript adapter zieht ohne skripte genausoviel cpu wie mit skripte?
dann liegt es ja erst mal nicht an den skripten.
da würde mir nur eines einfallen, das du wirklich viele änderungen an datenpunkten hast.
standardmäßig abonniert der javascript adapter alle datenpunkte. d.h. bei jeder änderung irgendeines datenpunkts (unabhängig ob in einem skript behandelt oder nicht) hat der adapter etwas zu tun (schreibt die daten in einen puffer).evtl kannst du in der javascript konfiguration diese option mal aktivieren.
mal schauen ob dann die prozessorlast runtergeht. dann erhält der javascript adapter nur eine meldung, wenn dieser datenpunkt explizit abonniert wurde (was ja durch den on-befehl passiert).eine weitere idee wäre noch:
der adapter läuft nur in einem prozess und kann zum gleichen zeitpunkt immer genau nur eine einzige anweisung ausführen. ein prozess läuft immer genau auf einer cpu. also die last eines prozesses kann nicht auf mehrere cpus verteilt werden.
wenn da jetzt zum gleichen zeitpunkt sehr viel passiert (50 skripte), warten die anweisungen dann entsprechend bis sie dran sind. das wird über den heap verwaltet.
das kann dazu führen das eine cpu höher belastet ist während die anderen sich langweilen (ich glaube ein raspi hat 4 cpus)
ggfs. kannst du die last bei aktivierten skripten etwas verbessern in dem du die skripte auf 2 javascript adapter aufteilst. zumindest die skripte die besonders ressourcenintensiv sind. dadurch kann sich die last etwas verteilen. aber wie gesagt nur wenn die last mit skripte ebenfalls höher ist wie ohne. -
@ceram sagte: Auch ein Neustart des javascript-Adapters mit gestoppten Skripten führt direkt wieder in diese Auslastung.
Auch ein Neustart von ioBroker mit gestoppten Skripten?
-
@oliverio sagte in Skriptausführung ioBroker.javascript: CPU-Grundlast 40 %:
hm, bei docker stellt man eigentlich weder cpu noch ram ein.
Also man kann schon Einfluss nehmen.
deploy: resources: limits: cpus: '2.00' memory: 1G reservations: cpus: '0.25' memory: 100M
So zum Beispiel. Aber eine Konfiguration haben wir noch nicht gesehen.
Ro75.
-
Hallo zusammen,
erst einmal vielen Dank für eure super schnelle Hilfe und all die Tipps. Ich will euch jetzt nicht mit docker composes und anderen Dingen langweilen, an denen es nicht lag. Deshalb komme ich schnell zur Sache.
Mir war nicht bewusst, dass der Adapter alle States subscribed, das sind bei mir schon eine Menge. Ausschalten der Option war aber leider auch keine Option, dann scheitert jedes getState() sofort mit Verweis darauf, dass es ohne die Option nicht synchron verwandt werden kann.
Deshalb dachte ich mir, ich deaktiviere einfach mal diejenigen Adapter, die viele Zustände in kurzen Abständen aktualisieren - und einen dev-Adapter, der einen wirklich sehr experimentellen Eindruck machte. Und siehe da: Die Auslastung ging sofort merklich runter, in den Bereich von 1-2%.
Auf der Suche nach dem konkreten Schuldigen dachte ich erst an unifi, weil der schon detaillierte Stats zu rund 200 Netzwerkgeräten bereithält und die laufend aktualisiert - er hat mit Abstand die meisten Datenpunkte. Aber nein, es war der unscheinbare Adapter "roborock" im dev-Branch, den ich nach dem Upgrade auf den RPi 5 (auf dem RPi 4 war RaspiOS zu alt für die benötigte node-Version) endlich mal ausprobieren wollte, der aber nur im dev-Branch überhaupt startete. Ich lasse ihn jetzt deaktiviert, schade um die frisch programmierte Erweiterung für meine Alarmanlage, mit der ich Bewegungen auf Etagen ignorieren konnte, auf denen gerade ein Roboter fuhr
Ich bin jetzt jedenfalls froh, dass mein System wieder rund läuft. Und der Lüfter ist auch ausgegangen
Vielen Dank!
ceram
-
Das sind Limitierungen und keine Zuordnungen.
Damit verhindert man das ein Container sich Zuviel holt. -
Die Sync getState kannst du einfach umstellen durch
await getStateAsync
Das hat den selben Effekt.
Ein echtes Sync gibtves bei JavaScript eh nie.