先日開催された memcached Night in Tokyo #1 というのに参加してきた。
http://groups.google.com/group/memcached-ja/web/memcached-night-in-tokyo-1
夕方6時開催という昨今の勉強会としては早めの開始時刻なので、あたふたと会社を出た。場所は原宿である。おされな場所である。浮足立つ。ということはどうでも良くて会場であるmixiに初めていったのだが綺麗なオフィスであった。
memcachedというのは、データベースに対する分散メモリキャッシュ技術みたいなもので昨今のWebではよく利用されている。国内ではmixiでの事例がよく知られている。
http://ja.wikipedia.org/wiki/Memcached
この話を初めて聞いたとき、うーん随分乱暴な話だな、RDBMSでやるべき仕事だろ、そーゆーことはと思った。由緒正しいRDBMSではこーゆーのはいかんだろう的なことを思った。しかし発想の転換というかちょっとしたハックというか、実際memcachedのソースコードは6千行位のきわめてシンプルな実装になっていて、MySQLとかスケールしねーよなあとか思っていたハッカーが自分の問題を素早く解決するために作ちゃったという感じなんだろうな、などとも思う。作ってみたら思いのほかいい感じで使いやすくて、どんどん適用事例も生まれ、ソースコードもオープンなので、米国あたりのWeb2.0系企業でがしがし使われるようになったと。
昨今OSやらRDBMSやらアプリケーションサーバやらWebサーバやらありとあらゆるものがオープンソースなので、どこで問題を最適化してもよくてRDBMSの上にちょっとしたキャッシュをおいて擬似的に高速化をはかってみたというのがmemcachedなのだろうなと思う。
mixiでは135台のmemcachedサーバを利用していて(この数もすごいな、国内最大級かな)、メモリを3GBほどわりあてているらしい。マシンはPentium 4との事なので発熱とかもすごそうな気がする。
KLABの安井さんのお話はmemcachedのreplicationだった。memcachedはシステムが死ぬとデータが消失するので、リプリケートをして永続性を持たせたいなあというお話である。永続性とかフェールオーバーとか信頼性とか、そーゆー事を言いだすと、話がどんどん複雑になるのでmemcachedとは相性が悪いのではないだろうかと思うのだけど、どうなんだろう。この手の話も昔からあって、本当の信頼性を求めるなら完全二重化とか、そーゆー話になるのだけど、コストと拡張性のバランスも必要で、さらにはスケーラビリティをどうするかという問題もあって難しい。また非同期の更新だとどうしても原子性をどう担保するかという問題もある。いっそのこと楽観的にやっちゃて、矛盾が発生したらリトライという感じでもいいのかもしれない。
すずききよたか(kiyotaka)さんのお話はmemcachedの利用をいろいろな角度からしていた。まあ、消える可能性のある汎用DBというのは言いえて妙である。Solarisで運用しているので、Solarisのお友達を募集していた。困っている事を自分から晒すというのは勉強会メソッドとしては黄金のパターンかと思う。そして同志と出あう。memcachedを使っているだけではなくSolarisで使っているという同志の結束は固そうに見えた。
mixiの長野(kazeburo)さんは大規模事例で、特にがりがりチューニングをしているという感じではなかった。
はてなの田中(stanaka)さん、30台のcore2 quad メモリ8GBで運用している。それぞれにはXenでmemcachedサーバとアプリケーションサーバを起動しているらしい。こちらも特にチューニングしているという感じではなかった。
mixiの前坂(tmaesaka)さんはmemcached Binary Protocolの解説である。こーゆープロトコルの設計の話は好きだ。速度命だし。テキストのプロトコルだとパースデコードのコストがかかるのであらかじめ定義したバイナリのプロトコルで高速化をはかろうというお話である。バイナリプロトコルであればインジェクションは簡単ではないのでセキュリティ向上にもつながるよ。
固定長のヘッダ(16バイト)+可変長のオマケのフィールドというデータ構造になっている。
http://code.sixapart.com/svn/memcached/branches/binary/server/doc/protocol-binary.txt
opcodeが1バイトなので要素256個の配列で命令実行ルーチンが書ける。デコードのコストは表引きだ。これがASCIIテキストだとstrcmp(command,"hogehoge")みたいなものを延々コマンドの数だけ書くはめになって、コマンドの数に比例したデコードコストがかかったりする。(まあパーフェクトハッシュ関数とか書けばいいのだがカジュアルに命令を追加したりとかはいろいろ面倒なので、結局はstrcmpで延々比較という泥仕事になる)
opcodeを固定長にするというのは王道中の王道のテクニックである。CISCに対するRISC的なアプローチと言ってもさしつかえない。
まあ、そんなことを思ったのだが、この手の古典的な高速化のテクニックというのは昔からずうっと変化していなくて、再発見、再発明が延々繰替えされているような気もする。
温故知新なのである。
でもって現在の実装についてちゃんとoprofileとかでミクロのプロファイリングを取って、チューニングをはじめたという事ではなく、なんとなく直観でぐわっとやっているらしい。まあ、それでもいいっちゃいいのだけど、ちゃんとベンチマークを定義して、oprofileなどでプロファイリングをして、ボトルネックを数字で示し、チューニング大会をするというのが正しい大人の姿である。
いろいろ設定準備とか大変だとは思うが、一度そのような環境を構築してしまえば、開発の最中、運用時等々貴重なデータを入手でき、パフォーマンスデバッグ(チューニング)のインフラになる。開発のプロセスに組込むというお作法は重要だ。なかなか実践するのは難しいが。
プロファイリングしてチューニングをする。王道中の王道だ。
まあ、こーゆーことをお酒を飲みながら、わいわいがやがや語るというのも勉強会の醍醐味でもある。
おまけ:
ソースコードはgithubで公開されているのでためしにゲットしてみた。
$ time git-clone git://github.com/tmaesaka/memcached.git
Initialized empty Git repository in /proj/memcached/.git/
remote: Counting objects: 1602, done.
remote: Compressing objects: 100% (472/472), done.
remote: Total 1602 (delta 1161), reused 1537 (delta 1108)
Receiving objects: 100% (1602/1602), 592.77 KiB | 237 KiB/s, done.
Resolving deltas: 100% (1161/1161), done.
real 0m4.901s
user 0m0.612s
sys 0m0.084s
memcached.c の dispatch_bin_command() はバイナリプロトコルのディスパッチルーチンであるが、だめじゃん。
switch(c->cmd) {
case PROTOCOL_BINARY_CMD_VERSION:
略
とかしている。ここは表引きだろう。しかもc->cmdの定義はuint8_tではない。だめじゃん。深入りしないことにした。
最近のコメント