Es taucht gelegentlich die Frage auf, was overcommit_memory unter Linux darstellt, welche Form verwendet wird und warum. Daher schauen wir uns das nun einmal näher an.

Overcommit beim Speicher bedeutet, dass mehr Speicher an Programme vergeben werden kann, als das System überhaupt besitzt. Da stellt sich einem die Frage, warum so etwas gut sein sollte. Die Kerneldokumentation schreibt zu diesem Punkt:

This feature can be very useful because there are a lot of programs that malloc() huge amounts of memory just-in-case and don’t use much of it.

Mit anderen Worten: Vielen Programmieren ist der wirkliche Speicherbedarf ihrer Programme unklar und sie reservieren einfach einmal reichlich davon. Wenn der Speicherplatz dann nicht vorhanden ist, starten sie nicht. Wenn es dann noch viele solcher Programme gleichzeitig auf einem System gibt, wird es richtig schwierig.

Dank overcommit können diese nun starten und laufen auch, da sie den Speicher oftmals wirklich nicht benötigen, sie greifen darauf gar nicht zu.

So gesehen, bewirkt das overcommit des Speichers eine Lösung zu einem Problem, welches unsorgfältig arbeitende Programmierer verursacht haben.

Linux bietet drei Arten von overcommit_memory an. Diese werden per sysctl oder dem proc-Dateisystem gesetzt oder ausgelesen. Die Einstellungen sind dann bei proc in der Datei /proc/sys/vm/overcommit_memory zu finden.

Die Voreinstellung ist dabei der Wert 0. Die Kerneldokumentation sagt dazu:

Heuristic overcommit handling. Obvious overcommits of address space are refused. Used for a typical system. It ensures a seriously wild allocation fails while allowing overcommit to reduce swap usage. root is allowed to allocate slightly more memory in this mode. This is the default.

Das Kritische ist hier das heuristic im Satz. Der Kernel überlegt sich hier, wieviel Speicher er sinnvoll per overcommit vergeben könnte. Das ist ein Kompromiss zwischen völligem overcommit und gar keinem.

Das völlige overcommit wird durch den Wert 1 ermöglicht:

Always overcommit. Appropriate for some scientific applications. Classic example is code using sparse arrays and just relying on the virtual memory consisting almost entirely of zero pages.

Damit bekommt ein Programm immer Speicher zugeteilt, egal wie groß dieser ist. Schwierig wird es hier, wie im obigen Fall, wenn auf den Speicher auch zugegriffen werden soll.

Die letzte Option stellt der Wert 2 dar, hier ist gar kein overcommit möglich, dann muss der Speicher auch vorhanden sein, wenn er angefordert wird. Anderenfalls liefert malloc() einen NULL-Pointer zurück und die Software kann darauf reagieren:

Don’t overcommit. The total address space commit for the system is not permitted to exceed swap + a configurable amount (default is 50%) of physical RAM. Depending on the amount you use, in most situations this means a process will not be killed while accessing pages but will receive errors on memory allocation as appropriate.

Hier gibt es gleich noch eine Einschränkung mehr: Der Speicher hat auch eine Obergrenze, ein Programm kann nicht allen Speicher allokieren. Die Kerneldokumentation erwähnt auch explizit, wann das verwendet werden sollte:

Useful for applications that want to guarantee their memory allocations will be available in the future without having to initialize every page.

Mit anderen Worten: Speicher der angefordert und vom Kernel bewilligt wurde ist auch immer vorhanden.

Praktischer Test

Mit dem Wissen, kann das nun durchgetestet werden. Dazu verwende ich einfach einmal ein kleines Programm:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define SIZE 1024*1024*256
long long count=1;

int main()
{
   char *buf;
   buf=malloc(SIZE);
   if (buf==NULL) {printf("first malloc failed\n"); exit(-1);}
   while (1) { 
     count++;
     printf("allocated: %lu MB\n",count*256);
     buf=realloc(buf,count*SIZE);
     if(buf==NULL) {
        printf("failed to allocate %lu memory\n",count*SIZE);
        exit(-1);
     }
     if (count > 400) {
         printf("100 GB of RAM allocated, stopping\n");
         exit(0);
     }
   }
}

Was macht dieses kleine Programm?

Es wird ein Speicherbereich von 256 MB angefordert:

buf=malloc(SIZE);

Danach wird geprüft, ob dieser Speicher bewilligt wurde. Ist das der Fall, wird nach und nach durch

buf=realloc(buf,count*SIZE);

jeweils der angeforderte Speicher um 256 MB vergrößert. In den erlaubten overcommit-Fällen geht das bis ans Ende des virtuellen Speicherbereiches, das kann dann auch ewig dauern. Daher habe ich noch eine Abbruchbedingung hinzugefügt:

 if (count > 400) {
     printf("100 GB of RAM allocated, stopping\n");
     exit(0);
 }

Das sind 100 GB, soviel RAM hat mein Testsystem garantiert nicht, noch nicht einmal annähernd. Daher ist diese Grenze durchaus sinnvoll.

Das ganze kann nun kompiliert werden:

$ gcc -o realloc realloc.c

Schon haben wir unser Testprogramm: realloc

Da swap zum Speicher zählt, ich aber vermeiden möchte, dass mein System unnötig auf der Festplatte herum schreibt, schalte ich diesen erst einmal ab:

# swapoff -a

Damit ist nun zu Beginn mein Speicher so ausgelastet:

# free -h
          total        used        free      shared  buff/cache available
Mem:       15Gi       2,0Gi        11Gi       262Mi       1,9Gi      13Gi
Swap:        0B          0B          0B

Es ist also duchraus schon Speicherplazt belegt, das System hat insesamt 16GB an RAM als Hauptspeicher und es gibt keinen Swapspace mehr.

default overcommit

Das ist der erste Testfall, der normale Zustand von overcommit_memory=0. Da hier zu erwarten ist, dass wir mehr Speicher bekommen werden, als wir tatsälich haben, ist die Ausgabe per tail auf die letzten 10 Zeilen beschränkt:

