Ich hatten an verschiedenen Stellen in letzter Zeit Diskussionen über Systemd. Einige meiner Gedanken will ich hier ablegen, auch wenn sie damit recht herausgerissen wirken, weil ich sie aus Gesprächverläufen kopiert habe.

Partition von verschlüsseltem USB-Stick einbinden

Die Denkweise bei Systemd sind Ereignisse und nicht Aktionen. Du hast die Struktur: usb -> crypto -> partition. Wenn Du auf die Partition zugreifen willst, sagst Du deshalb start parition. Wenn Du aber den USB-Stick abziehen willst, sagst Du stop usb.

Das macht Systemd für Dich. Du sagst nur »stoppe alles vom USB-Stick« (Event). Systemd übersetzt das dann in die Aktionen »umount Partition«, »cryptsetup close« usw. – event-basiert ggü. aktions-basiert.

Das ist das riesige Problem, dass alle Sysv-Nutzer immer jammern, dass sie keine Shell-Skripte mehr haben. Das ist der gedankliche Wechsel von Anweisungen hin zu Zustandsbeschreibungen. Wenn Du beides als gleich ansiehst, dann hast Du es nicht verstanden.

Man kann auf beiden Wegen die selben Ziele erreichen, aber die Wege sind völlig verschieden. Das ist so wie Haskel, C und C++ völlig unterschiedliche Ansätze sind, aber das Programm läuft auf dem selben Prozessor und liefert das selbe Ergebnis.

Die Unit ist kein aktives Programm. Der aktive in diesem System ist Systemd. Eine Unit ist im Grunde nichts anderes als ein Zettel, auf dem steht, wie so eine Unit aussieht, also im Grunde wie ein Puzzleteil mit Nasen und Ausbuchtungen. Systemd als Puzzler setzt sich hin und sucht zum gewünschten Ziel die notwendigen Steine zusammen und setzt sie aneinander. Nicht die Unit handelt, sondern Systemd. Bei Sysv-Init haben die Skripte gehandelt.

Mit systemctl start X sagst Du bildlich zu Systemd: Baue mir einen Weg zum Puzzleteil X. Mit systemctl stop X sagst Du wiederum: reduziere das Bild bis zum Puzzleteil X. Wenn Systemd fertig ist, ist das Gesamtbild (das System) in dem Zustand, wie Du es haben wolltest. Ob es dafür 5 Teile zwischendurch hinzugefügt und wieder weggenommen hat, ist unbestimmt. Es zählen nur die Zustände am Anfang und am Ende. Den Plan, um diese zu erreichen, bastelt Systemd und setzt ihn um.

Die Unit sagt Systemd nicht, wie zu puzzln ist, sondern beschreibt mit After und Before einfach die Nasen und Ausbuchtungen, also die Form.

Wenn auf Deinem USB-Stick noch eine zweite Partition wäre und diese auch eingehängt seien könnte, würde der Plan zum Entfernen wesentlich komplexer. So sagst Du aber einfach nur stop usb und wie das zu Stande kommt, darf Systemd rausfinden.

Diskussion über das Konzept von Systemd

Matrix-Raum

Ich finde wiederum Systemd vom Design her echt genial. Ich habe vorher schon immer mit runit rumgebastelt, um Prozesse ordentlich zu überwachen und war neidisch auf die Windows-Leute, die einfach den Restart in den Eigenschaften zusammenklicken konnten und noch dazu sagen konnten, aber beim dritten Mal, lass es. Bei SysV-Init sind die Prozesse einfach abgeraucht und Pech gehabt. Postfix und andere Dienste haben dann ihren eigenen Master erfunden, der die Funktionalität implementiert.

Ebenso habe ich mit systemd-coredump das Programm gefunden, was ich selbst schon seit Jahren gebastelt hatte. Wenn heute irgendein Prozess abraucht, kann man sich ruckzuck die Analyse dazu besorgen und fast vollautomatisiert einen Bugreport erzeugen.

Ich sehe z. B. auch bei Systemd auf technischer Ebene die Umsetzung mit dem Logging über Stdout/-err als Schritt nach vorn an. Wenn ich bei LWN immer die Diskussionen über Systemcalls lese und wie teuer die viele Entwickler ansehen, da ist das printf eine echte Verschlankung gegenüber openlog/syslog/closelog.

