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 をチューニングすることで無駄を小さくすることができるのです.

  • -p は TCPポート(memcachedのdefaultは11211)
  • -vv は -v(verbose) を更に verbose にするオプションです.
-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 間の差が大きく, 相当量のメモリが無駄に消費されてしまうことが予想されます.

 

参考