memcached の Slab Allocator について理解する
Slab Allocator とは
従来の memcached のではすべてのレコードに対して malloc と free を行うというものでした. しかしこの方法では memory の fragmentation (断片化) を発生させてしまい, OS の memory manager に負荷をかけてしまいます.
この問題を解消するために作成されたものが Slab Allocator です.
Slab Allocator は確保したメモリを最初に設定したサイズのクラスに応じた固定長memory chunkに分割することで framgmentation 問題を克服します.
Slab Allocator の弱点
端的に言えば、確保したメモリをフルフルまで使い切ることができない, ということです.
Slab Allocator はサイズクラスに応じて固定長メモリの固まりに分けているのでした. よって, 確保したメモリをすべて使い切ることはできません. 例えば100バイトのデータを128バイトのchunkにキャッシュすると, 余りの28バイトが無駄になってしまいます.
Slab Allocator の弱点を補うために
Growth Factor (-f) という因子を指定することで slab間のサイズの幅を制御することができるようになっています. 例えば 2 に設定すると, 固定メモリサイズchunkは 2 の累乗で確保されていきます. (なおGrowth Factorが開発された現在default値は 1.25 のようです.)
この Growth Factor をチューニングすることで無駄を小さくすることができるのです.
-f が 2 の時
$ memcached -p 11211 -vv -f 2 slab class 1: chunk size 96 perslab 10922 slab class 2: chunk size 192 perslab 5461 slab class 3: chunk size 384 perslab 2730 slab class 4: chunk size 768 perslab 1365 slab class 5: chunk size 1536 perslab 682 slab class 6: chunk size 3072 perslab 341 slab class 7: chunk size 6144 perslab 170 slab class 8: chunk size 12288 perslab 85 slab class 9: chunk size 24576 perslab 42 slab class 10: chunk size 49152 perslab 21 slab class 11: chunk size 98304 perslab 10 slab class 12: chunk size 196608 perslab 5 slab class 13: chunk size 393216 perslab 2 slab class 14: chunk size 1048576 perslab 1
クラスのサイズが2倍づつ大きくなっているのがわかります. f:2 だとslab間の差が比較的に大きいため, ユースケース次第で相当なメモリが無駄に消費されてしまいます.
次に -f 1.25 を設定してみます.
$ memcached -p 11211 -vv -f 1.25 slab class 1: chunk size 96 perslab 10922 slab class 2: chunk size 120 perslab 8738 slab class 3: chunk size 152 perslab 6898 slab class 4: chunk size 192 perslab 5461 slab class 5: chunk size 240 perslab 4369 slab class 6: chunk size 304 perslab 3449 slab class 7: chunk size 384 perslab 2730 slab class 8: chunk size 480 perslab 2184 slab class 9: chunk size 600 perslab 1747 slab class 10: chunk size 752 perslab 1394 slab class 11: chunk size 944 perslab 1110 slab class 12: chunk size 1184 perslab 885 slab class 13: chunk size 1480 perslab 708 slab class 14: chunk size 1856 perslab 564 slab class 15: chunk size 2320 perslab 451 slab class 16: chunk size 2904 perslab 361 slab class 17: chunk size 3632 perslab 288 slab class 18: chunk size 4544 perslab 230 slab class 19: chunk size 5680 perslab 184 slab class 20: chunk size 7104 perslab 147 slab class 21: chunk size 8880 perslab 118 slab class 22: chunk size 11104 perslab 94 slab class 23: chunk size 13880 perslab 75 slab class 24: chunk size 17352 perslab 60 slab class 25: chunk size 21696 perslab 48 slab class 26: chunk size 27120 perslab 38 slab class 27: chunk size 33904 perslab 30 slab class 28: chunk size 42384 perslab 24 slab class 29: chunk size 52984 perslab 19 slab class 30: chunk size 66232 perslab 15 slab class 31: chunk size 82792 perslab 12 slab class 32: chunk size 103496 perslab 10 slab class 33: chunk size 129376 perslab 8 slab class 34: chunk size 161720 perslab 6 slab class 35: chunk size 202152 perslab 5 slab class 36: chunk size 252696 perslab 4 slab class 37: chunk size 315872 perslab 3 slab class 38: chunk size 394840 perslab 2 slab class 39: chunk size 493552 perslab 2 slab class 40: chunk size 616944 perslab 1 slab class 41: chunk size 771184 perslab 1 slab class 42: chunk size 1048576 perslab 1
~100byte単位のレコードをキャシュするのに適していることがわかります.
次にあまり用いないようですが, f:8 を設定してみます.
$ memcached -p 11211 -vv -f 8 slab class 1: chunk size 96 perslab 10922 slab class 2: chunk size 768 perslab 1365 slab class 3: chunk size 6144 perslab 170 slab class 4: chunk size 49152 perslab 21 slab class 5: chunk size 1048576 perslab 1
この設定だと slab 間の差が大きく, 相当量のメモリが無駄に消費されてしまうことが予想されます.