<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Dirks Blog]]></title>
  <link href="http://www.lug-erding.de/blog//atom.xml" rel="self" />
  <link href="http://www.lug-erding.de/blog/" />
  <updated>2020-05-15T14:47:47+02:00</updated>
  <id>http://www.lug-erding.de/blog/</id>
  <author>
    <name><![CDATA[Dirk Geschke]]></name>
    <email><![CDATA[dirk@lug-erding.de]]></email>
  </author>
  <generator uri="https://github.com/jmacdotorg/plerd">Plerd</generator>


  <entry>
    <title type="html"><![CDATA[Linux und overcommit_memory]]></title>
    <link href="http://www.lug-erding.de/blog/2020-05-15-linux-und-overcommit_memory.html"/>
    <published>2020-05-15T11:31:35+02:00</published>
    <updated>2020-05-15T14:47:42+02:00</updated>
    <id>http://www.lug-erding.de/blog/2020-05-15-linux-und-overcommit_memory.html</id>
    <content type="html"><![CDATA[<p>Es taucht gelegentlich die Frage auf, was <code>overcommit_memory</code> unter
Linux darstellt, welche Form verwendet wird und warum. Daher schauen
wir uns das nun einmal näher an.</p>

<p>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:</p>

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

<p>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.</p>

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

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

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

<p>Die Voreinstellung ist dabei der Wert 0. Die Kerneldokumentation sagt dazu:</p>

<blockquote>
  <p>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.</p>
</blockquote>

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

<p>Das völlige <em>overcommit</em> wird durch den Wert 1 ermöglicht:</p>

<blockquote>
  <p>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.</p>
</blockquote>

<p>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.</p>

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

<blockquote>
  <p>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.</p>
</blockquote>

<p>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:</p>

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

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

<h2 id="praktischertest">Praktischer Test</h2>

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

<pre><code>#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdio.h&gt;

#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 &gt; 400) {
         printf("100 GB of RAM allocated, stopping\n");
         exit(0);
     }
   }
}
</code></pre>

<p>Was macht dieses kleine Programm? </p>

<p>Es wird ein Speicherbereich von 256 MB angefordert:</p>

<pre><code>buf=malloc(SIZE);
</code></pre>

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

<pre><code>buf=realloc(buf,count*SIZE);
</code></pre>

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

<pre><code> if (count &gt; 400) {
     printf("100 GB of RAM allocated, stopping\n");
     exit(0);
 }
</code></pre>

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

<p>Das ganze kann nun kompiliert werden:</p>

<pre><code>$ gcc -o realloc realloc.c
</code></pre>

<p>Schon haben wir unser Testprogramm: <code>realloc</code></p>

<p>Da <code>swap</code> 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:</p>

<pre><code># swapoff -a
</code></pre>

<p>Damit ist nun zu Beginn mein Speicher so ausgelastet:</p>

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

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

<h3 id="defaultovercommit">default overcommit</h3>

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

<pre><code>$ 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
</code></pre>

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

<h3 id="fullovercommit">full overcommit</h3>

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

<pre><code>$ 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
</code></pre>

<p>Das war nun wenig überraschend. </p>

<h3 id="noovercommit">no overcommit</h3>

<p>Was passiert nun, wenn wir gar keien <em>overcommit</em> zulassen?</p>

<pre><code>$ 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
</code></pre>

<p>Voila, das Programm bricht sauber ab. Warum wir hier nicht die vollen
freien Bytes bekommen, liegt in der obigen Aussage. Per <em>default</em> 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.</p>

<h2 id="abgewandeltertest">Abgewandelter Test</h2>

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

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

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

<pre><code> // use the memory
 memset(buf,0,count*MB);
</code></pre>

<p>hinzu. Dieser einfach Befehl schreibt einfach nur Nullen in den
zugewiesenen Speicherbereich. Das Programm nennen wir nun <code>realloc2</code>.</p>

<p>Dann schauen wir einmal, was jetzt passiert…</p>

<h3 id="defaultovercommit">default overcommit</h3>

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

<p>Jetzt ist erst einmal wieder die <em>heuristic</em> gefragt:</p>

<pre><code>$ 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
</code></pre>

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

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

<p>Das ist also durchaus sinnvoll!</p>

<h3 id="noovercommit">no overcommit</h3>

<p>Was passiert aber im Fall von völligem <em>overcommit</em>? </p>

