Redis Cluster の構築と利用(Redis 3.0.0)

みなさまこんにちは。池内です。

Redis 3.0.0 から正式な機能として盛り込まれたRedis Clusterの構築と基本的な動作について紹介します。

※ 期せずして本日 LINEさんの事例 LINEの100億超/日メッセージを支えるRedis・HBaseのスケールアウト・アップ戦略(A-5) #linedevday – Togetterまとめ が話題になっていますが、合計48TBものメモリサイズで運用しているようです。凄いですね。

Redis Cluster とは

  • 疑似的なマルチマスタ構成
  • 複数ノードでデータをシャーディングできる
  • スレーブ構成を採用すれば耐障害性の向上も可能

概ね上記のような内容です。マルチマスタを「疑似的」としているのは、実際にデータが各ノードに伝播しているわけではないからです。Redis Clusterは、あるレコードをどのノードに保存するかを把握しておき、ノード間でリダイレクトすることによって、どのノードから接続しても指定するデータにたどり着けるというアーキテクチャを採用しています。この記事では便宜上マルチマスタと表記します。

Redis Cluster マスタのみの構築

下記のノードが存在するとします。(単一のサーバーホストにポート違いで複数台Redisを起動する方法がよく紹介されますが、今回の手順では、実際にサーバーが複数台存在する環境を想定しています)

Host Private IP
redis1 192.168.10.212
redis2 192.168.10.213
redis3 192.168.10.214
redis4 192.168.10.215

通常の手順で各ホストにRedisをインストールした後、redis.conf に下記の設定を記述します。

redis.conf の設定

設定ファイルの場所や使用するPort番号は適時読み替えて下さい。

Cluster の作成

redis-3.0.0.tar.gz を解凍すると、クラスタ構築用のRubyスクリプト redis-trib.rb が入っているのでこれを利用します。

以上が正常に実行されれば、Cluster の作成は完了です。ログイン時は下記の通りオプションを付与します。

この構成では、4ノード全てがマスタになっています。マルチマスタが実現されているので、どのノードから SET しても、全ノードからGETすることができます。

実際にコマンドを実行すると、下記のように表示されることがあります。

redis1 から接続しましたが、redis2にリダイレクトされ、結果 Key: key1, Value: value1 のレコードは redis2 に保存されます。

この点の解説は多く存在するのでここまでにします。

Redis Cluster マスタ・スレーブの構築

上述の手順では、4つのノード全てがマスタの役割を持っていました。この場合、データが冗長化して保存されている訳ではありません。従ってノードがクラッシュすると、そのノードのデータがロストする可能性があります。また、各ノードの死活監視はRedis Cluster自身が行っていますが、ノードが fail と判定されると、そのままでは「 (error) CLUSTERDOWN The cluster is down」となり、読み書きが出来なくなります。

そこで、Redis Clusterの可用性をあげるためにマスタ・スレーブ構成で構築します。

同様に、 redis-trrib.rv スクリプトで create を行います。このとき、 –replicas 1 オプションを付与します。しかし、下記のエラーが発生します。

Redisクラスタはマスタが最低3ノード必要で、各マスタに1つのスレーブが対応付くため、結果的に6ノードが必要になります。そこで、サーバーを2台追加します。このとき設定ファイルは変更する必要がありません。

Cluster の作成

この結果、以下の状態になったとします。

Host Private IP Role
redis1 192.168.10.212 Master1
redis2 192.168.10.213 Master2
redis3 192.168.10.214 Master3
redis4 192.168.10.215 Slave of Master1
redis5 192.168.10.216 Slave of Master2
redis6 192.168.10.217 Slave of Master3

障害時の挙動

ノードの障害時は、以下のような挙動をとります。

  • redis6 がダウンした場合、redis6はSlaveであるため、そのままClusterの動作を続行します。その後 redis6 が復帰した場合、自動でClusterに加えられます。
  • redis3 がダウンした場合、redis3 のスレーブである redis6 がマスタに昇格します。redis3 が復帰した場合、今度は redis3 が redis 6のスレーブとしてClusterに参加します。
  • redis1 がダウンした場合、redis1 のスレーブである redis4 がマスタに昇格します。続いて redis4がダウンした場合、 (error) CLUSTERDOWN The cluster is down となり動作を続行できません。その後 redis1 または redis4が復帰した場合、マスタとしてClusterに参加します。

全体で6ノード稼働している場合、2ノードの同時停止でCluster全体が機能不全に陥る可能性があります(反対に最大で、3ノードの同時停止まで耐えられます)。AWSで構築する場合、マスタとスレーブのAZを分けるなどの設計が求められます。

なお、各マスタに紐尽くスレーブは1ノードよりも多くすることもできます。

利用ノードの固定

ノードの固定について紹介します。

Redis Clusterでは、レコードが各ノードに散らばって保存されます。しかし、SET型で集合演算を行う際に、集合演算対象のレコードが同一のノードに存在している必要があるという制約が存在します。このときに利用するのが Keys hash tags です。

どちらかのSETで、リダイレクトが発生する状況であると仮定します。その際、共通利用できるキーの文字列部分を {} で囲うことで、ハッシュとして利用できます。

この結果、{foo}-var0001 と {foo}-var0002 を同一ノードに保存するこができます。

MSET などの Multiple Keys についての注意

Redis Clusterでは、MSETなどの利用にも注意が必要です。

上記の通り、通常通りMSETを実行するとエラーになります。 hash tags を利用することによってMSETが実行可能になります。MGETも同様です。

クライアントについて

Redis Clusterを利用するには、対応したクライアントライブラリを利用します。RubyやPythonの対応クライアントは公式ドキュメントでも紹介されています。

いずれも、非対応ライブラリとの差分はインスタンスを作成する際にRedisのノード情報をリストで渡す箇所程度のようです。

まとめ

  • マスタノードだけでは可用性の向上には繋がらない点に注意して利用します。
  • マスタ・スレーブは可用性の向上に繋がりますが、最小6台構成を取る必要があります。Fail Overの挙動を把握しておく必要があります。
  • レコードが同一ノード上にないと問題の発生する処理(コマンド)があります。ノードを固定することもできますが、データの偏りに気を配りましょう。

Redis Sentinelのように司令塔を配置しなくてもよいため、単純な揮発性のデータストアとして利用するにはかなり気軽に運用できそうです。ただし、集合演算をする場合やもう少しシビアな運用を迫られるケースでは、Redis Clusterの特性をよく理解しておく必要があることが分かりました。

参考文献