6. Speicherverwaltung
HAProxy verwendet eine einfache und schnelle Speicherverwaltung mit Pools. Da nur wenige verschiedene Objekttypen benötigt werden, ist es wesentlich effizienter, neue Objekte aus einem Pool mit Objekten passender Größe zu entnehmen, als für jede Größe malloc() aufzurufen. Die Pools sind als Stapel nach dem LIFO-Prinzip organisiert. Neu zugeteilte Objekte stammen daher aus den zuletzt zurückgegebenen Objekten, die noch in den CPU-Caches liegen. Pools ähnlicher Größe werden zusammengelegt, um die Speicherfragmentierung zu begrenzen.
Da die Leistung im Vordergrund steht, wird standardmäßig jedes zurückgegebene Objekt wieder in seinen ursprünglichen Pool gelegt. Der zugeteilte Speicher wird nie freigegeben, weil eine baldige Wiederverwendung erwartet wird.
Über die CLI lässt sich die Speichernutzung der Pools mit dem Befehl “show pools” prüfen:
Der Poolname dient nur als Hinweis: Er entspricht dem ersten Objekttyp, der diesen Pool verwendet. Die Größe in Klammern bezeichnet die Größe der Objekte im Pool. Objektgrößen werden immer auf das nächste Vielfache von 16 Bytes aufgerundet. Die Ausgabe zeigt die Anzahl der aktuell zugeteilten Objekte und die entsprechende Bytezahl, sodass sich der Pool mit dem höchsten Speicherverbrauch leicht ermitteln lässt. Das Feld “used” nennt zusätzlich die Anzahl der gerade verwendeten Objekte. Die Differenz zwischen “allocated” und “used” entspricht den zurückgegebenen Objekten, die sofort wieder verfügbar sind. Die Adresse am Zeilenende ist die Adresse des Pools. Die anschließende Zahl ist sein Index, sofern vorhanden; wurde kein Index zugewiesen, wird -1 ausgegeben.
Mit der Befehlszeilenoption “-m”, gefolgt von einer Anzahl Megabytes, lässt sich die Speicherzuteilung pro Prozess begrenzen. Die Grenze erfasst den gesamten adressierbaren Speicher des Prozesses, einschließlich des von Bibliotheken verwendeten Speichers und des Stacks. Sie stellt einen zuverlässigen Grenzwert für Systeme mit begrenzten Ressourcen dar. Die Wirkung entspricht “ulimit -v” auf Systemen, die dies unterstützen, beziehungsweise “ulimit -d” auf anderen Systemen.
Schlägt eine Speicherzuteilung fehl, weil der Grenzwert erreicht ist oder das System nicht genügend Speicher hat, gibt haproxy zunächst alle verfügbaren Objekte aus sämtlichen Pools frei und versucht anschließend erneut, Speicher zuzuteilen. Diese Freigabe ungenutzten Speichers lässt sich auch durch das Signal SIGQUIT an den haproxy-Prozess auslösen.
Beim Neuladen gibt auch der Prozess, der in den Zustand des geordneten Herunterfahrens versetzt wurde, nach jeder Freigabe einer Verbindung automatisch Pool-Speicher frei. So wird möglichst viel Speicher für den neuen Prozess verfügbar.