repcached 1.0リリースの補足とちょっとしたHowTo
前のエントリでrepcached 1.0のリリースをお知らせしました。
開発の動機はプロジェクトページにちょっと書いたのですが、たいせつなことをひとつ書き忘れていました。
repcachedを開発しようと思い立ったのは、ひとことでいうと「キャッシュサーバといっても止まらないようにしたい」、別ないい方をすると「サーバ管理者だって夜はぐっすり眠りたい」というものでした。
そしてふたりのエンジニアが自ら社内向けに企画・提案してrepcachedの設計・開発にとりかかり、プロダクション環境で使えるようなレベルのものができあがりました。
これがrepcachedを開発した動機です。
さて、昨日はrepcachedをみなさんに向けて公開しました。
いうまでもなく、repcachedを社内に閉じて外部には公開せずに使い続けるという選択肢もありました。
でもわたしたちはそうしませんでした。
わたしたちはいろいろなオープンソースのプロダクトのお世話になって、今日もおいしいごはんが食べられる生活を過ごせています。とても幸せなことだと思っています。
でも、常々こうも思っていました。
「give and takeでいえば、takeしてばかりではないか?」
「どうしたらgiveすることができるだろうか?」
そして、
「いつかはみなに使ってもらえるようなオープンソースソフトウエアを作りたい」
という想いをもっていました。
これが前のエントリで書き忘れたこと、そしてこのエントリで(ちょっとはずかしいですがw)みなさんに伝えたかったこと ―repcachedを公開した動機― です。
ちなみにrepcached以外にも、いくつか公開しているソフトウエアがあるのですが、これらもすべて同じ想いで公開しているものですのでお使いいただければと思います!
だいぶ前置きが長くなってしまいましたが、後半は、各所でいただいた意見を反映しながら、使い方についてちょっと補足したいと想います。
repcachedのビルド
現時点でのrepcachedのバージョンは1.0、対応するmemcachedのバージョンは1.2.2です。以降の説明では$MCDVER
、$RCDVER
というシェル変数を使っていますが、これらには次のようにバージョン番号を格納している
$ MCDVER=1.2.2 $ RCDVER=1.0
とします。もし、将来、バージョンが変わっても、新しいバージョンを代入すれば以降の手順はそのまま使えると思います。
repcachedはmemcachedに対するパッチという形式で配布していますので、memcachedのアーカイブを入手・展開して、repcachedパッチをダウンロードして適用してください。
$ wget http://www.danga.com/memcached/dist/memcached-${MCDVER}.tar.gz $ tar zxf memcached-${MCDVER}.tar.gz $ cd memcached-${MCDVER} $ wget http://downloads.sourceforge.net/repcached/repcached-${RCDVER}-${MCDVER}.patch.gz $ gzip -cd repcached-${RCDVER}-${MCDVER}.patch.gz | patch -p1
また、memcachedにrepcachedパッチ適用した状態のアーカイブも配布していますので、こちらを利用になっても構いません。
$ wget http://downloads.sourceforge.net/repcached/memcached-${MCDVER}-repcached-${RCDVER}.tar.gz $ tar zxf memcached-${MCDVER}-repcached-${RCDVER}.tar.gz $ cd memcached-${MCDVER}-repcached-${RCDVER}
ソースコードの準備ができたら、つづいてコンパイルです。
レプリケーション機能を有効にするには、configureで--enable-replication
を指定します。ただし、--enable-replication
と、memcachedでスレッドサポートするための--enable-threads
は併用できない点に注意してください。
スレッドサポートと併用できない理由(ちょっと内部実装の話になりますが)はこうです。repcachedの場合、レプリケーション待ちのデータを内部で保持するためにキューを作って使っているのですが、スレッドサポートの場合は複数のスレッドが同時にこのひとつのキューに対して読み書きをするため、排他制御をかける必要があります。実は当初はスレッドサポートで排他制御をするように実装していたのですが、性能評価をした結果、思った以上に性能が低下したので、思いきってスレッドサポートをやめて、一切、排他制御が必要のない実装にすることにした、という経緯があります。
さて、そのほかのconfigureのオプションはオリジナルのmemcachedと同じです。 configureが成功したら、続いてmake、make installを行います。
$ ./configure --enable-replication $ make # make install
起動
インストールができたら起動してみましょう。
repcachedでは2つのオプションが追加されています。
- -x <ip_addr>
- マスタのホスト名かIPアドレスを指定します
- -X <port>
- レプリケーション用のポートを指定します。デフォルトは11212です。 理由がなければオプション無指定でデフォルト値でいいと思います。
-xオプションでマスタを指定します。
このオプションが指定された場合は、まず、指定されたマスタ(の-Xオプションで指定されたポート。デフォルトで11212)に接続しにいきます。
もし、接続できた場合は、自分はバックアップ機として動作します。
一方、接続できなかった(=マスタが存在しなかった)場合は、自分はマスタ機として動作をするようになっています。
では具体的に、2つのホスト、fooとbarでレプリケーションしてみましょう。
まずは、fooでmemcachedを起動します。
(repcachedパッチを適用しても、memcachedプログラムのファイル名は「memcached」のままです)
マスタとしてbarを指定(-x bar
)していますが、この時点ではまだホストbarではmemcachedが起動していない(=マスタが存在しない)ので、fooはマスタ機として動作します。
foo$ memcached -v -x bar replication: master start
続いてホストbarで、マスタとしてfooを指定(-x foo
)してmemcachedを起動します。
さきほど、fooではマスタとなるmemcachedを起動していますので、barのmemcachedはマスタの存在を検知してバックアップ機として振る舞います。
bar$ memcached -v -x foo replication: backup start (master=10.10.2.26:11212) replication: connect
うまくレプリケーション接続が確立できた場合、起動オプションに-vをつけていればマスタ側に「replication: accept」と出力されるはずです。
レプリケーションの確認
この状態で、正しくデータのレプリケーションが行われているはずです。試しに、マスタ(foo)に適当な値をset(例えば、key:test1, data:one)してみて、同じ値がマスタ機(foo)とバックアップ機(bar)の両方から得られるか確認してみてください。
repcachedは、シングルマスタ/シングルバックアップという構成でレプリケーションします。
現時点では、マルチマスタや、シングルマスタ/マルチバックアップという構成では動作しませんので注意してください。
フェイルオーバとフェイルバック
レプリケーションの動作が確認できたら、repcachedのもうひとつの目玉機能であるフェイルオーバを試してみましょう。
マスタ(foo)、バックアップ(bar)でレプリケーションができている状態で、おもむろにマスタ(foo)のmemcachedを終了してみます。
するとバックアップだったbarは、マスタの不在を検知して、自らがマスタとして振る舞うようになります。barのターミナルには次のように表示されているはずです。
replication: close replication: master start
つまり、バックアップ機がマスタに昇格してフェイルオーバが成功したわけです。
注目して欲しいのは、昇格する際にbarに対して外部から管理コマンドを送ったり通知シグナルを送ったりする必要はなく、自動的に昇格したという点です。
さて、いまの状態を確認しておくと、マスタ(bar)だけでバックアップ機はなしという状態です。
あとの実験のため、ここで適当な値(例えば、key:test2, data:two)をマスタに対してsetしておきましょう。
ところで、いつまでもマスタ1台だけの片肺飛行はまずいので、バックアップ機を復帰(フェイルバック)してみることにしましょう。
ホストfooで、次のようにしてmemcachedを起動します。
foo$ memcached -v -x bar replication: backup start (master=10.10.2.27:11212) replication: connect
ここで注目してほしいのは、いちばん最初にfooでmemcachedを起動したときと、オプションが全く同じだということです。
いちばん最初の例では指定マスタが存在しなかったので自らがマスタになりましたが、こんどは指定されたマスタ(bar)が存在するので、バックアップとして動作します。
繰り返しになりますが、repcachedでは、状況(マスタが存在するか/しないか)に応じて、適切な振る舞い(マスタになるか/バックアップになるか)を自動的に判断するように実装しています。
これで再び、マスタ/バックアップ構成に復帰できたわけですが、双方が保持するデータはどのようになっているでしょうか?
試しに、最初にレプリケーションできたときにsetした値(key:test1)と、マスタだけの片肺飛行中にsetした値(key:test2)を、バックアップからgetして値を確認してみてください。マスタと同じ値がバックアップ機からも得られるはずです。
実は、ひとつもデータを持っていない新しいバックアップ(foo)がマスタ(bar)に接続した場合、まず最初にマスタが持っているすべてのデータをバックアップにコピーするようにしています。ですので、まっさらなバックアップ機を復帰した場合でも、マスタとバックアップとで保持しているデータが食い違ってしまうといったことは起こりません。
ちなみに、手元の環境(1000Base-T)でマスタ→バックアップの全コピーにかかった時間は、20万件で2秒、100万件で10秒でした。
おちぼひろい
フェイルオーバ時のクライアントの対応
repcachedはシングルマスタ構成なので、memcachedのクライアントは接続するサーバとしてただひとつのIPアドレスを指定する必要があります。
しかし、repcachedがフェイルオーバした場合、マスタの役割を果たすサーバが変わってしまうので、サーバのIPアドレスも変わってしまいます。
これではフェイルオーバのたびにクライアントの設定を変えなくてはならず、「ラクな運用」を信条とするDSASでは受け入れられません。
この問題については、後日、別エントリでスマートな解決方法を考えてみたいと思っていますのでご期待くださいませ。
パフォーマンスについて
レプリケーションという機能を追加している以上、オリジナルのmemcachedとrepcachedはまったく同じ性能である、というのは嘘になります。
しかし、オリジナルのmemcachedがもつイベントループやIO多重化の機構にうまくとけこむようにrepcachedの処理を実装したので、性能の低下は「ないわけではないがそれほど大きい低下ではない」と考えています。
気になる方は、要求や用途に即した環境においてご自身の手で性能評価を行うのがいちばんだと思います。
が、参考までに記しておきますと、わたしたちが行ったマイクロベンチの結果はプロジェクトページの方に書いてある通りで、ベンチマークプログラムに改善の余地はあるものの、秒あたりのset数、秒あたりのget数共に高い数値ではないかと思っています。