Beobachtung mittels MQTT

Bei der Beobachtung der Systemeigenschaften wie Last und Speicherverbrauch hatte ich mehrfach festgestellt, dass die Beobachtung das Experiment verändert hat. Beispielsweise war die durchschnittliche Systemlast der letzten Minute immer stark geprägt vom SSH-Login und dem Aufruf von uptime. Das hatte ich anfangs noch hingenommen, aber spätestens bei der Beobachtung der Wachzustände war das Mist. Als Lösungsmöglichkeit habe ich mich mit MQTT beschäftigt und inzwischen ein paar Skripte laufen, die regelmäßig Informationen zu den Betriebsparametern liefern.

Bei MQTT wird ein Server (Broker) bereitgestellt, bei dem sich verschiedene Clients anmelden können. Jeder Client kann sowohl Senden als auch Empfangen, aber üblicherweise sind das applikativ getrennte Rollen. Der Sender kippt Informationen ein (publish), die in Topics strukturiert sind (z.B. system/cpu/temperature). Der oder die Empfänger abonnieren (subscriben) die Topics, für die sie sich interessieren, und erhalten die Informationen als Benachrichtigung. Weiterhin können Informationen so gesendet werden, dass der Broker ihren letzter Wert speichert und direkt zustellt, wenn sich ein Client neu darauf abonniert (retain).

Als Broker setze ich Eclipse Mosquitto ein, als Docker-Container mit Volumes auf der SD-Karte (damit ich ihn während der Backups nicht beenden muss). Mosquitto ist erfreulich sparsam in Bezug auf Arbeitsspeicher, der ganze Container dümpelt die meiste Zeit bei circa 2 Megabyte herum. Da ich keine Benutzerkonten benötige komme ich fast mit der Standard-Konfiguration aus, es muss lediglich der anonyme Zugriff von anderen Hosts aus erlaubt werden (allow_anonymous true). Die Topics werden bei MQTT nicht eingerichtet oder vorgegeben, sondern entstehen automatisch durch das Senden darauf.

Auf der Client-Seite habe ich mit mqtt-simple experimentiert, bin aber relativ schnell auf eigene Python-Skripte unter Verwendung von paho-mqtt umgestiegen. Für die Darstellung hatte ich etwas mit Node-RED rumgespielt, habe mir dann aber meine eigenen Dashboards ebenfalls als Konsolen-Anwendungen mit Python und prettytable zusammengebaut. Da waren auch so Features wie "maximaler Arbeitsspeicherverbrauch seit Beobachtung" leicht umsetzbar, was ich zur Bestimmung der Ressourcen-Limits genutzt habe. Auch die Beobachtung der Festplatten-Wachzustände erfolgt via MQTT, wobei ich hier auf der Beobachterseite einfach einen Aufruf von mqtt-simple in eine Textdatei schreiben lasse (auf dem Pi selbst, damit es rund um die Uhr laufen kann).

syswatch.py svcwatch.py
HDD state:              idle (since 3 hours ago)
Load average:           0.22, 0.32, 0.27
Memory usage:           46.7% (536.3 MB available)
System uptime:          1 day, 14 hours and 52 minutes
Temperature:            47.2  °C
Volume usage backup:    2.7% (1.8 TB available)
Volume usage live:      5.3% (902.3 GB available)
     
+-------------+--------+----------------+---------------+
| service     |  limit | currently used |  highest seen |
+-------------+--------+----------------+---------------+
| filebrowser | 262144 |   8888 ( 3.4%) | 11172 ( 4.3%) |
| gogs        | 262144 |  46308 (17.7%) | 46524 (17.7%) |
| linkding    | 262144 |  64080 (24.4%) | 64084 (24.4%) |
| mosquitto   |   8192 |   1552 (18.9%) |  1556 (19.0%) |
| mytinytodo  |  65536 |  13760 (21.0%) | 13776 (21.0%) |
| vaultwarden |  98304 |  16524 (16.8%) | 16608 (16.9%) |
+-------------+--------+----------------+---------------+