$ cat /proc/sys/vm/overcommit_memory 
0
$ ./realloc |tail
allocated: 100608 MB
allocated: 100864 MB
allocated: 101120 MB
allocated: 101376 MB
allocated: 101632 MB
allocated: 101888 MB
allocated: 102144 MB
allocated: 102400 MB
allocated: 102656 MB
100 GB of RAM allocated, stopping

Siehe da, wir können problemlos 100 GB RAM anfordern und es ginge noch weit mehr, würden wir hier nicht abbrechen.

full overcommit

Hier ist das gleiche Verhalten zu erwarten, warum sollte hier auch weniger RAM vergeben werden?

$ cat /proc/sys/vm/overcommit_memory
1
$ ./realloc |tail
allocated: 100608 MB
allocated: 100864 MB
allocated: 101120 MB
allocated: 101376 MB
allocated: 101632 MB
allocated: 101888 MB
allocated: 102144 MB
allocated: 102400 MB
allocated: 102656 MB
100 GB of RAM allocated, stopping

Das war nun wenig überraschend.

no overcommit

Was passiert nun, wenn wir gar keien overcommit zulassen?

$ cat /proc/sys/vm/overcommit_memory
2
$ ./realloc |tail
allocated: 1536 MB
allocated: 1792 MB
allocated: 2048 MB
allocated: 2304 MB
allocated: 2560 MB
allocated: 2816 MB
allocated: 3072 MB
allocated: 3328 MB
allocated: 3584 MB
failed to allocate 3758096384 memory

Voila, das Programm bricht sauber ab. Warum wir hier nicht die vollen freien Bytes bekommen, liegt in der obigen Aussage. Per default wird nur Swap + 50% RAM vergeben. Swap haben wir nicht mehr und zu dem Zeitpunkt waren vermutlich nur etwas über 7 GB RAM aktuell frei.

Abgewandelter Test

Offenbar verhält sich das heuristic wie völliger overcommit. Es sollte doch hier einen Unterschied geben, oder?

Wie wäre es also, wenn wir obiges Testprogramm anpassen und den zugewiesenen Speicher auch einfach einmal benutzen?

Dazu passen wir einfach den obigen Code an und fügen nach der Abfrage ob ein NULL-Pointer zurückgegeben wurde, ein

 // use the memory
 memset(buf,0,count*MB);

hinzu. Dieser einfach Befehl schreibt einfach nur Nullen in den zugewiesenen Speicherbereich. Das Programm nennen wir nun realloc2.

Dann schauen wir einmal, was jetzt passiert…

default overcommit

Da wir den Speicher auch gleich noch befüllen, dauert die Ausführung des Programmes nun deutlich länger.

Jetzt ist erst einmal wieder die heuristic gefragt:

$ cat /proc/sys/vm/overcommit_memory
0
$ ./realloc2  |tail
allocated: 12032 MB
allocated: 12288 MB
allocated: 12544 MB
allocated: 12800 MB
allocated: 13056 MB
allocated: 13312 MB
allocated: 13568 MB
allocated: 13824 MB
allocated: 14080 MB
failed to allocate 14763950080 memory

Aha, nun ist bei etwas unter 14 GB Schluss. Denn mehr Speicher kann das System auch nicht vergeben:

$ free -h
         total        used        free      shared  buff/cache available
Mem:      15Gi       1,5Gi        13Gi       251Mi       363Mi      13Gi
Swap:       0B          0B          0B

Das ist also durchaus sinnvoll!

no overcommit

Was passiert aber im Fall von völligem overcommit?

Das ist nun der interessante Teil:

$ cat /proc/sys/vm/overcommit_memory
1
$ ./realloc2  |tail
$ echo $?
0

Nun was ist das? Das Programm liefert gar keine Ausgabe, der Rückgabewert ist aber ok?

Die Antwort liefert nun dmesg:

dmesg |tail -3
[149965.615871] Out of memory: Kill process 13185 (realloc2) score 879 or sacrifice child
[149965.615876] Killed process 13185 (realloc2) total-vm:14420200kB, anon-rss:14316496kB, file-rss:4kB, shmem-rss:0kB
[149965.766914] oom_reaper: reaped process 13185 (realloc2), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

Da hat der Out of memory Killer vom Kernel zugeschlagen! Das ist nun völlig fatal, das Programm könnte gar nicht auf den fehlenden Speicher reagieren.

no overcommit

Wie sieht das nun aus, wenn es gar keinen overcommit gibt?

Genau, es ist das Gleiche wie im ersten Fall ohne den memset()-Aufruf:

$ cat /proc/sys/vm/overcommit_memory
2
$ ./realloc2  |tail
allocated: 1536 MB
allocated: 1792 MB
allocated: 2048 MB
allocated: 2304 MB
allocated: 2560 MB
allocated: 2816 MB
allocated: 3072 MB
allocated: 3328 MB
allocated: 3584 MB
failed to allocate 3758096384 memory

Ist dann der default ok?

Darüber lässt sich nun streiten. Letztendlich ist das nur ein Kompromiss zu dem unsäglichen Speicheranforderungsverhalten diverser Programme. Dabei wird Speicher so lange per overcommit zugewiesen, wie dieser auch nicht benutzt wird. Daher gab es im ersten Fall die 100 GB an zugewiesenen Speicher, obwohl dieser definitiv nicht im System verfügbar ist, es gab aber noch genug freie Reserven.

Wenn wir jedoch den Speicher auch gleich belegen, dann reduziert sich der freie Pool und irgendwann vergibt dann auch der Kernel keinen Speicher mehr.

Also ist doch alles gut?

Das ist leider nicht ganz so einfach: Was passiert, wenn mehrere Programme Speicher allokieren und dann vielleicht ein wenig später erst nutzen? Dann würden sie erst aus dem freien Pool viel Speicher per overcommit zugewiesen bekommen. Wenn sie ihn dann aber verwenden, kann es sein, dass die anderen Programme schon den letzten freien Speicher verwendet, also belegt haben.

Simulieren kann man das mit obigem Programm auch. Man müsste es entsprechend anpassen oder einfach mehrfach zeitversetzt starten. Dann tritt, wie es zu erwarten war, wieder das Problem mit dem fehlenden Speicher bei völligem overcommit auf:

