さて、皆さん、長らく放置してたredisのクラスタリングについて少し見ていきたいと思います。
ここでいうクラスタリングはレプリケーションをさします。シャーディングは少し難しい話に
なるのでまたの機会に先送りにしましょう。
1 構築方法
まずやってみるのか一番なので構築方法を書きます。
redisのプロセスを二つ立ち上げましょう。今日もリソースの問題で、全てローカルで作業しますが、その気になればネットワーク越しに作業することも容易のはず。(host portをそれぞれの環境に合わせて設定しましょう。)
$ redis-server --port 6379
これでまず、redis-serverが起動しました。待ち受けのポーとは6379番です。ちなみにredisはデフォルトで6379に待機するのでこのオプションは無くてかまいませんが、今回スレーブも同時にローカルに立てるので明示的に書きました。
次に別のshellを開いて
$ redis-server --port 6380
これでもう一つredisのプロセスが立ち上がりました。試しに更に別のshellで ps aux | grep redis
とかやるとプロセスが二ついます。
次に、redis-cliでスレーブにしたい方にアクセスして見ましょう。
$ redis-cli -p 6380
redis 127.0.0.1:6380>
こんなプロンプトが出ます。次に、これをスレーブにするためにコマンドを一つ打ちます。
redis 127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
redis 127.0.0.1:6380>
これだけで終了です。このredis6380はredis6379のスレーブになりました。
非常に簡単です。はい。
でも毎回この作業をするのは面倒なので、設定ファイルに書いた方が良さそうです。
そのときに、前回チューニングで説明したredis.confの
slaveof host port
とか書かれている項目を見てください。これはredisを立ち上げるとき、対象のホストとポートを指定して、そのスレーブとして参加させるという意味になります。
複数のホストならこちらの方がいいでしょう。
2 レプリケーションの仕組みと機構
スレーブがレプリケーションに参加したときにまず何が起きるかを見ていきましょう。
① スレーブがレプリケーションに参加すると SYNCコマンドを実行してまずマスターと同期する
② マスターにBGSAVEが走ってスナップショットを作成し、スレーブは手元の古いスナップショットがあればそれを消去する。
③ マスターはさっき作ったスナップショットをスレーブに送りつける。さらに、マスターはこの間に書き込みがあった場合、それを覚えている。 スレーブは送られてきたスナップショットをパースしてスナップショットを同期する。
④ マスターは書き込みがあったこと分をスレーブに送りつける。スレーブはスナップショット以降の書き込みをマスターから受け取り、単純にそのコマンドを実行する。
これで同期完了。
さらに、レプリケーションはさらに連鎖できる。つまり、マスター スレーブ スレーブのスレーブ
というふうに、マスターが一つであれば、スレーブはいかなる形でもレプリケーションに参加できる。
さて、お待ちかねのQ & A
Q. え?マスター一つしかだめなの?
A. はい。スプリットブレインしたらまずいのでマスターは一般的なMySQLのマスタースレーブでよくある感じに一つだけです。さらに、書き込みもスレーブにしてはいけません。書き込みはマスターへ。読み込みはスレーブからが常套手段です。しかし、そもそも、スレーブに書き込みしようとするとエラーが帰ってくるので致命的な不整合にはなりませんが。。。
Q. スレーブのスレーブにする意味あるの?全部マスターのスレーブにおけばいいじゃん。
A. それはそうなんですが、実はスレーブの数がたくさんあると不都合が生じます。
それはI/Oです。例えば、マスター一つに対してスレーブが100個あったとすると、その100個に対してスナップショットを同期します。しかも同時に。すると、ネットワークの大域があっという間にパンクしてしまいます。パンクするとせっかく同期したのにマスターからスレーブが切断され、また同期とらなきゃいけません。
このため、例えば100個のスレーブに同期させたい場合は 10 × 10とまず分解します。マスター直下にスレーブが10個。スレーブのスレーブがそれぞれ10個。こうする事で、一気にかかる同期がさっきの1/10になって、マスターとその直下のスレーブのI/Oは軽減されます。
Q. フェイルオーバー機能とか無いの?
A. ありますが、デフォルトではないです。 Redis-Sentinelというのがあって、このツールを使うことでフェイルオーバーが可能です。
http://redis.io/topics/sentinel
機構としては、マスターとスレーブの振る舞いを監視しており、マスターとスレーブのPINGとマスターに対するPUB/SUBを組み合わせ、このsentinelプロセスがすべき情報を集める。
マスターが死ぬと、このsentinelがスレーブから一つだけマスターを選び、フェイルオーバーする。
そう。これはMongoDBに組み込まれているアービターのやってる事を引き受けるツールなのです。
次回、ロックとトランザクションについて見ていきましょう。