まるまるこふこふ

数々の次元が崩壊し、全ての生命が塵と化すのを見てきた。私ほどの闇の心の持ち主でも、そこには何の喜びも無かった。

node + Redis でpub/subを楽しむとしてRedisがフェイルオーバーしたらどうなっねんと

メモ書き程度の能力。

Redis のインストール

qiita.com

node で Redis の Subscribe機能を使う

Redis の Pub/Sub を使って Node.js + WebSocket のスケールアウトを実現する方法 | dakatsuka's blog

Redis で master/slave 設定

qiita.com

Redis Sentinel で自動フェイルオーバー

qiita.com

Redisがフェイルオーバーすると

node から Redis のSubscribe をしている最中にフェイルオーバー起こったら、 Redis との接続切れるよな……再接続したとして、正常に購読しなおせるのかな……と 疑問に思ったので試す。

Subscribeするサンプルコード

var sys        = require('sys');
var redis      = require('redis');
var subscriber = redis.createClient(6379, 'localhost');

subscriber.subscribe('hoge');
subscriber.on("message", function(channel, message) {
    sys.puts(channel + " :" + message);
});

subscriber.on('error', function(err) {
    console.log('redis_err ' + String(err));
});

別端末からPublishすると当然 Subscribeできてる。

% redis-cli
127.0.0.1:6379> 
127.0.0.1:6379> PUBLISH hoge "Hello World!"
(integer) 1

この状態でフェイルオーバーしたと仮定して、redis-sever を再起動させてみる。

再度上記のコマンドで Publish してみると、フェイルオーバー後もnodeが Redisに再接続し、再購読しなおしてる事が確認できる。

めでたしめでたし。

なんで

node-redis モジュールが勝手に Reconnectしてくれてる。具体的に言うと 下記のようにerrorイベントさえハンドリングしとけば Redisとの接続が切れても再接続しなおしてくれる。

subscriber.on('error', function(err) {
    console.log('redis_err ' + String(err));
});

逆に言うとハンドリングしなければRedisとの接続が切れるとnode側も巻き込まれて落ちる。

その他ハマったこと

var sys        = require('sys');
var redis      = require('redis');
var subscriber = redis.createClient(6379, 'localhost');

subscriber.on("connect", function(){
    subscriber.subscribe('hoge');
    subscriber.on("message", function(channel, message) {
        sys.puts(channel + " :" + message);
    });
});
subscriber.on('error', function(err) {
    console.log('redis_err ' + String(err));
});

当初は上記のようにconnectイベントにハンドリングして購読してた。 connectイベントは最初の接続時はもちろんのこと、再接続時も発行されるので うまく購読できるように見えて、再接続時はうまいこと購読できなかった。