Und dbus will man haben. Die Welt hat sich einfach weiter entwickelt und wir stehen nicht mehr auf dem Level, dass mit mit einfach Signalnummern einem Prozess klarmachen können, was wir wollen. Die Kommunikation muss ausführlicher und vielfältiger sein, wenn SIGHUP ≠ Reload Config seien soll.

Systemd will oder soll eben auch mehr abdecken als die Dienste eines Servers starten. Im besten Fall soll es auf Embedded-Geräten (Handys) laufen und dort auf die dynamische Umgebung reagieren. Das ist eben dann ein einfaches System mehr, wie es früher für ein SysV gereicht hat.

Na XML war schon zu seiner Hochzeit verschrien und es geht ja weiter. JSON finde ich auch nicht perfekt, aber wesentlich nutzbarer als XML. So läuft eben die Entwicklung. Damals dachten die Entwickler eben, dass Robustheit toll ist und waren von HTML geprägt. Dass das aber beim Parsen zu Konflikten führt und am Ende sinnlos ist, hat man eben erst gelernt.

https://www.agwa.name/blog/post/how_to_crash_systemd_in_one_tweet

Oh sorry. Das ist ein Rumgeheule. Der hätte mal Linux vor 15 Jahren benutzen müssen. Da ist Dir der Kernel öfter hochgegangen und hat mal Ooops gerufen. Also zu glauben, dass Software fehlerfrei entwickelt wird, ohne dass sie vorher im Einsatz ist, der ruft nach einem »Wasch mich, aber mach mich nicht nass«. Auch die Diskussion um C finde ich immer komisch. Was wäre denn die Alternative? Wir hatten 2015 keine brauchbare Sprache für Systementwicklung. Und C++ hat so seine Schwierigkeiten mit dem Linken und Bibliotheken. Wenn man aber Exception und allen OO-Kram (vtables) weglässt, damit man für andere Sprachen kompatibel ist, dann ist man wieder bei C.

Auch X ist heute wesentlich benutzbarer als vor 20 Jahren. Was haben wir damals noch mit Modlines und so rumgebastelt. Aber diese ganze Automatik und Verbesserung ist eben erst mit der Zeit gekommen.

Was ich allerdings bei Systemd auch etwas schade finde, dass es keine Alternativen gibt. Aber bei SysV-Init gab es die auch nicht. Bei Init kann es wahrscheinlich nur einen geben. Aber mit den Units ist schon mal eine Abstraktion geschaffen worden, die besser ist, andere Systeme zu entwickeln. Mit runit und den SysV-Init-Skripten hatte ich nicht Probleme. Effektiv habe ich für runit die Skripte neu geschrieben.

Im Nachhinein hätten immer viele Dinge schöner seien können. Das ist eben Evolution und das die mit Entwicklung verläuft sehen wir ja auch bei uns Menschen. Wie cool wäre es gewesen, wenn die Deppen vor 200 Jahren kapiert hätten, dass Kohle und Erdöl besser in der Erde bleiben sollten, weil sie die Natur vor Millionen Jahren aus gutem Grund dorthin gepackt hat. Fehler müssen gemacht werden.

https://blog.darknedgy.net/technology/2015/10/11/0/

Ich habe mich jetzt mal durch (fast) den gesamten Text gequält und habe keine ernsthaften Kritikpunkte gefunden. Der Einwand, dass es bei Abhängigkeiten zu Schleifen kommen kann, ist auf einer akademischen Ebene toll, aber so ist das Leben – diese Probleme hatte zuvor auch insserv.

Auch hat der Typ ein echtes Problem nach vorn zu denken. Sein Verständnis von readiness notification, file units und Abhängigkeiten ist das der alten Welt – da gab es das nicht. Dass es beim Übergang zu einer neuen Welt holprig zugeht und Anpassungen notwendig sind, liegt in der Natur der Sache, ebenso dass zu Beginn noch nicht alles fertig ist. Über neue Ideen und Konzepte zu jammern, weil sie neu sind, sehe ich als nicht angebracht an.

Also welches sind effektiv die Kritikpunkte und wie hätte man sie besser lösen können als mit »Wir lassen alles wie es ist«? Dabei aber nicht singuläre Teilprobleme herauspicken und die »besser« lösen, indem man die restlichen Anforderungen vergisst.

Ich bin heute auch das erste Mal wirklich mit Wayland in Berührung gekommen und Himmel. Wenn das Verbreitung findet, wird es auch tierischen Ärger geben. Mit Http3/Quic rechne ich auch mit heftigem Ärger.

