Harald Kirsch

genug Unfug.

2014-07-14

Page Faults

Aus einem aktuellen Anlass musste ich mich sehr konkret mit der Speicherverwaltung von Linux beschäftigen und habe noch einiges dabei gelernt. Der Anlass ist eine Solr Testinstallation, in der wir die Leistung von Solr/Lucene ausloten wollen. Unser Ziel ist es, schließlich mehrere 100 Millionen Dokumente einer Firma zu indexieren.

Aktuell haben wir gerade mal 10 Millionen Dokumente indexiert. Der Index auf der Festplatte hat 100 GB. Wie geht Solr damit um?

Der wichtigste Aspekt ist wohl, dass Solr/Lucene seit einiger Zeit sogenannte memory mapped Dateien für den Index benutzt. Das Betriebssystem, in unserem Fall Linux, lässt den Prozess dabei mit einer Datei arbeiten, als sei sie ein (großes) Feld von Bytes im Speicher. Der Prozess fordert die Datei vom Betriebssystem als "memory mapped" an und erhält als Ergebnis das Bytefeld so, als sei es direkt im Speicher verfügbar. Tatsächlich aber lädt das Betriebssystem immer nur typischerweise 4k-Byte große Blöcke ins RAM, auf die der Prozess auch tatsächlich zugreift. Veränderte Blöcke werden nach Bedarf auf die Festplatte geschrieben.

Das Betriebssystem hat seine eigene Strategie, welche Blöcke es wie lange im RAM vorhält. Ohne Speichernot werden die Blöcke nicht verworfen. Aber wenn ein noch nicht geladener Block angefordert wird und das RAM voll ist, fliegt ein anderer geladener Block raus, gegegebenenfalls nachdem er auf Festplatte geschrieben wurde. Der Zugriff auf einen noch nicht im RAM befindlichen Block nennt man Seitenfehler (Englisch major page fault).

So ist es möglich, dass Solr mit dem Index von 100 GB selbst bei nur 16 GB RAM so arbeiten kann, als sei er im komplett im Speicher. "Merken" könnte der Prozess den Unterschied nur, wenn er Zugriffsgeschwindigkeiten messen würde.

Damit das auch funktioniert, ist auf Linux eine wichtige Einstellung zu überprüfen: es darf kein (zu kleines) Limit auf die virtuelle Speichergröße existieren. Mit ulimit -v hat man einen ersten Hinweis. Kommt unlimited heraus, ist man im grünen Bereich. Für einen bereits laufenden Prozess mit der PID 22334 prüft man das gesetzte Limit wie folgt:

% cat /proc/22334/limits | grep -E 'address|Soft'
Limit                     Soft Limit           Hard Limit           Units     
Max address space         unlimited            unlimited            bytes

Wichtig ist wieder das unlimited bzw. ein hinreichend großes Limit. Falls das Limit nicht ausreicht, dann quittiert Solr das mit einer Fehlermeldung, die ohne das Wissen um den virtuellen Speicher schwer zu verstehen ist.

Wenn Solr dann so richtig loslegt, sieht man das an zwei Stellen sehr gut. In der Ausgabe von top werden in der Spalte VIRT Größen angegeben, die der mit du gemessenen Indexgröße auf der Festplatte entsprechen und gegebenenfalls weit über die RAM-Größe hinaus gehen. Außerdem findet man in der Datei /proc//smaps alle Indexdateien wieder, insbesondere mit ihrer Größe (Size) und der aktuell im RAM befindlichen Teilmenge (RSS):

Size:                380 kB
Rss:                 180 kB

Schließlich kann man sich unter /proc//stat in Spalte 12 (Zählung ab 1) die Anzahl der "harten" Seitenfehler (major page faults) ansehen.

Wenn ich bei unserer Solr Testinstallation anfange, mit 12 Threads Anfragen zu schicken, so sehe ich hier jede Sekunde eine um 150 bis 300 größere Zahl. Das ist bei 100 GB virtuellem Speicher und 16 GB RAM natürlich keine Überraschung. Wir haben dann einen Anfragedurchsatz von circa 2 pro Sekunde. Was ich derzeit noch nicht einschätzen kann ist, ob dieser schlechte Durchsatz tatsächlich an den Seitefehlern liegt, oder ob es noch andere Gründe gibt. Vielleicht bekommen wir in Kürze deutlich mehr RAM, dann werden wir sehen.