6. メモリ管理
HAProxyは、単純で高速なプール方式のメモリ管理を使用します。扱うオブジェクトの種類が少ないため、サイズごとにmalloc()を呼び出すより、適切なサイズのオブジェクトを持つプールから取得するほうがはるかに効率的です。プールはスタック、つまりLIFOとして構成されます。このため、新たに割り当てるオブジェクトには、解放されたばかりでCPUキャッシュにまだ残っているものを使用します。メモリの断片化を抑えるため、サイズが近いプールは統合されます。
デフォルトでは性能を重視し、解放された各オブジェクトを元のプールに戻します。すぐに再利用すると想定しているため、割り当て済みのオブジェクトのメモリは解放しません。
CLIの「show pools」コマンドで、プールのメモリ使用状況を確認できます。
プール名は目安であり、そのプールを最初に使用したオブジェクト型の名前です。括弧内のサイズは、そのプールのオブジェクトサイズです。オブジェクトサイズは常に16バイトの倍数に切り上げられます。現在割り当てられているオブジェクト数と総バイト数が表示されるため、どのプールが最も多くのメモリを使用しているかを簡単に把握できます。現在使用中のオブジェクト数は「used」フィールドに表示されます。“allocated"と"used"の差は、解放済みですぐに再利用できるオブジェクトの数です。行末のアドレスはプールのアドレスで、続く数値はプールのインデックスです。インデックスが割り当てられていなければ-1と表示されます。
コマンドラインオプション「-m」に続けてメガバイト数を指定すると、プロセスごとに割り当てるメモリ量を制限できます。プロセスがアドレス指定できる空間全体が対象となるため、一部のライブラリやスタックが使うメモリも含まれますが、リソースに制約のあるシステムでは確実な上限として利用できます。「ulimit -v」があるシステムではそれと同じように、それ以外では「ulimit -d」と同じように機能します。
メモリ上限に達した場合やシステムのメモリが不足した場合に割り当てが失敗すると、haproxyはまずすべてのプールから未使用のオブジェクトをすべて解放し、その後メモリの割り当てを再試行します。この未使用メモリの解放処理は、haproxyプロセスにSIGQUITシグナルを送ることでも実行できます。
リロード時にグレースフルシャットダウン状態に移ったプロセスは、接続を解放するたびに自動的にメモリの解放処理も行います。これにより、解放可能なメモリをすべて解放し、新しいプロセスが利用できるようにします。