Ich kann bestätigen, dass es mit Systemd Probleme gibt. Aber die liegen für mich eher in der Implementation und dem Wechsel der Welten und nicht im Konzept.

Die Zyklen baut doch Systemd nicht in den Graphen hinein, sondern die werden von der Umwelt an es herangetragen. Diese Zyklen gab es auch schon früher (z. B. ist mir das Problem bei NFS als Rootfs das erste Mal bewusst geworden), nur musste da der Admin diese auflösen. Das ist einfach eine Welt-Theorie-Diskrepanz. Entweder macht man das System so strikt, dass es gewisse Vorkommnisse nicht abbilden kann, oder man versucht irgendwie mit der Komplexität der Welt zurecht zu kommen. Ja, man hätte sich auch für den strikten Ansatz entscheiden können, aber das ist eben etwas praxisfremd.

Mir sind diese Kritikpunkte nicht so erkenntlich. Deshalb frage ich ja, welche das sind. Ich sehe zwischen alter Welt und neuer Welt einfach einen fundamentalen Bruch an mehreren Stellen: beim alte Initsystem war das Ziel, eine Aktion auszuführen. Daher wurden die Skripte geordnet und der Reihe nach ausgeführt. Wie ein bestimmtes Ziel erreicht wird, war vor (a priori) dem Booten bekannt.

Aber es hat sich über die Jahre hin das System immer vielfältiger entwickelt – früher war auch der Kernel ganz stringent und hat die Treiber nach und nach initialisiert. Aber dort gab es über die Zeit hin einen Wandel dazu, dass man auf Ereignisse reagiert hat, weil man nicht mehr garantieren konnte, dass zu einem festen Zeitpunkt (x Sekunden nach dem Einschalten) ein bestimmter Zustand (Festplatte verfügbar, WLAN-Chip ist bereit) herrscht. Früher war im Kernel alles mit vielen Warten verbunden, um in einen festgelegten Zustand zu kommen. Schon mit USB fing es an und wurde einfach immer unvorhersagbarer und die Wartezeiten waren sinnlos verschwendete Zeit. Deshalb wurde der Kernel hin zu asynchron entwickelt: /sbin/hotplug, udev usw. Und bei asynchron spricht man nicht mehr über Abläufe (wie sie bei synchron möglich sind), sondern muss über Zustände nachdenken.

Und das hat man an allen Ecken und Enden gemerkt, dass der alte Weg von festen Abfolgen nicht mehr zur neuen (asynchronen) Denkweise von Ereignissen und Zuständen passte – eine Diskrepanz zwischen Kernel und Userspace. Da aber heute auch nicht mehr klar ist, wie das Universum aussieht, wenn es ausgeführt wird, kann man die Zustandsübergänge nicht mehr vorberechnen, sondern muss es dann tun, wenn das Ereignis eintritt. Deshalb passiert eben auch das Parsen und Berechnen der Abhängigkeiten zur Laufzeit. Ob man für das Parsen nun noch eine Zwischenrepräsentation wählt, ist meiner Meinung nach irrelevant, weil mit einem solchen Pre-Compiled-Format der Parser auch patzen kann – diesen Einwand aus der qmail-Ecke fand ich nicht zutreffend.

Wenn man sich die Probleme der realen Welt einfach ansieht und nach einer Lösung sucht, mir würde auch nichts anderes als das Konzept von Systemd einfallen, eben weil es auch typisch für asynchrones Denken ist. Die haben da nicht viel neues erfunden, nur eben das Konzept (Ereignisse+Zustände) auf diese Situation angepasst.

Ebenso sehe ich keine andere Lösung, wenn man über die Frage »Signale + Überwachung + Logging« nachdenkt. Da kommt man zwangsweise auf einen solchen Klumpen wie dbus + systemd + journald. Nur wenn man eine andere Frage stellt, kommt man zu anderen Lösungen. Allerdings habe ich da Bedenken, dass diese Frage näher an der Realität ist.

Wayland habe ich noch nicht so genau untersucht, aber von dem was ich über die Jahre mitbekommen habe, stellen die dort auch einfach eine ganz andere Frage als sie die Entwickler von X vor sich hatten. Deshalb wird das System auch anders.