$ ./realloc2 |tail
$ echo $?
0
$ dmesg |tail -3
[155595.704888] Out of memory: Kill process 24296 (realloc2) score 696 or sacrifice child
[155595.704892] Killed process 24296 (realloc2) total-vm:11536616kB, anon-rss:11338296kB, file-rss:4kB, shmem-rss:0kB
[155595.876869] oom_reaper: reaped process 24296 (realloc2), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

Hier wird halt die Folge des Kompromisses offenbar: Es kann dennoch zu plötzlichem, eigentlich unerklärlichem Absturz eines Programmes kommen. Das ist für ein Desktop-System oder Notebook in aller Regel noch tolerabel, für einen Server jedoch durchaus fatal.

Und nein, automatische Neustarts durch systemd sind hier keine adäquate Lösung! Ein Administrator sollte wissen, wann ein Dienst warum beendet wird. Nur so kann auch geeignet darauf reagiert werden.

Gute Programme würden eventuell darauf reagieren, wenn der Speicher knapper wird und dann zum Beispiel einige Dienste reduzieren, keine neuen Verbindungen annehmen bis wieder Speicher da ist oder ähnliches. Wenn aber der OOM-Killer zuschlägt, hat ein Programm keine Chance und der Entwickler könnte das Problem noch nicht einmal lokalisieren oder beheben: Es liegt nicht mehr in seiner Macht.

Weitere Einstellungen für overcommit

Wenn wir uns schon overcommit ansehen, dann sollten wir auch die weiteren Optionen dazu ansehen. Die sind mitunter auch relevant um ein System optimal nutzen zu können.

admin_reserve_kbytes

Über diesen Wert kann dem Administrator noch ein Rest an Speicher freigehalten werden, so dass er sich zum Beispiel per ssh einwählen und wildgewordene Prozesse beenden kann.

Der default-Wert hierfür sind der Minimum von 3% der freien Seiten oder 8 kB. Das ist aber nur sinnvoll, für overcommit_memory=0. Wird kein overcommit erlaubt, so muss der gesamte virtuelle Speicher für die zu startenden Prozesse (also zum Beispiel ssh und bash) vorhanden sein, der Wert sollte also größer sein. Die Kerneldokumentation empfiehlt hier dann 128 MB.

overcommit_kbytes und overcommit_ratio

Diese beiden Werte schließen sich gegenseitig aus, wird einer aktiviert, so wird der andere deaktiviert. Sie greifen auch nur, wenn overcommit_memory=2 gesetzt ist.

Dann dürfen Prozesse nicht mehr Speicher allokieren als Swap-Space plus den angegebenen Wert an RAM. Im ersten Fall, also bei overcommit_kbytes sind es die absoluten Werte, im zweiten Fall ist es der Prozentteil des RAMs. Dieser Wert steht per default auf 50, damit sind maximal Swap-Sapce plus 50% des RAMs für einen Prozess nutzbar.

Wenn kein Swapspeicher vorhanden ist, bedeutet dass, das ein Prozess in dem Fall nie mehr als 50% des verfügbaren RAMs allokieren kann. Das sollte einem durchaus bewusst sein und mitunter sollte der Wert dann entsprechend angepasst werden!

Fazit

Es ist auf der einen Seite recht traurig, dass viele Programmierer nicht darauf achten, wieviel Speicher sie wirklich benötigen. Mitunter greifen sie auch auf Bibliotheken zu, die sich ebenso verhalten, weil ein anderer Programmierer zu bequem war, nachzudenken.

Das führte dann dazu, dass overcommit_memory eingeführt wurde und viele Programme laufen damit wunderbar obwohl sie mehr Speicher belegen wollen, als das System hat.

Damit wird aber der Druck auf die Programmierer reduziert, sorgfältiger zu arbeiten. Es gibt scheinbar keine Probleme mehr.

Auf der anderen Seite wiederum, verhindert das overcommit_memory, dass ein Programm auf Speicherknappheit geeignet reagieren kann. Es wird dann mitunter einfach beendet, obwohl es fehlerfrei läuft.

Das führte dann auch zu Entwicklungen von Hilfsprogrammen wie monit oder supervisor und auch systemd bietet die Eigenschaft: Wenn ein Programm, warum auch immer, unsanft beendet wird, so wird es einfach neu gestartet.

