yrmcds 1.0.0 をリリースしました

@ymmt2005 こと山本泰宇です。去る 7 月に yrmcds という memcached 互換な KVS を公開したことをご案内しました。それから 5 ヶ月経ちましたが、今回は安定版となるバージョン 1.0.0 をリリースをご案内します。

ダウンロードはこちらからどうぞ: https://github.com/cybozu/yrmcds/releases/tag/v1.0.0

0.9.0 からの変更点を短くまとめるとバグがなくなって、memcached より多分高速になっています。ちょっと長めの記事ですが、末尾にいいことが書いてありますので、是非ご一読ください。

yrmcds の特長

yrmcds は memcache のテキストプロトコルとバイナリプロトコルを、仕様書にあるものは全て実装している互換性の高い KVS です。加えて、レプリケーション機能による高可用化やオブジェクトを 1 つのクライアントがロックする機能を有しています。

レプリケーション

yrmcds はマスター/スレーブ型のレプリケーション機能を実装しています。マスターの選出は固定ではなく、仮想IP(VIP)を持つサーバーで動作するインスタンスが自動的にマスターに昇格するようになっています。そのため、マスター/スレーブの切り替えを意識する必要がありません。

VIP管理は keepalivedheartbeat/pacemaker などが利用可能です。keepalived の場合、フェイルオーバーは約 3 秒で完了します。

この機能を利用すれば、ハードウェア障害はもちろん、yrmcds のバグで万一落ちた場合もデータを失うことはありません。一台ずつ落とすことで、以下の図にあるように無停止でプログラムのバージョンアップも可能です。

yrmcds_update

サーバーサイドロック

0.9.0 で運用を開始したあと、すぐに必要になった機能がサーバーサイドロックです。当社のグループウェア Garoon は PHP のセッション機能を利用しているのですが、セッション情報の書き込みを排他処理するためにロックする必要があります。

当初は memcached や Redis で一般的なやり方である atomic add を使う方式(1, 2)で実装したのですが、試験運用中に問題が発生しました。PHPがリクエストの途中で死ぬようなことがあると、ロックが外れなくなり、ユーザー操作が長時間ブロックされてしまうのです。アドホックな対策としてロックオブジェクトを一定時間後に expire (自動消去)する方式もありますが、信頼性の観点でとても採用する気になれません

根本的な解決には、クライアントコネクションが切断されたらロックが外れるような、サーバーサイドのロック機構が不可欠です。そこで、こちらの仕様にあるようにプロトコルを拡張して、サーバーサイドでオブジェクトをロックできるようにしました。PHPのセッション管理もこの機能を利用するように実装し、その後の運用で一切問題は発生していません。

No slabs

memcached は slab という仕組みでメモリを管理しています。slab の仕組みに起因して、メモリが不足する場合に最も長く使われていないオブジェクト(Least Recently Used, LRU)を捨てる動作がうまく働かないといった問題や、slab 間でバランスが悪くなる問題があります。

yrmcds のメモリ管理ではそのような問題は発生しません。

その他 memcached との差異

こちらにまとめてあるように、軽微な違いがいくつかあります。一点紹介しておきますと、stats ops でどのコマンドが何回実行されたかの統計情報が取得できるようになっています。

$ echo 'stats ops' | socat - TCP:localhost:11211,crlf
STAT text:set 6179
STAT text:add 0
STAT text:replace 0
...
STAT binary:LaG 692592
STAT binary:LaGQ 0
STAT binary:LaGK 0
STAT binary:LaGKQ 0
STAT binary:RaU 0
STAT binary:RaUQ 6947
END

運用実績と性能

cybozu.com ではマスター 1 台、スレーブ 2 台の構成で5ヶ月間運用してきました。ちょっとした手違いで常時毎秒 7 万回ほどコマンドを捌く(本来の負荷はもっと低いはずでした)状態ですが、性能面での問題はまったく発生していません。不具合については大小ありましたが 1.0.0 までに全て改修し、既知の不具合は 0 件です。

格納オブジェクト数は 600 〜 700 万個、データ量にして 3 GiB ほどです。700 万オブジェクト、3.25 GiB の時に新しいスレーブに全オブジェクトを同期するのに 29 秒かかりましたが、これはネットワーク帯域(1 Gbps)で律速されたものです。正確には 963 Mbps と、ほぼ帯域を使いきってレプリケーションできています(37 Mbps の差分はたぶんプロトコルでつくヘッダ分)。10 Gbps 使える環境で測定してくれる人がいたら嬉しいです。

memcached と比較したベンチマークも実施し、結果はこちらにあります。ご覧の通り、この測定では yrmcds は memcached より高速という結果がでています。簡易なベンチマークなので、徹底評価してくれる人がいたら嬉しいです。

クライアント

サーバーサイドロックのためにプロトコルを拡張したので、クライアントも作成する必要がでてしまいました。バイナリプロトコルの全機能にアクセスできるクライアントライブラリが見当たらなかったので、libyrmcds という C のライブラリを開発して公開しています。

さらに PHP 拡張の php-yrmcds も用意しました。既存の PECL モジュールでトラブルなどある方は memcached クライアントとしてももちろん使えますので、是非お試しください。余談ですが、php-yrmcds を作る際に調査したモダンな PHP 拡張の書き方も公開しています。

0.9.0 からの変更まとめ

  • サーバーサイドロックの実装
  • 実行ユーザー・グループを設定ファイルで指定できるようにした
  • 最大接続数を設定ファイルで制限できるようにした
  • stats ops でコマンド実行数の統計を取れるようにした
  • チューニングして性能が向上
  • ハッシュ関数を SipHash に変更してハッシュ衝突攻撃への耐性を向上
  • 色々な不具合を修正

もっと細かい一覧はこちらで確認できます。

バグ報告を募集します!

最後になりますが、yrmcds は公開以来まだ 1 件も外部からの不具合報告をいただいていません。あまりに寂しいので、バグを報告してくれた方に Amazon ギフトコードを進呈しようと思います!

期間は 2013 年内で、1 件 1,000 円〜5,000円、累計 10 万円に達したらそこまでとします。バグ認定(won't fix や duplicate なものは無効)や金額については私の判断とさせていただきます。見つけた方は GitHub issues まで twitter ID かメールアドレスと共にお願いします。

yrmcds をご活用いただければ幸いです。