Etwas kniffliger war die eigentliche Datenerhebung. Im ersten Anlauf hatte ich viel aus /proc gelesen oder externe Programme gestartet und deren Ausgabe geparst (z.B. df -k oder docker stats --no-stream). Nach und nach habe ich diese Aufrufe durch Funktionen aus verschiedenen Python-Bibliotheken ersetzen können (shutil, psutil und docker). Das Skripte-Ökosystem besteht jetzt aus drei Datenquellen (hddmon.py, svcmon.py und sysmon.py) sowie zwei Dashboards (svcwatch.py und syswatch.py). Die leichte Asymmetrie ergibt sich daraus, dass die Erhebung der HDD-Aktivität vergleichsweise komplex ist, die Darstellung des Zustands aber hübsch in syswatch.py aufgegangen ist. Das Schöne an MQTT und den Topics ist, dass Informationen zwar dezentral eingekippt werden können, am Ende aber trotzdem wie aus einer Quelle aussehen. (MQTT kennt kein Konzept von Eigentümern oder Schreibberechtigten; man tut sich aber selbst einen Gefallen, wenn man die hierarchische Struktur nutzt, und die Blattknoten konzeptionell somit doch einen definierten Eigentümer haben, der als einziger darauf schreibt, um Kollisionen zu vermeiden.)

Update: inzwischen habe ich die Langzeiterfassung der Festplattenaktivität auch mit einem Python-Skript umgesetzt (hddlog.py), um die Abhängigkeit zu mqtt-simple zu verlieren (vorher war hier die Installation eines Perl-Packages via CPAN notwendig).

Update: ich habe die vielen Einzelskripte (svcmon.py, svcwatch.py, sysmon.py, syswatch.py und das Hilfsskript mqtthelper.py) durch zwei komplexere, aber besser strukturierte Skripts ersetzt: observer.py und dashboard.py. Außerdem habe ich die viele einzelnen Datenpunkte durch zwei Telegramme ersetzt, die jeweils ein JSON-Objekt beinhalten. Das macht einerseits die Auswertung einfacher, andererseits ist die Datenkonsistenz sichergestellt (vorher war es Glückssache, ob alle Datenpunkte schon einmal empfangen wurden und ob der Inhalt zueinander passt). Außerdem habe ich den MQTT-Broker selbst komplett aus filebox4 herausgetrennt und als eigenen Dienst laufen; das war notwendig geworden, weil ich den Broker auch für andere Projekte nutze und mir die Querabhängigkeit ein Dorn im Auge war...

dashboard.py
+-------------------+-----------+-------------------+-------------------+
| Service           |     Limit |    Currently used |      Highest seen |
+-------------------+-----------+-------------------+-------------------+
| filebrowser-app-1 | 256.0 MiB |  10.9 MiB ( 4.3%) |  12.6 MiB ( 4.9%) |
| gogs-app-1        | 256.0 MiB | 109.1 MiB (42.6%) | 240.0 MiB (93.8%) |
| linkding-app-1    | 256.0 MiB | 125.1 MiB (48.9%) | 127.4 MiB (49.8%) |
| mqtt-broker-app-1 |   8.0 MiB |   1.9 MiB (23.4%) |   1.9 MiB (23.5%) |
| mytinytodo-app-1  |  64.0 MiB |  10.2 MiB (15.9%) |  10.2 MiB (15.9%) |
| vaultwarden-app-1 |  96.0 MiB |  35.9 MiB (37.3%) |  39.0 MiB (40.6%) |
+-------------------+-----------+-------------------+-------------------+

+-----------------------+-------------------------------------------+
| Property              | Value                                     |
+-----------------------+-------------------------------------------+
| Load average          | 0.25, 0.22, 0.19                          |
| Memory usage          | 63.0% (372.7 MB available)                |
| System uptime         | 2 months, 14 days, 23 hours and 6 minutes |
| Temperature           | 46.2 °C                                   |
| Volume "backup" usage | 108.1 GB of 2.0 TB used (5.5%)            |
| Volume "live" usage   | 103.3 GB of 1.0 TB used (10.3%)           |
+-----------------------+-------------------------------------------+

Als weitere Verbesserung wird der "Highest seen"-Wert jetzt serverseitig ermittelt und kann somit auch über einen längeren Zeitraum betrachtet werden, als nur während einer Beobachtungssitzung. Allerdings ist die Abtastrate mit (Voreinstellung) 1/Minute etwas gering für eine echte Performance-Messung.


Zurück zur Hauptseite