Insgesamt gesehen, liegt das Kind schon im berühmten Brunnen und man muss damit irgendwie leben. Daher finde ich persönlich, dass die default-Einstellung von `overcommit_memory=0 auf einem Notebook oder Desktop durchaus vertretbar ist. Diese werden häufiger einmal neu gestartet oder wenn hier ein Programm bei der Arbeit crasht, dann ist es ärgerlich, kann aber leicht neu gestartet werden. Viele Programme erkennen das und bieten an, den alten Zustand wieder herzustellen.

Schwieriger sehe ich das allerdings bei Servern. Da ist das Verhalten der Programme, deren Nutzung und die Erwartung eine andere. Hier rate ich dazu, es einfach abzustellen und für genügend Swap-Speicher zu sorgen.

Es gibt viele Ansätze für hochverfügbare Dateien zu realisieren. Gerade viele hochverfügbaren Serverlösungen setzen auf hochverfügbare Dateien. Eine Lösung, dies bei einem Serverausfall abzufangen, betsteht darin, einfach einen externen Dateiserver, also ein NAS oder SAN zu verwenden.

Das bleibt bestehen, wenn der Server einmal weg ist. Aber wie regelt man, wer darauf zugriff haben darf und wie? Und was passiert, wenn just dieses zentrale Speichmedium ausfällt?

Eine Lösung besteht darin, einfach die Daten auf zwei Servern lokal vorzuhalten und die irgendwie zu synchronisieren. Eine beliebte und Open Source Lösung war hier DRBD.

Die hatte allerdings einen Nachteil: Man konnte die Daten immer nur auf einem System nutzen, das zweite war nur ein Backup. Mit neueren Versionen ist diese Einschränkung wegefallen, es können nun beide Systeme aktiv genutzt werden.

Allerdings hat das noch immer ein Problem: Wer darf auf welche Daten zugreifen? Da muss es dann locking-Mechanismen geben, um sicherzustellen, dass nicht zwei Prozesse die gleiche Datei zeitgleich auf verschiedenen Systemen (nodes) verändern. Da kommt dann oft der Distributed Lock Manager zum Einsatz oder man setzt ein Dateisystem auf dem DRDB ein, dass diese Funktion ebenfalls bereit hält, wie zum Beispiel GlusterFS

Wenn aber GlusterFS dieses Locking bereits bietet und obendrein ein verteiltes Dateisystem darstellt: Geht es dann nicht auch ohne DRBD?

Einsatzzwecke von HA-Dateien im aktiv-aktiv-Modus

Es gibt viele Fälle, bei denen beide Systeme aktiv genutzt werden sollten:

  • Live-Migration von VMs

  • schnelle Verfügbarkeit bei Ausfall

  • höhere Performance durch Lastverteilung

Bei einer Live-Migration zum Beispiel mit QEMU wird dasselbe VM-Image auf einem zweiten Server gestartet und wartet auf den Abgleich der Daten wie die akutelle Hauptspeicherbelegung und welche Verbindungen aktiv sind. Dazu muss dann auch das zweite System auf das Image zugreifen können.

Beim Ausfall im aktiv-passiv-Modus fällt gleich alles aus und muss warten, bis das passive System aktiv ist. Bei aktiv-aktiv ist mitunter nur eine Hälfte betroffen und der Wechsel auf den anderen Server könnte schneller gehen.

Und die Geschwindigkeit ist eventuell auch höher, sofern sich die aktiven Nodes schnell synchronisieren können. Dazu beitet sich eine eigene Verbindung an. Dann kann ein Teil mit dem einen Node, der andere Teil mit den zweiten Node arbeiten.

Probleme bei aktiv-aktiv

Ein Problem wurde bereits erwähnt: Das locking muss geklärt werden. Sonst können zwei Prozesse auf verschiedenen Nodes dieselben Dateien verändern. Wer wird dann gewinnen? Mitunter werden dann Daten verloren oder noch schlimmer, die Datei ist anschließend korrupt und unnutzbar.

Ein weiteres Problem besteht aber im sogenannten split-brain-Fall. Die Server synchronisieren sich und stellen durch ein locking sicher, dass die Dateien nicht gleichzeitig mehrfach editiert werden. Die Änderungen werden dann in der Regel über eine eigene Netzwerkverbindung abgeglichen.

Was aber passiert, wenn diese Synchronisation unterbrochen ist? Wenn die zwei Nodes sich nicht mehr sehen? Wer ist denn dann der aktive Knoten? Die Lösung ist einfach: Es wird geprüft, ob der andere Node erreichbar und funktional ist. Nur wenn das nicht geht, die Node sich nicht sehen, wohl aber beide von den Clients angesprochen werden können?

Das ist ein Problem, jeder der beiden Nodes denkt dann, er wäre der alleinige aktive Knoten und nimmt Datenänderungen gemäß den Clientanforderungen vor. Das kann nur im Chaos enden und ist der größte Alptraum in diesem Umfeld

Der Schiedsrichter

Bei GlusterFS gibt es die Möglichkeit drei Server zu verwenden und über ein Quorum zu definieren, welche noch die alleinigen aktiven Nodes sind. Wenn dann einer ausfällt oder von einem anderen Node nicht mehr gesehen wird, so sind noch die Nodes aktiv, die sich sehen.

Sieht ein Node die zwei anderen Nodes nicht, so ist er der isolierte und verweigert daraufhin die weitere Arbeit bis alle Systeme wieder sichtbar sind und ein Abgleich der Daten stattgefunden hat.

Das ist eine schöne Lösung, hat aber einen Haken: Dann sind die Daten nicht zweimal sondern dreimal vorhanden, es wird dann der dreifache Speicherplatz benötigt, statt dem doppelten.

Hier hat GlusterFS eine elegante Lösung gefunden. Es gibt einen Node der nur Schiedsrichter (arbiter) spielt. Der muss nicht den vollen Datensatz zur Verfügung haben, sondern lediglich nur die Metadaten der Dateien um zu sehen, wie der Status ist, also zum Beispiel der Zeitpunkt der letzten Änderung, Zugriffsrechte, Größe, etc. Das belegt dann nur noch einen Bruchteil des Speicherplatzes und ist dann wieder in einem vertretbarem Rahmen.

Die Daten liegen dann lokal in einem Verzeichnis auf dem Node, dieses wird brick genannt. Allerdings werden Daten, die dahin geschrieben werden, nicht synchronisiert. Dafür muss das GlusterFS auch auf dem Server gemountet werden. Das kann per NFS erfolgen, besser ist aber das Userland per fuse eingebunden. Dabei findet auch eine Art der Lastverteilung auf die Nodes statt.

Fazit

Mit GlusterFS sind auch andere Szenarien realisierbar wie ein verteiltes Speichern von Daten oder auch etwas was sich Geo-Replikation nennt, da liegen die Dateien mitunter auf verschiedenen Kontinenten.

Aber eine der schönsten Anwendungen sind die hochverfügbaren Dateien in Verbindung mit einem arbiter. Gerade wenn Live-Migrationen von virtuellen Maschinen interessant sind oder die Daten möglichst immer da sein müssen, weil es zum Beispiel ein Home-Verzeichnis ist, so ist das eine schöne Lösung.

Es gibt auch andere Lösungen wie Ceph oder BeeGFS, aber meines Wissens haben diese alle nicht diese arbiter Funktion.

Die Verwaltung von Passwörtern ist schon immer ein Problem gewesen. Ein Passwort für alle Dienste ist keine gute Option, sollte es einmal bekannt werden, wären gleich alle Dienste gefährdet. Einfache, leicht zu merkende Passwörter sind da auch keine Option, die meisten Systeme lehnen diese auch ab. Der Passwortmanager des Browsers ist durchaus eine Lösung. Allerdings sollte man die Sicherheit hier, selbst mit einem Masterpasswort, nicht allzusehr vertrauen. Da gab es viel zu oft schon Möglichkeiten die gespeicherten Daten remote zu erlangen.

Eine Lösung: KeePassXC

KeePass war ein Passwortmanager, der ursprünglich nur für Windows verfügbar war. Eine Alternative dazu unter Linux entstand mit dem Namen KeePassX. Beide sind mittlerweile frei für beide Plattformen verfügbar. Allerdings stoppte die Entwickling von KeePassX, die letzte Version ist von 2016. Davon spaltete sich eine weitere Entwicklung ab: KeePassXC

KeePass selber ist zwar auch noch verfügbar, basiert aber auf C# und benötigt daher .NET von Microsoft.

Diese Variante ist auch für Windows und MacOS verfügbar, ist komplett Open Source und verwendet das gleiche Datenbankformat wie aktuelle KeePass-Versionen.

Die Einträge können, wenig überraschend, gruppiert werden. Es kann eine URL hinterlegt werden, die auch von KeePassXC direkt geöffnet werden kann.

Damit kann man nicht nur elegant die Passwörter verwalten, es gibt auch die Option Auto-Type, die füllt die Daten automatisch in das Login-Feld ein.

Noch besser geht es aber mit den Browser-Plugins. Die lassen sich mit dem KeePassX verbinden und darüber kann dann der Browser die Daten einfügen, nachdem man mit einem Mausklick dieses bestätigt hat. Das erleichtert das Leben doch ungemein.

Das Plugin erkennt dabei den richtigen Eintrag anhand der verwendeten URL, diese sollte also auch beim Eintrag in KeePassX hinterlegt sein. Wichtig: http und https werden unterschieden. Ist also nur ein https-Eintrag in der der Datenbank und wird per http zugegriffen, so wird der Eintrag nicht gefunden.

Wird er hingegen gefunden, erscheint beim Loginfeld ein grünes KeePassXC-Logo auf das man klicken kann.

Wichtig: KeePassXC muss dazu auf dem System laufen und die Datenbank muss auch per Passphrase entsperrt sein.

Wenn dem so ist, poppt eine Abfrage von KeePassXC auf, ob der Browser die gewünschten Daten abfragen darf. Diese muss man bestätigen und das Login- und Passwort-Feld werden befüllt. Diese Entscheidung kann auch permanent abgespeichert werden, so dass beim nächsten Mal nicht nachgefragt wird.

Kommandozeile

Ein Problem besteht oft darin, dass man die Datenbank nicht dabei hat. Wenn diese auf einem remote erreichbaren System liegt, so fehlt doch oft die grafische Oberfläche oder diese braucht mehr Ressourcen als im Moment zur Verfügung stehen.

Für diese Fälle, gibt es das Kommandozeilentool keepassxc-cli. Das ist zwar nicht sonderlich komfortabel, die Passphrase für das Öffnen der Datenbank muss bei jeder Aktion eingegeben werden. Aber es besteht dennoch die Möglichkeit auf Einträge zuzugreifen.

Problem Multiuser

Das ist leider ein offenes Problem, es gibt nur eine Passphrase um die Datenbank zu entsperren. Sollen sich also mehrere Benutzer eine Datenbank teilen, so geht das über Lese- und Schreibrechte der Gruppe, es müssen aber alle die gleiche Passphrase verwenden. Das ist etwas unschön.

Installation

Die Installation ist unter Debian sehr einfach:

apt install keepassxc

Nach dem Starten hat man die selbterklärenden Optionen

  • Neue Datenbank erstellen
  • Existierende Datenbank öffnen
  • Aus KeePass 1 importieren
  • Aus CSV importieren

Da man in aller Regel noch nichts hat, ist es gut mit einer neuen Datenbank zu starten. Als erstes muss man sich dazu den Namen für die Datei auswählen und eine Passphrase wählen. Hier wird zwar nur nach einem Passwort gefragt, aber eine längere Passphrase ist doch ratsam, schließlich landen hier doch irgendwann sehr viele, wichtige Einträge die gut gesichert sein sollten.

Es gibt auch eine Option eine Schlüsseldatei zu verwenden, wenn die jedoch verloren geht, hat man verloren. Also dann ist doch eine gute Passphrase die bessere Option.

Danach ist die Datenbank geöffnet und man kann Einträge erstellen.

Browserintegration

Um die Browserplugins zu unterstützen, gibt es unter Werkzeuge und Anwendungseinstellungen das Feld Browser-Integration. Dort muss diese aktiviert werden. Dort gibt es auch gleich die Links zu den Plugins für die Browser Firefox und Google Chrome / Chromium / Vivaldi.

Hat man diese installiert, erscheint oben rechts in der URL-Leiste das ausgegraute KeePassXC-Icon.

Vorher muss aber noch in KeePassX die Integration für den jeweiligen Browsertyp aktiviert werden. Danach kann das Browser-Plugin mit KeePassXC verbunden werden, dazu muss lediglich auf das Icon und dann auf Verbinden geklickt werden. Anschließend muss noch ein eindeutiger Name für den Zugriff vergeben werden und das war es schon.

Weitere Einstellungen

Ein paar Einstellungen sind noch interessant, so kann ein Passwort kopiert werden, wird aber nach 10 Sekunden aus der Zwischenablage wieder gelöscht. Diesen Wert kann man konfigurieren, er passt aber in aller Regel. Es verhindert, dass aus Versehen das Passwort in ein anderes Feld eingefügt wird, wo es nicht hingehört.

Der Punkt Datenbank sperren nach einer Inaktivität von sollte eventuell angepasst werden. Dir Voreinstellung von 240 Sekunden ist doch etwas kurz und wer will schon so häufig die doch lange Passphrase eingeben.

Sinnvoll ist natürlich auch, dass die Datenbank geschlossen wird, wenn die Sitzung beendet wird.

Fazit

Das ist ein kleines, sehr nützliches Tool. Gerade in der Kombination mit den Browser-Plugins ist es eine deutliche Erleichterung, vor allem auch, wenn man mehrere verschiedene Browser verwendet.

Das war dann heute leider eine für mich traurige Nachricht, Pro-Linux hört auf!

Das war immer eine schöne, unaufgeregte Seite rund um Linux. Man mag es kaum glauben, aber das war ein fast ein volles, schönes Vierteljahrhundert. Nun haben sie beschlossen, die Seite einzustellen:

Es war uns eine Ehre

Irgendwo kann man es verstehen, nach 22 Jahren ist so manche Luft heraus und man mag vielleicht neue Aufgaben suchen. So gesehen, geht das jetzt völlig in Ordnung, es war eine schöne Zeit.

Nur wird mir die Seite in Zukunft fehlen, gerade im deutschsprachigen Raum gibt es kaum Alternativen.

Schwierige Zeiten

Hier muss ich aber einmal auch in die Runde werfen, dass die Zeiten in der IT irgendwie zu stehen scheint. Es gibt kaum wirkliche Innovationen und nur über neue Versionen von Software zu berichten, ist nicht unbedingt erfreulich.

Während auf der einen Seite Open Source immer mehr zu boomen scheint, ist auf der anderen Seite aber auch ein anderer Trend zu beobachten. Die Sourcen sind zwar frei, aber die Dokumentation wird weniger, die Programme werden meistens als Docker-Image parat gestellt und weitere Optionen werden verschwiegen.

Vieles deutet darauf hin, dass das dazu dient, auf der einen Seite Open Source auf der Fahne stehen zu haben und auf der anderen Seite über den Support oder gehostete Dienste Geld zu verdienen.

Das an sich ist nicht verwerflich, es ist jedoch nicht das, was alte Hasen unter Open Source verstehen. Das Ganze wird noch meist dadurch gesteigert, dass nicht einfach ein paar Bibliotheken verwendet werden, sondern gleich ganz Programmpakete die irgendwie miteinander verwoben sind. Da verliert man schnell den Überblick, da ist des gut, wenn es in einem Docker-Image versteckt ist?

Debugging ist da schon schwierig, aber wie sieht es da mit der Beurteilung der Sicherheit aus? Da kann man wenige Aussagen dazu treffen, da müsste man den Source Code der Komponenten analysieren, sowie deren Zusammenspiel. Was macht man jedoch, wenn es da keine Dokumentation dazu gibt? Beim Support nachfragen, ist wohl keine gute Option…

Fazit

Ich kann verstehen, dass sie nicht mehr mögen. Dennoch bedauere ich das, gerade vor dem Hintergrund des jahrelangen Genusses der Seite. Es ist schade, wenn sie verschwindet. Es war immer eine Berichterstattung ohne finanzielle Hintergedanken, auch wenn das eine oder andere kleine goodie geflossen sein mag. So bleibt mir nur zu schreiben:

Macht es gut und Danke für die schöne Zeit!

Die Frage taucht immer häufiger auf und die Meinungen gehen da weit auseinander. Es scheint ein einfaches Thema zu sein und irgendwie will da jeder mitreden. Aber ganz so einfach ist es nicht…

Allgemeines zu Swap

Wenn der Hauptspeicher ausging - es ist eine begrenzte Ressource - dann besteht offensichtlich ein Problem. Die Lösung war, das ganze Prozesse auf externe Speicher wie Magnetbänder oder Festplatten ausgelagert wurden. Das ist eine sehr langsame Lösung, denn es muss auch alles zum Abarbeiten wieder eingelesen werden.

Heutzutage passiert das nicht mehr, es werden nur einzlene Teilbereiche ausgelagert, sogenannte pages, das sind in aller Regel Blöcke von 4 kB Größe. Dadurch bleibt das meiste im Hauptspeicher, so weit es geht.

Welche Seiten ausgelagert werden, ist eine wichtige Frage. In Frage kommen hier vor allem Bereiche, die nie oder nur sehr selten benutzt werden. Deren fehlen fällt also gar nicht oder nur kaum auf. Eine Herausforderung besteht aber darin, diese zu finden. Dafür sorgt der Kenerldienst kswapd. Dieser lagert wenig oder gar nicht genutzte, insbesondere schon seit langem nicht mehr genutzte Seite aus, sollte der freie Speicher knapp werden.

Wie aggressiv das passiert, kann über den Kernelparamter vm.swappiness gesteuert werden. Je höher der Weter (0-100), desto aggressiver werden Seiten ausgelagert.

Ich habe genug RAM

Das ist einer der häufigsten Sätze, die man zu diesem Thema hört. Swap ist langsam, das will ich nicht, ich habe genug RAM, ich brauche keinen Swapspace.

Und damit ist das Thema doch schon erledigt, oder?

Der schwierige Teil

Auf dem Desktop scheint das durchaus eine gangbare Lösung zu sein, viele scheinen damit auch gut zu fahren. Da wird dann doch ein Swapbereich angelegt, da man so etwas wie suspend-to-disk nutzen will: Die Auslagerung von allem um nach einem Neustart an der Stelle weiterarbeiten zu können wo man aufgehört hat.

Gleichzeitig wir dann vm.swappiness=0 gesetzt, um das Paging zu verhindern.

Aber selbst wenn das scheinbar propblemlos läuft, sollte man es auf einem Server auch so betreiben?

Was ist im RAM?

Man sollte einmal einen Blick darauf werfen, wozu der Hauptspeicher genutzt wird:

  • Programmcode
  • Daten, statische und dynamische
  • Datenpuffer
  • Datencache

Die ersten beiden Punkte sind offensichtlich. Die zwei anderen sind aber auch von Interessant. Daten, die zum Beispiel auf eine Festplatte geschrieben werden sollen, werden nicht sofort geschrieben, sie landen erst in einem Datenpuffer.

Der Grund ist einfach: Das Programm müsste so lange angehalten werden, bis alle Daten geschrieben sind. Solche Fälle gibt es auch, aber in aller Regel ist es einem Programm egal, ob die Daten auch schon wirklich geschrieben wurden, es arbeitet dann einfach weiter.

Die Daten aus den Datenpuffer (buffer) werden dann vom Kernel im Hintergrund auf den Datenträger geschrieben. Das erhöht die Ablauf- geschwindigkeit der Programme immens.

Was ist aber mit Daten, die man geschrieben hat und wieder einlesen möchte? Hier muss das Programm dann so lange warten, bis die Daten vom externen Speicher eingelesen wurden. Das ist meistens nicht sehr performant.

Wie wäre es aber, wenn man den freien Speicher dazu verwendet, die Daten, die vorher im Datenpuffer waren, dort zu belassen damit man sie bei Bedarf wieder schnell einlesen, also aus dem RAM holen, kann?

Das ist die Aufgabe vom Datencache: Warum sollte man den freien Speicher nicht dafür verwenden? Das Gute daran ist auch, dass man diesen Speicher jederzeit problemlos freigeben kann.

Abwägungsfrage

Wenn ein Datenpuffer und -cache im RAM sehr effektiv sind, ungenutzte Seiten jedoch vermutlich nie oder nur sehr selten benutzt werden, wie geht man damit um, wenn der Hauptspeicher sich füllt?

Das ist nun der Punkt, wo vm.swappiness eine Rolle spielt. Sollte man nicht die vermeintlich nie bis selten genutzen Seiten auslagern um die Vorteile von Datencache und Datenpuffer besser nutzen zu können?

Schließlich profitieren die Programme immens von diesen zwei Funktionen, es wäre dann doch schlecht, sie nicht zu nutzen. Es ist also durchaus sinnvoll, dass die vm.swappiness nicht auf Null gesetzt werden sollte und man einen Swapbereich hat.

Es wird noch komplizierter

Warum sollte man teile vom Programmcode in den Swap schreiben, das Programm liegt doch schon auf der Festplatte. Genau, die werden auch gar nicht in den Swap ausgelagert…

Aber was ist mit dem vielen Speicherbedarf? Ein Programm legt in der Regel beim Start oder später bei der weiteren Ausführung fest, wieviel Speicher es denkt zu benötigen. Das wird dem Kernel mitgeteil und er reserviert dafür Speicherplatz. Was ist aber, wenn das Programm den Speicher doch nicht im vollen Umfang benötigt?

Das Programmdilemma

Viele Programme greifen auf bestehende Bibliotheken zu, diese allokieren oft reichlich Speicherplatz, egal ob sie ihn benötigen oder auch nicht. In aller Regel ist der Speicher auch vorhanden, der Progammierer denkt dabei gar nicht darüber nach.

Wenn die Programme aber viel Speicher verlangen, ihn jedoch nicht benötigen, dann könnte man ihnen den doch einfach nur scheinbar geben.

So macht es der Kernel in aller Regel auch, es gibt dann die zwei Teile RSS, den sogenannten Resident Set Size und den VSZ, die sogenannte Virtual memory SiZe. Erstere muss wirklich im RAM liegen, für letzteres reicht Speicherplatz im Swap aus. Dieser wird erst bereitgestellt, wenn er wirklich benötigt wird.

Das klingt doch gut.

Nur: Wenn die Programme doch alle deutlich mehr Speicher anfordern, als sie benötigen, muss man deswegen gleich so großen Swapspace bereithalten?

Die Antwort ist nicht ganz so einfach.

Overcommit Memory

Bei Linux wurde aus diesem Grund das vm.overcommit_memory eingeführt. Damit kann man der Kernel angewiesen werden, jede Speicherplatzanforderung einfach zu bewilligen. Damit entfällt auch die Notwendigkeit diesen Speicherplatz überhaupt irgendwo zu haben.

Die Idee ist, dass die Programme wirklich zuviel Speicher anfordern, den sie in Wircklichkeit nie nutzen. Damit ist das Swap-Problem gelöst, man braucht ihn nicht mehr.

Aber: Was ist, wenn die Programme den Speicher doch benötigen?

Das ist ein sehr großes Problem: Wenn ein Programm Speicher anfordert, so bekommt es normalerweise als Antwort den Speicher zugeteilt oder die Fehlermeldung, dass kein Speicher mehr vorhanden ist. Darauf kann das Programm reagieren, eine Fehlermeldung generieren, mit weniger Speicher arbeiten, anderweitig welchen freigeben oder gar warten, bis die Anforderung erfüllbar ist.

Wenn aber der Speicher zugesagt wurde, er aber dann doch nicht da ist, wird das Programm mit SIGSEGV abgebrochen. Das ist fatal, es kann zwar das Signal abfangen und dann umschiffen, es fehlt jedoch der Kontext um geeignet damit umzugehen.

Bei einem Desktop-System ist das vermutlich egal, das Programm wird einfach neu gestartet und wenn das noch immer nicht funktioniert, wird das gesamte System einfach neu gestartet. Dann ist wieder reichlich freier Speicherplatz vorhanden.

Aber was ist mit einem Server? Hier wird doch erwartet, dass dieser am Besten das ganze Jahr ohne Unterbrechung durchläuft. Da wäre doch so eine Einstellung mehr als fatal!

Wenn man aber das vm.overcommit_memory hier abstellt, dann wird auch ein entsprechend großer Swapspeicher benötigt. Andernfalls könnte ein Programm gar keinen Speicher bekommen.

RSS und VSZ

Einfach ausgedrückt, ist RSS der Speicher, der im RAM liegt, VSZ der, der (virtuell) im Swap liegt.

Das ist nicht ganz korrekt, wenn man alle RSS-Werte aufsummiert, kann es mehr sein, als Hauptspeicher im System ist. Das liegt aber an einem anderen Konzept: shared memory und shared libraries Dise Speicherteile sind in mehreren Programmen identisch vorhanden und werden nur einmal im Speicher gehalten, jedoch bei jedem Prozess als ihm gehörig aufgelistet.

Aber als Faustregel kann man sagen: RSS+VSZ von allen Prozessen sollte immer kleiner sein als RAM+Swap.

Out of Memory

Was passiert nun, wenn wir kein overcommit vom Speicher zulassen und ein RSS+VSZ ausgeschöpft sind? Dann müsste das System stehen bleiben, es hat keinen Handlungsspielraum mehr, es würde einfrieren. Manche Betriebssyteme machen das, Linux hat da eine andere Lösung: OOM-Killer. Das ist ein Programm, dass laufende Prozesse beendet um Speicher freizubekommen. Das ist nicht ideal, mitunter wichtige Dienste laufen dann nicht mehr. Dafür ist das Gesamtsystem aber noch handlungsfähig.

Braucht man Swapspeicher?

Damit wären wir wieder bei der Eingangsfrage: Ich denke, zumindest auf einem Server sollte man nicht ohne Swapspeicher arbeiten und vor allem das vm.overcommit_memory=2 setzen. Alles andere ist sonst ein Glücksspiel.

Die Größe des Swaps ist dann in der Tat eine heikle Frage und ich denke, bei einem Server sollte der sehr wohl recht groß sein, auch wenn er vermutlich nie wirklich genutzt wird. Aber wer viel Geld für RAM ausgibt, sollte auch noch genug Geld haben, um auch einen brauchbaren Swapbereich finanzieren zu können.

Auch so Effekte wie Datencache und Datenpuffer sind sehr wichtig, von daher sollte man nicht beunruhigt sein, wenn ein paar Gigabyte Swap belegt sind, hier ist ein Beispiel:

$ free -h
          total        used        free      shared  buff/cache   available
Mem:      1.5Ti       489Gi       993Gi       110Mi        27Gi       1.0Ti
Swap:     5.4Ti       322Gi       5.0Ti

Das System arbeitet dabei tadellos, es sind keine Beeinträchtigungen zu bemerken.

Was ist wenn aktive Seiten ausgelagert werden

Das ist nun der schlimmste Fall der eintreten kann, daher wollen viele diesen dadurch vermeiden, dass sie gar keinen Swapbereich anlegen. Es müssen dann Seiten aus- und eingelesen werden, die aktive genutzt werden. Das Programm hält dann so lange an, bis die Seite da ist. Bei sehr aktiven Programmen geht dann der CPU-Anteil von 100% auf unter 1% hinunter! Das sollte mit allen Mitteln vermieden werden.

Hilft da ein schneller Swapspeicher

Das ist eine schwierige Frage: Sicherlich ist das ein- und auslagern von Seiten davon abhängig, wie schnell das Medium ist. Bei klassischen Festplatten muss der Lesekopf erst an die richtige Stelle bewegt werden, die Daten müssen eingelesen werden, wenn sie am Lesekopf vorbeikommen.

Da ist sicherlich eine SSD deutlich besser. Aber wenn man nun glaubt, eine NVMe-SSD ist fast so schnell wie RAM, damit dürfte es doch keine Einschränkung geben, der sollte sich vielleicht nicht wundern, wenn es dennoch langsam ist.

Die hohe Geschwindigkeit wird gewöhnlich über mehrere parallele Datenströme erreicht, beim pagen ist es aber in aller Regel immer nur ein Block. Auch Effekt wie Datencache und Datenpuffer sind hier nicht hilfreich, der Speicher ist schon ausgegangen. Das Einlesen der Datenseite um sie dann auszführen, benötigt auch seine Zeit.

Fazit

Ich denke, jeder der einene Server betreibt, ist gut darin beraten, auch einen Swapbereich anzulegen und das overcommit des Speichers abzuschalten. Wenn letzteres aber abgeschaltet ist, muss im freien Bereich auch genug Speicher für die Programme vorhanden sein, also auch im erst einmal nicht-genutzten virtuellen Bereich VSZ. Wenn dieser fehlt, brechen die meisten Programme mit no memory available ab.

Das ist jetzt nicht alles zu 100% präzise und mitunter ändern sich auch Dinge. Aber dennoch denke ich, dass ich damit nah an dem dran bin, was sinnvoll ist und was nicht.

Klar, wer ein Notebook mit 16 GB RAM und 128 GB SSD hat, der will nicht noch 16 GB oder mehr für Swap opfern, vor allem wenn es meistens völlig ungenutzt aussieht. Aber ein Notebook wird auch häufiger einmal neu gestartet und es ist auch nicht dramatisch, wenngleich unschön, wenn ein Programm einmal abstürzt.

Das ist ein Blogbeitrag via plerd, ein einfacher, minimaler, offsite Bloggenerator basierend auf Markdown und MultiMarkdown.

Das Tool ist in Perl geschrieben und generiert die Seiten automatisch und verlinkt diese. Das sieht nach einer einfachen und feinen Sache aus.

Es ist sogar leicht möglich Bilder einzubinden:

So liefert

![Ein bild aus der Pfalz](P1040953.JPG "Die Weinstraße in der Pfalz")

ein schönes Bild mit Weinfeldern und dem pfälzer Wald im Hintergrund. (Ja, in der Pfalz sind die Weinberge flach und der Wald hügelig…)

Ein bild aus der Pfalz

Auflistungen sind auch kein Problem

  • die gibt es leicht unnummeriert

  • mit einem Punkt beginnend

Es muss dann erst wieder normalen Text geben, sonst wird alles eingebettet. So liefert das hier:

2. oder nummeriert?

1. er passt die Zahlen an...
* und weiter geht es?

4. die Nummerierung erfolgt fortlaufend

diese Ausgabe:

  1. oder nummeriert?

  2. er passt die Zahlen an…

    • und weiter geht es?
  3. die Nummerierung erfolgt fortlaufend

Blockquotes gehen auch, ebenso verschiedene Headergrößen, so liefert:

> Header 1
> ========
> Header 2
> --------
> ###Header 3###

das hier:

Header 1

Header 2

Header 3

Betonungen auch: star double star underscore double underscore

Referenzen gehen auch:

References: [LUG-Erding][1]

[1]: https://www.lug-erding.de/

Das liefert:

References: LUG-Erding

Code ist auch einfach per backticks: example

Besser geht es mit Tabs oder 4 Leezeichen:

#!/bin/sh
echo $0
   PROC=${0##*/*/}
echo $PROC

Mit Multimarkdown gehen auch Tabellen:

So liefert

|        |    grouping     ||
| First  | Second | Third   |
|--------| :----: | -----:  |
| 1. Wert|  3.0   | 4.1     |
| 2. Wert|  33. 0 | 41      |
| 3. Wert |    doppelt     ||
[Eine Tabelle]

das hier:

Eine Tabelle
grouping
First Second Third
1. Wert 3.0 4.1
2. Wert 33.0 41
3. Wert doppelt


Das ist jetzt nicht unbedingt die hübscheste Tabelle, man kann aber wohl damit leben.

Es kann aber auch HTML direkt verwendet werden, wenn auch umgeben von Leerzeilen:

<br />

Das liefert einen break

Das ist alles wunderbar einfach und begrenzt flexibel genug um nutzbar zu sein. Man kann sogar die Templates anpassen…