読者です 読者をやめる 読者になる 読者になる

tumblr

tumblr(タンブラー)は、メディアミックスブログサービス。ブログとミニブログ、そしてソーシャルブックマークを統合したマイクロブログサービスである。アメリカのDavidville.inc(現: Tumblr, Inc.)により2007年3月1日にサービスが開始された。

キー一覧を見るためにmemcached入門

memcachedを使う場合、多くはアプリケーションの言語ごとにあるクライアントを使ってgetとかsetをすると思う。telnetで直接memcachedプロトコル使うのはキーの一覧が見たいとかデバッグ時くらいだと思う。そのデバッグ時も言語ごとのrepl使うほうが早かったりするけど。

まぁそんなわけでmemcachedtelnetから叩くことは殆どないのではないかと思う。自分が単純に経験不足なのも在るだろうけど。で、この間直接覗きたい機会があったのでどういうkeyが入ってるのか調べるためにキー一覧を見ようとしてみたのだけど見方が全くわからない。『memcached key 一覧』でググって一番最初に出てきたこのページを参考にしてstats itemsコマンドを打ってみたけど何が何だか...

> set hoge 0 0 4
> hage
STORED

> stats items
STAT items:1:number 1
STAT items:1:age 929
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0

空のmemcachedhogeというkeyをsetしてもこうなってしまう。
コマンド1つでkeyを一覧で表示させたいのだけなのに...
というかkeyが1つしか入ってないはずなのに何で色々出てくるの...
cache dumpコマンドを打てば一覧見れそうだけど、何を指定すればいいの...
色々よくわからない。

memcachedがkey-value形式で値を保存するのは知っていたので、keyを一覧するなんて簡単に出来そうだと安易に思っていたけどそうでもなさそうだ。色々調べてみると、telnetから直接keyを一覧するというのは無理そうだと分かる。というかそもそもkey-valueを見るためにmemcachedが内部でどのようにデータを保存しているかを知らなければならない。という訳で簡単にまとめてみた。

SlabAllocator

memcachedはkey-value型のストレージ。RDBと違う部分の1つに、データをメモリに保存する。RDBはデータをHDDなどの補助記憶に保存するため、速度抜きにして保存という観点で見ればそこまでメモリは必要ない。が、memcachedの場合は全てのデータをメモリに載せる。ということはデータサイズの増減に合わせて行うメモリ管理(mallocとかfree)が重要になるのだが、この管理が面倒らしくフラグメンテーション起こしたり色々面倒なことが起こっていたようだ。それを克服するためにmemcachedはSlabAllocatorという構造を取り入れた。
ざっくり言えばSlabAllocatorはメモリを最初からある程度の量確保しておき、その確保したメモリを一定サイズの塊に分割してフラグメンテーションが起こらないようにした。そしてこの構造を理解する事でtelnetからmemcachedに入っているkey-valueを取得できるようになる。
memcachedはchunkという小さなメモリ領域に値を保存する。このchunkは決まったサイズのものだ。chunkのサイズは複数あるが、同一サイズのchunkをまとめたものがSlabと呼ばれる。memcachedはまずメモリをPageという単位で分割する。このPageはデフォルトで1MB。そのPageのなかにそれぞれのSlabが入り、Slabの中にはSlab固有のchunksizeのchunkたちが入っているという構造だ。*1
データを入れる場合、memcachedはそのデータサイズに一番近いchunkにそのデータを格納する。0.5KB、1KB、2KBのSlabがあり、今0.8KBのデータを格納しようとした場合は1KBのchunkを選択する。Slabのサイズは最小で96バイトで、デフォルトでは1.25倍のサイズのSlabが用意される。前述の例の場合、1.1KBのデータは2KBのchunkに入ることになるが、その場合0.9KBが無駄になる。Slab間のサイズが大きすぎると無駄が発生してしまう。

stats itemsの意味

ともかく、slabとchunkという単位が分かった。ここでmemcachedプロトコルについてのドキュメントを見てみる。
https://github.com/memcached/memcached/blob/master/doc/protocol.txt

最初に打ったstats itemsというのは実際の所なにを表しているのか調べてみると、以下のように書いてあった。

The "stats" command with the argument of "items" returns information about
item storage per slab class. The data is returned in the format:
STAT items:: \r\n

どうやらstats itemsで見られるのはslabごとに入っているkeyの情報だったようだ。今回はhogeというkeyを1つしか入れていないため、slabclass = 1のものしかmemcached内で生成されず、そのslabclass = 1のslabに関する情報が出てきていたのだ。STAT items:1:number 1 というのはどうもslabclass1には1つのkeyしかはいっていないという情報が出ているらしい。ちなみにstats slabsでSlab自体の一覧情報が表示される。

> stats slabs 
STAT 1:chunk_size 96
STAT 1:chunks_per_page 10922
STAT 1:total_pages 1
STAT 1:total_chunks 10922
STAT 1:used_chunks 2
STAT 1:free_chunks 0
STAT 1:free_chunks_end 10920
STAT 1:mem_requested 144
STAT 1:get_hits 1
STAT 1:cmd_set 1
STAT 1:delete_hits 0
STAT 1:incr_hits 0
STAT 1:decr_hits 0
STAT 1:cas_hits 0
STAT 1:cas_badval 0
STAT active_slabs 1
STAT total_malloced 1048512
END

stats cachedump

ここでやっと本題のkey-valueはどうやって見るのか?というところに来る。見たい値はstats cachedumpコマンドを使えばいい。stats cachedumpは以下の形式で打てばいいようだ*2
stats cachedump
slab-idについてはもう分かるだろう。stats itemsまたはstats slabsで取得したidを使えばいい。stats slabsからそのchunksizeがわかるので、データサイズからslab-idの値を推測できそうだ。limitは表示する値のlimitだ。

ということで

>stats cachedump 1 1
ITEM hoge [4 b; 1390641291 s]
END

できた!

*1:slabとpageが常に1:1で割り当てられるのか、多:1なのか、多:多なのかはよく分からない...

*2:cachedumpについてのドキュメントがどこにもなくて無いんだけど、みんなどうやって見つけたの…