Bei quic glaube ich schon, dass es noch richtig Spaß geben wird, weil das den ISO/OSI-Stack umdefiniert. Das wird viel Spaß geben, bis sich alle daran gewöhnt haben, wenn Verschlüsselung dann plötzlich ein Muss ist.

Über »magic numbers« würde ich nicht diskutieren. Das sehe ich einfach aus meiner praktischen Erfahrung, dass man irgendwo immer Dinge festlegen muss, eben z. B. Puffergrößen, und dass man die nicht als konfigurierbar auslegt ist auch verständlich. Vor zwei oder drei Wochen war bei LWN eine Diskussion über die Puffergröße der negativen Cache-Einträge für Dateisuchen zu lesen, holla, also diese Diskussion hat dann so Stück für Stück die Komplexität dieses Puffers für NFS und sonstige Szenarien hervorgebracht. Sich also hinstellen und sagen »na hätten sie den Puffer doch mal größer gemacht«, zeugt nicht so wirklich von Verständnis für die Sache.

Irgendwo muss man Grenzen ziehen. Das ist die selbe Diskussion wie mit Stichtagen für irgendwelche Rentenalter oder Ladengrößen für Genehmigungen. Das hat Komplexitätsreduktion so an sich: Es bildet die Realität nicht zu 100 % ab und es gibt eben Stellen, da ist es unfair und ungenau.

Wie ich an dem Beispiel mit den Events im Kernel für USB und andere Geräte schon erläutert hatte, sehe ich es nicht so, dass man sich die Komplexität reinholt, sondern die drückt einem die Welt einfach rein. Die Computer sind nicht mehr so wohlstrukturiert wie vor 30 Jahren und die Aufgaben, die heute damit bewältigt werden, sind viel umfangreicher. Früher war doch Roaming und eine Connection-Übergabe von einer IP-Adresse zur anderen überhaupt kein Thema. Heute nimmt der Nutzer sein Handy, hat einen langlaufenden Prozess für einen Webstream drauf und geht von seiner Wohnung (WLAN) über die Straße (4G) ins Café (WLAN). Das ist wesentlich komplexer als die Anforderungen vor 20 Jahren. Oder im Hardwarebereich: NUMA, unterschiedliche Prozessorarchitekturen auf dem selben Chip (Cell-Prozessor), temperatur- und stromsensitives Prozess-Scheduling. Da sind dann Fragen zur Ergonomie nicht die großen Konzeptfragen. Klar, benutzbar muss es sein, aber dafür sollte man sich lieber um Alternativimplementationen bemühen.

Schlimm ist, dass wir gerade nur einen Systemd und ein Journald haben. Aber das liegt (hoffentlich nur) daran, dass wir gerade in der Sturm-und-Drang-Phase sind und erst, wenn es sich gesetzt hat, bleibt die Chance für Alternativen – ähnlich wie auch mit Synapse bei Matrix. Daher, so ist das Leben.

systemd, 10 years later: a historical and technical retrospective

Ich habe jetzt diesen Blogeintrag zu einem guten Stück gelesen (aber auch etliche Teile überflogen). Was mir auch da wieder bewusst wird: Es geht um Befindlichkeiten und verletzte Gefühle. Weite Strecken des Textes lesen sich wie eine Beweisführung, dass die Systemd-Entwickler hinterhältige Schurken sind und die Welt betrogen haben.

Dieses »der hat damals das gesagt« und »dann wurde das nur angedeutet, aber nicht gesagt und heute haben wir es. Das wussten die schon damals und wollten es uns nur nicht sagen.« Ich habe mich wie im Sandkasten beim Lesen gefühlt.

Im Abschnitt 1.2. erläutert er sehr schön die Situation vor Systemd:

  • devfs, hal, udev und die nicht-deterministische Systemkonfiguration beim Booten, aber auch zur Laufzeit
  • die Konfiguration von SysV-Init mit Symlinks, die einfach nicht mehr das erfüllt haben, das bedurft wurde (deaktivieren, einheitliche Steuerung (service/start-stop-daemon), bedingtes Starten (policy-rc.d für build-chroot), definierte Umgebung (Initskripte haben nicht das Environment aufgeräumt, deshalb hat Samba nach service restart plötzlich in Deutsch geloggt, was logcheck nicht konnte))
  • Metainformationen zu Abhängigkeiten u.ä. waren in Kommentaren in Shellskripten – klassisches »ich habe da mal was ergänzt« und ganz in der Denke von C und Fehler == -1
  • Mit startpar/insserv war schon Parallelisierung da, aber das hat Spaß mit den Logmeldungen gegeben, also wurden schon diese ganzen log_action_begin_msg usw. eingeführt
  • qmail, postgres, apache, exim usw. erfinden alle ihre Prozessüberwachung
  • Socket-Aktivierung in OS X
  • cgroups, namespaces und viele Kernel-Funktionen, die Verbesserung brachten, aber nicht einfach nutzbar waren