<p>Das ist nun der interessante Teil:</p>

<pre><code>$ cat /proc/sys/vm/overcommit_memory
1
$ ./realloc2  |tail
$ echo $?
0
</code></pre>

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

<p>Die Antwort liefert nun <code>dmesg</code>:</p>

<pre><code>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
</code></pre>

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

<h3 id="noovercommit">no overcommit</h3>

<p>Wie sieht das nun aus, wenn es gar keinen <code>overcommit</code> gibt?</p>

<p>Genau, es ist das Gleiche wie im ersten Fall ohne den
<code>memset()</code>-Aufruf:</p>

<pre><code>$ 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
</code></pre>

<h2 id="istdannder_default_ok">Ist dann der <em>default</em> ok?</h2>

<p>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 <em>overcommit</em> 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. </p>

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

<p>Also ist doch alles gut? </p>

<p>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 <em>overcommit</em> zugewiesen bekommen. Wenn sie ihn dann aber verwenden,
kann es sein, dass die anderen Programme schon den letzten freien
Speicher verwendet, also belegt haben.</p>

<p>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 <em>overcommit</em> auf:</p>

<pre><code>$ ./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
</code></pre>

<p>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. </p>

<p>Und nein, automatische Neustarts durch <code>systemd</code> 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.</p>

<p>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.</p>

<h2 id="weitereeinstellungenfr_overcommit_">Weitere Einstellungen für <em>overcommit</em> </h2>

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

<h3 id="admin_reserve_kbytes"><code>admin_reserve_kbytes</code></h3>

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

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

<h3 id="overcommit_kbytesundovercommit_ratio"><code>overcommit_kbytes</code> und <code>overcommit_ratio</code></h3>

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

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

<p>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!</p>

<h1 id="fazit">Fazit</h1>

<p>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.</p>

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

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

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

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

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