Wer damals schon mit file-rc, runit, upstart usw. über den Tellerrand geschaut hat, hat gemerkt, dass es mächtig brodelt und es musste einen Knall geben. Der war im Grunde zwar nicht sonderlich innovativ, aber hat einfach all diese ganzen Bestrebungen eingesammelt und verbunden, die damals herumwaberten. Das etwas passieren musste, lag in der Luft, und dass es sich massiv von SysV-Init unterscheidet, hat auch nur jene überrascht, die bis dahin nicht viel anderes gemacht hatten.

Im Grunde war der Schritt von Upstart zu Systemd nicht groß, aber bei all dem, was noch mit hinzugenommen wurde, entstand wahrscheinlich in den Köpfen der Entwickler ein große Vision. Und das wird das eigentliche Problem gewesen sein: vieles von dem, was man gesehen hat, was gesagt wurde und was passiert ist, war Entwicklung.

Zu Beginn wussten die Entwickler vielleicht nicht, wie komplex die ganzen Anforderungen werden und waren sicher auch damals davon überzeugt, nur ganz wenig Abhängigkeitsdeklarationen zu benötigen – da wird sie aber irgendwann die Zeit eingeholt haben und das ganze ist vielfältig geworden. Oder wie Brecht sprach: »Wer A sagt, muss nicht B sagen, er kann auch erkennen, dass A falsch war.«

Dann glaube ich auch, dass die Entwickler noch gar nicht so richtig wussten, wie sie einige Details umsetzen. Unterbewusste hatten sie schon eine vage Vorstellung und haben deshalb auch so komische, halbe Aussagen getätigt. Aber konkret in Worte konnten sie es damals auch nicht fassen.

Als drittes glaube ich, dass sie im Rausch der inneren Endorphinwelle so getragen waren, dass sie der Meinung waren, alles neu und richtig machen zu müssen. In einem Interview mit Lennart hat er erzählt, dass sie rsyslog bzgl. Anpassungen angefragt hatten, aber diese lehnten ab. Ich selbst habe als Betreuer des Debian-Pakets für Bootchart miterlebt, welch Eiertanz es war, die Logs von der initrd ins laufende System zu bekommen, um sie zu speichern; gleichen Problem hatten auch die Leute von fsck. Dass da die Entwickler kurzer Hand journald erfunden haben, um das Problem mit initrd u. s. w. zu lösen (wofür rsyslog nicht zu haben war), liegt auch auf der Hand.

Für Networkmanager und ifupdown liegt der Schritt zu networkd auch auf der Hand. Systemd-coredump liegt auch auf der Hand, wenn man sich für das Problem interessiert. Es sind viele Programme, die echt was verbessern.

Aber wie oben schon gesagt, ich glaube, wir haben bei Systemd einfach high-live die Entwicklung miterlebt, mit all ihren Irrungen und Wirrungen, dem Vor und Zurück und dass es am Ende anders aussieht, als es angekündigt wurde. So kenne ich das auch. Eine Glaskugel wäre cool, aber ist nie greifbar und »Life can only be understood backwards, but it must be lived forwards.« und man muss auch bedenken, dass da Menschen am Werk sind, die mit Gefühlen und Einstellungen einfach nicht immer so präzise und deterministisch wie ein Computerprogramm arbeiten.

Dass sich auch Systemd + Journald + udev erst mal zu einem Klumpen verdichtet haben und das ganze System sehr monolithisch ist, wundert mich auch nicht. Das geht mir bei der Programmierung auch so, dass ich erst vielen zusammenklebe und dann über die Zeit merke, wo ich etwas sinnvoll auseinander trennen und abstrahieren kann. Da habe ich auch keine Bedenken, dass in ein paar Jahren es nicht auch einen Journald-ng gibt.

Ich denke, wir sollten den Entwicklern dankbar sein, dass sie all diese Änderungen durchgeboxt, das System wieder vorangebracht und wieder Schwung in die Entwicklung gebracht haben.