<p>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.</p>
]]></content>
  </entry>

  <entry>
    <title type="html"><![CDATA[Hochverfügbare Dateien mit GlusterFS]]></title>
    <link href="http://www.lug-erding.de/blog/2020-05-13-hochverf%C3%BCgbare-dateien-mit-glusterfs.html"/>
    <published>2020-05-13T17:17:35+02:00</published>
    <updated>2020-05-13T18:17:55+02:00</updated>
    <id>http://www.lug-erding.de/blog/2020-05-13-hochverf%C3%BCgbare-dateien-mit-glusterfs.html</id>
    <content type="html"><![CDATA[<p>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.</p>

<p>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?</p>

<p>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 <a href="https://de.wikipedia.org/wiki/DRBD">DRBD</a>.</p>

<p>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.</p>

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

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

<h2 id="einsatzzweckevonha-dateienim_aktiv_-_aktiv_-modus">Einsatzzwecke von HA-Dateien im <em>aktiv</em>-<em>aktiv</em>-Modus</h2>

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

<ul>
<li><p>Live-Migration von VMs</p></li>
<li><p>schnelle Verfügbarkeit bei Ausfall</p></li>
<li><p>höhere Performance durch Lastverteilung</p></li>
</ul>

<p>Bei einer Live-Migration zum Beispiel mit <em>QEMU</em> 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.</p>

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

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

<h2 id="problemebei_aktiv_-_aktiv_">Probleme bei <em>aktiv</em>-<em>aktiv</em></h2>

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

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

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

<p>Das ist ein Problem, jeder der beiden <em>Nodes</em> 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</p>

<h2 id="derschiedsrichter">Der Schiedsrichter</h2>

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

<p>Sieht ein <em>Node</em> die zwei anderen <em>Nodes</em> 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.</p>

<p>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.</p>

<p>Hier hat <em>GlusterFS</em> eine elegante Lösung gefunden. Es gibt einen <em>Node</em>
der nur Schiedsrichter (<em>arbiter</em>) 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.</p>

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

<h1 id="fazit">Fazit</h1>

<p>Mit <em>GlusterFS</em> 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.</p>

<p>Aber eine der schönsten Anwendungen sind die hochverfügbaren Dateien
in Verbindung mit einem <em>arbiter</em>. 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.</p>

<p>Es gibt auch andere Lösungen wie
<a href="https://de.wikipedia.org/wiki/Ceph">Ceph</a> oder
<a href="https://de.wikipedia.org/wiki/BeeGFS">BeeGFS</a>, aber meines Wissens
haben diese alle nicht diese <em>arbiter</em> Funktion.</p>
]]></content>
  </entry>

  <entry>
    <title type="html"><![CDATA[Passwortmanagement mit KeePassXC]]></title>
    <link href="http://www.lug-erding.de/blog/2020-05-12-passwortmanagement-mit-keepassxc.html"/>
    <published>2020-05-12T12:14:55+02:00</published>
    <updated>2020-05-12T13:58:46+02:00</updated>
    <id>http://www.lug-erding.de/blog/2020-05-12-passwortmanagement-mit-keepassxc.html</id>
    <content type="html"><![CDATA[<p>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.</p>

<h2 id="einelsung:keepassxc">Eine Lösung: KeePassXC</h2>

<p>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: <a href="https://keepassxc.org/">KeePassXC</a></p>

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

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

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

<p>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.</p>

<p>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. </p>

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

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

<p><strong>Wichtig</strong>: KeePassXC muss dazu auf dem System laufen und die Datenbank
muss auch per Passphrase entsperrt sein.</p>

<p>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.</p>

<h2 id="kommandozeile">Kommandozeile</h2>

<p>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.</p>

<p>Für diese Fälle, gibt es das Kommandozeilentool <code>keepassxc-cli</code>.
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.</p>

<h2 id="problemmultiuser">Problem Multiuser</h2>

<p>Das ist leider ein offenes Problem, es gibt <strong>nur</strong> 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.</p>

<h2 id="installation">Installation</h2>

<p>Die Installation ist unter Debian sehr einfach:</p>

<p><code>
apt install keepassxc
</code></p>

<p>Nach dem Starten hat man die selbterklärenden Optionen</p>

<ul>
<li>Neue Datenbank erstellen</li>
<li>Existierende Datenbank öffnen</li>
<li>Aus KeePass 1 importieren</li>
<li>Aus CSV importieren</li>
</ul>

<p>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.</p>

<p>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.</p>

<p>Danach ist die Datenbank geöffnet und man kann Einträge erstellen.</p>

<h3 id="browserintegration">Browserintegration</h3>

<p>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.</p>

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

<p>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 <code>Verbinden</code> geklickt werden. Anschließend muss noch ein
eindeutiger Name für den Zugriff vergeben werden und das war es schon.</p>

<h3 id="weitereeinstellungen">Weitere Einstellungen</h3>

<p>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.</p>

<p>Der Punkt <em>Datenbank sperren nach einer Inaktivität von</em> 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.</p>

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

<h2 id="fazit">Fazit</h2>

<p>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. </p>
]]></content>
  </entry>

  <entry>
    <title type="html"><![CDATA[Good bye Pro-Linux!]]></title>
    <link href="http://www.lug-erding.de/blog/2020-05-04-good-bye-pro-linux.html"/>
    <published>2020-05-04T20:40:36+02:00</published>
    <updated>2020-05-04T20:45:33+02:00</updated>
    <id>http://www.lug-erding.de/blog/2020-05-04-good-bye-pro-linux.html</id>
    <content type="html"><![CDATA[<p>Das war dann heute leider eine für mich traurige Nachricht,
<a href="http://www.pro-linux.de/">Pro-Linux</a> hört auf! </p>

<p>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:</p>

<p><a href="https://www.pro-linux.de/artikel/2/1996/es-war-uns-eine-ehre.html">Es war uns eine Ehre</a></p>

<p>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.</p>

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

<h2 id="schwierigezeiten">Schwierige Zeiten</h2>

<p>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.</p>

<p>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.</p>

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

<p>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 <em>irgendwie</em> miteinander verwoben
sind. Da verliert man schnell den Überblick, da ist des gut, wenn es in
einem Docker-Image versteckt ist?</p>

<p>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…</p>

<h2 id="fazit">Fazit</h2>

<p>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
<em>goodie</em> geflossen sein mag. So bleibt mir nur zu schreiben:</p>

<p><center> <strong>Macht es gut und Danke für die schöne Zeit!</strong> </cite></p>
]]></content>
  </entry>

  <entry>
    <title type="html"><![CDATA[To swap or not to swap?]]></title>
    <link href="http://www.lug-erding.de/blog/2020-05-03-to-swap-or-not-to-swap.html"/>
    <published>2020-05-03T12:42:04+02:00</published>
    <updated>2020-05-03T12:45:37+02:00</updated>
    <id>http://www.lug-erding.de/blog/2020-05-03-to-swap-or-not-to-swap.html</id>
    <content type="html"><![CDATA[<p>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…</p>

<h2 id="allgemeineszuswap">Allgemeines zu Swap</h2>

<p>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.</p>

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

<p>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 <strong>kswapd</strong>. Dieser lagert wenig oder gar nicht genutzte,
insbesondere schon seit langem nicht mehr genutzte Seite aus, sollte
der freie Speicher knapp werden.</p>

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

<h2 id="ichhabegenugram">Ich habe genug RAM</h2>

<p>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.</p>

<p>Und damit ist das Thema doch schon erledigt, oder?</p>

<h2 id="derschwierigeteil">Der schwierige Teil</h2>

<p>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 <em>suspend-to-disk</em> nutzen will: Die
Auslagerung von allem um nach einem Neustart an der Stelle
weiterarbeiten zu können wo man aufgehört hat.</p>

<p>Gleichzeitig wir dann <code>vm.swappiness=0</code> gesetzt, um das Paging zu
verhindern.</p>

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

<h3 id="wasistimram">Was ist im RAM?</h3>

<p>Man sollte einmal einen Blick darauf werfen, wozu der Hauptspeicher
genutzt wird:</p>

<ul>
<li>Programmcode</li>
<li>Daten, statische und dynamische</li>
<li>Datenpuffer</li>
<li>Datencache</li>
</ul>

<p>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.</p>

<p>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.</p>

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

<p>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.</p>

<p>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? </p>

<p>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.</p>

<h3 id="abwgungsfrage">Abwägungsfrage</h3>

<p>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?</p>

<p>Das ist nun der Punkt, wo <code>vm.swappiness</code> 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?</p>

<p>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 <code>vm.swappiness</code> nicht auf Null gesetzt werden sollte
und man einen Swapbereich hat.</p>

<h2 id="eswirdnochkomplizierter">Es wird noch komplizierter</h2>

<p>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…</p>

<p>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? </p>

<h3 id="dasprogrammdilemma">Das Programmdilemma</h3>

<p>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.</p>

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

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

<p>Das klingt doch gut.</p>

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

<p>Die Antwort ist nicht ganz so einfach.</p>

<h3 id="overcommitmemory">Overcommit Memory</h3>

<p>Bei Linux wurde aus diesem Grund das <code>vm.overcommit_memory</code> 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.</p>

<p>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.</p>

<p>Aber: Was ist, wenn die Programme den Speicher doch benötigen?</p>

<p>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.</p>

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

<p>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.</p>

<p>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!</p>

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

<h3 id="rssundvsz">RSS und VSZ</h3>

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

<p>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: <em>shared memory</em> und <em>shared libraries</em> Dise
Speicherteile sind in mehreren Programmen identisch vorhanden und werden
nur einmal im Speicher gehalten, jedoch bei jedem Prozess als ihm
gehörig aufgelistet.</p>

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

<h3 id="outofmemory">Out of Memory</h3>

<p>Was passiert nun, wenn wir kein <em>overcommit</em> 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:
<strong>OOM-Killer</strong>. 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.</p>

<h2 id="brauchtmanswapspeicher">Braucht man Swapspeicher?</h2>

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

<p>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. </p>

<p>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:</p>

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

<p>Das System arbeitet dabei tadellos, es sind keine Beeinträchtigungen zu
bemerken.</p>

<h3 id="wasistwennaktiveseitenausgelagertwerden">Was ist wenn aktive Seiten ausgelagert werden</h3>

<p>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.</p>

<h3 id="hilftdaeinschnellerswapspeicher">Hilft da ein schneller Swapspeicher</h3>

<p>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.</p>

<p>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.</p>

<p>Die hohe Geschwindigkeit wird gewöhnlich über mehrere parallele
Datenströme erreicht, beim <em>pagen</em> 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.</p>

<h2 id="fazit">Fazit</h2>

<p>Ich denke, jeder der einene Server betreibt, ist gut darin beraten, auch
einen Swapbereich anzulegen und das <em>overcommit</em> 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 <em>no memory available</em> ab.</p>

<p>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.</p>

<p>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.</p>
]]></content>
  </entry>

  <entry>
    <title type="html"><![CDATA[Mein erster Blogversuch mit und über <em>plerd</em>]]></title>
    <link href="http://www.lug-erding.de/blog/2020-05-02-my-first-blog-entry.html"/>
    <published>2020-05-02T11:34:02+02:00</published>
    <updated>2020-05-02T14:00:05+02:00</updated>
    <id>http://www.lug-erding.de/blog/2020-05-02-my-first-blog-entry.html</id>
    <content type="html"><![CDATA[<p>Das ist ein Blogbeitrag via <a href="https://jmac.org/plerd/">plerd</a>,
ein einfacher, minimaler, offsite Bloggenerator basierend auf
<a href="http://daringfireball.net/projects/markdown/">Markdown</a> und 
<a href="http://fletcher.github.io/MultiMarkdown-5/MMD_Users_Guide.html">MultiMarkdown</a>.</p>

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

<p>Es ist sogar leicht möglich Bilder einzubinden:</p>

<p>So liefert</p>

<pre><code>![Ein bild aus der Pfalz](P1040953.JPG "Die Weinstraße in der Pfalz")
</code></pre>

<p>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…)</p>

<p><img src="P1040953.JPG" alt="Ein bild aus der Pfalz" title="Die Weinstraße in der Pfalz" id="einbildausderpfalz" /></p>

<p>Auflistungen sind auch kein Problem</p>

<ul>
<li><p>die gibt es leicht unnummeriert</p></li>
<li><p>mit einem Punkt beginnend</p></li>
</ul>

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

<pre><code>2. oder nummeriert?

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

4. die Nummerierung erfolgt fortlaufend
</code></pre>

<p>diese Ausgabe:</p>

<ol>
<li><p>oder nummeriert?</p></li>
<li><p>er passt die Zahlen an…</p>

<ul>
<li>und weiter geht es?</li>
</ul></li>
<li><p>die Nummerierung erfolgt fortlaufend</p></li>
</ol>

<p>Blockquotes gehen auch, ebenso verschiedene Headergrößen, so 
liefert:</p>

<pre><code>&gt; Header 1
&gt; ========
&gt; Header 2
&gt; --------
&gt; ###Header 3###
</code></pre>

<p>das hier: </p>

<blockquote>
  <h1 id="header1">Header 1</h1>
  
  <h2 id="header2">Header 2</h2>
  
  <h3 id="header3">Header 3</h3>
</blockquote>

<p>Betonungen auch: <em>star</em> <strong>double star</strong> <em>underscore</em> <strong>double
underscore</strong></p>

<p>Referenzen gehen auch:</p>

<pre><code>References: [LUG-Erding][1]

[1]: https://www.lug-erding.de/
</code></pre>

<p>Das liefert:</p>

<p>References: <a href="https://www.lug-erding.de/">LUG-Erding</a></p>

<p>Code ist auch einfach per backticks: <code>example</code></p>

<p>Besser geht es mit Tabs oder 4 Leezeichen:</p>

<pre><code>#!/bin/sh
echo $0
   PROC=${0##*/*/}
echo $PROC
</code></pre>

<p>Mit Multimarkdown gehen auch Tabellen:</p>

<p>So liefert</p>

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

<p>das hier:</p>

<table>
<caption>Eine Tabelle</caption>
<col />
<col align="center" />
<col align="right" />
<thead>
<tr>
	<th> </th>
	<th colspan="2">grouping</th>
</tr>
<tr>
	<th>First</th>
	<th>Second</th>
	<th>Third</th>
</tr>
</thead>
<tbody>
<tr>
	<td>1. Wert</td>
	<td align="center">3.0</td>
	<td align="right">4.1</td>
</tr>
<tr>
	<td>2. Wert</td>
	<td align="center">33.0</td>
	<td align="right">41</td>
</tr>
<tr>
	<td>3. Wert</td>
	<td colspan="2" align="center">doppelt</td>
</tr>
</tbody>
</table>

<p><br /></p>

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

<p>Es kann aber auch HTML direkt verwendet werden, wenn auch umgeben von
Leerzeilen:</p>

<pre><code>&lt;br /&gt;
</code></pre>

<p>Das liefert einen <em>break</em> </p>

<p>Das ist alles wunderbar einfach und begrenzt flexibel genug um nutzbar
zu sein. Man kann sogar die Templates anpassen…</p>
]]></content>
  </entry>


</feed>
