NHN Cloud Meetup 編集部
開発者のためのRedisチュートリアル(3)
2020.04.16
3,239
レプリケーション(Replication)
ここからはRedisのHA(High Availability)について調べてみましょう。Redisは、マスター(Master) – レプリカ(Replica)形式の複製を提供しています。レプリケーション接続がされている間、マスターノードのデータはリアルタイムでレプリカノードにコピーされます。したがって、サービスを提供していたマスターノードがダウンしても、レプリカノードにアプリケーションを再接続すればサービスを継続できます。
1つのマスターに複数のレプリカノードをつけることができ、レプリカノードに別のレプリカノードを接続することも可能ですが、1つの複製グループには、常に1つのマスターノードのみが存在します。マルチマスターの構造で両方にデータを複製することはできません。
複製方法は非常に簡単で、たとえばマスターノードのIPアドレスが127.0.0.1、ポートが6001であれば、レプリカノードで下記のコマンドを実行すると複製が開始されます。
> replicaof 127.0.0.1 6001
replicaofコマンドを受信したマスターノードAは子プロセスを作成し、バックグラウンドでダンプファイルを作成して、これをネットワークからレプリカノードであるBに送信します。このファイルを受信したノードBは、データをメモリにロードします。
一度接続されると、データの複製は非同期で行われます。つまり、マスターにデータが入ってくると、マスターはアプリケーションにACKを送信します。その次にレプリカノードにデータを転送するため、もしマスターにデータが入力された後にマスターノードがダウンした場合、このデータはレプリカノードまで伝達されず、データが失われる可能性があります。現時点では、この現象に対するデバッグが困難なほどにデータの配信速度が速いため、データが失われるケースはほとんど発生しないだろうと予想されます。
センチネル(Sentinel)
インメモリデータベースにおける障害の危険性
Redisプロセスがダウンした場合、メモリ内に保存されたデータは失われます。マスターノードに接続されたレプリカノードがある場合は幸いにもそのデータがレプリカノードに残っていますが、運用中のサービスでは、アプリケーションがマスターに接続されている場合に、以下の手順を手動で実行する必要があります。
- レプリカノードに接続し、REPLICAOF NO ONE
コマンドを使ってマスター接続を解除する
- アプリケーションコードからRedisの接続設定を変更する(マスターノードのIP -> レプリカノードのIP)
- 配布
実際に運用されているサービスで、これらを解決するまでには長い時間がかかるでしょう。また、この期間中にデータが失われる可能性もあります。アプリケーションがマスターノードにアクセスできないとき、データを取得するために一時的に多くのコネクションがRDBMSに殺到し、サービス障害につながった事例もあります。
センチネル構成
このような障害を回避できるようにサポートするのがセンチネルです。センチネルは、マスターとレプリカノードを継続してモニタリングし、障害時にはレプリケーションノードをマスターに昇格させるため、自動フェイルオーバーを実行します。特定の状況で担当者にメールを送信するように通知(Notification)設定も可能です。
正常に機能するには、少なくとも3つのセンチネルインスタンスが必要です。各センチネルインスタンスはRedisのすべてのノードをモニタリングし、相互に接続されています。3台のセンチネルノードのうち、過半数以上(quorum)の同意があればフェイルオーバーを開始することができます。
このような構成で、アプリケーションはマスターやレプリカノードへ直接接続せずに、センチネルノードと接続します。センチネルノードは、アプリケーションに現在のマスターのIPアドレスやポートを伝達し、フェイルオーバー以降は、新しいマスターのIPアドレスとポート情報を伝達します。
フェイルオーバーのプロセス
では、フェイルオーバーがどのように進行されるか簡単にみてみましょう。
この例では、マスターに2つのレプリカノードが接続されています。このときマスターがダウンすると、これをモニタリングしていたセンチネルは、マスターに接続できない状況になっているか投票を開始します。
この投票で過半数以上が同意した場合、フェイルオーバーを開始します。この例では、3つのうち2つのノードの賛成を得るとフェイルオーバーが可能です。接続できないマスターのレプリケーション接続を切断し、レプリカノードの1つを選択して、マスターに昇格させます。
もう1つのレプリカノードは昇格されたマスターノードに接続します。そして、ダウンしていたマスターノードが復活すると、新しいマスターにコピー版が接続されます。
クラスタ(Cluster)
最後に、Redisの王様ともいえるクラスタについてみてみましょう。なぜ王様かというと、今までのすべてのメリットにシャーディング機能までが加わるからです。Redis Clusterの特徴として、拡張性、高性能、高可用性があります。
- データセットを複数のノードに自動分散 -> 拡張性、高性能
- 複数のノードがダウンしても継続して使用可能 -> 高可用性
外部のプロキシやツールを使用しなくても、このような機能が利用できることがRedisの大きなメリットといえるでしょう。
Redis Clusterの構成
クラスタ内のすべてのノードは、相互に接続されたフルメッシュ(Full Mesh)構造となっています。すべてのマスターとレプリカノードは相互に接続されており、ゴシッププロトコルを利用して通信します。クラスタを使用するには、少なくとも3つのマスターノードが必要です。
それでは、Redisに入ってくるデータがどのように分散されるか、みてみましょう。
シャーディング(Sharding)
アプリケーションから入ってくるすべてのデータは、ハッシュスロットに格納されます。Redis Clusterは、合計16384個のスロットを保有し、マスターノードはスロットを分けて保存します。マスターノードが3つのとき、次のようにハッシュスロットが分配されることがあります。
- ノードAは、0から5500までのハッシュスロットを含む
- ノードBは、5501から11000までのハッシュスロットを含む
- ノードCは、10001から16383までのハッシュスロットを含む
入力されたすべてのキーは、スロットにマッピングされます。このとき次のようなアルゴリズムを使用します。
HASH_SLOT = CRC16(key) mod 16384
ハッシュスロットはマスターノード内で自由に移動できるためダウンタイムは必要ありません。したがって、新しいノードを追加したり、既存のノードを削除するときには、ハッシュスロットを移動させるだけでよく、これによって簡単に拡張ができます。
一般的には、3台のマスターに3台のレプリカノードを接続する構成がよく使われます。またレプリカノードは、図のようにマスターノードの正確なレプリカを保有しています。
フェイルオーバー(Failover)
センチネルと同様に、Redis Clusterでもマスターノードがダウンすると、接続されたレプリカノードをマスターに昇格させるフェイルオーバーが発生します。ただし、センチネル構造ではセンチネルプロセスがノードをモニタリングしましたが、Redis Cluster構造では、すべてのノードが相互にモニタリングするという点で違いがあります。
もし、可用性が重要なサービスにおいてRedis Cluster構成を使用する際に、ノードを追加できる余裕があるならば、どのマスターにもレプリカノードをもう1つ接続させることをお勧めします。Redis Clusterは、レプリカノードのいずれかがダウンした場合、レプリカノードがないマスターがあったときには、レプリカノードが2つあるマスターのレプリカノードをその場に補填できるからです。下図のように、Aにレプリカノードを2つ接続した状態で、Bのレプリカノードがダウンすると、Aに接続されたレプリカノードをBのレプリカノードに変更させます。すべてのプロセスはユーザーが介入することなくクラスタ内の通信で行われます。
クライアントへのリダイレクト(Client Redirection)
クラスタ構造のデータはマスターノードに分割されて保存されるとのことですが、アプリケーションは分割されたデータをどのように把握してデータを保存するのでしょうか?
クライアントはレプリカノードを含むすべてのノードに自由にクエリを送信することができます。しかし、要求されたコマンドのキーが、アクセスするノードに存在しない可能性があります。このような場合、ノードは当該キーを持っているノードの情報を伝達してくれるリダイレクトメッセージを返します。Redisサーバー自体は、不正な接続に対して直接データを移動させたりコマンドを伝達するのではなく、ただ正しいアドレスを伝達します。
サービスにおいては、ほとんどがJedisやredis-pyなどのライブラリを通じてRedisを利用していると思いますが、このようなRedisクライアントは、リダイレクトメッセージを受信すると、正しいアドレスへ接続を変更し、再度同じメッセージを送信します。
簡単にいうと、アプリケーションはシャーディングを考慮せずに、どこに投げてもライブラリとRedisサーバーが自動で行ってくれます。
1:誤ったアドレスに保存する
2:無効なアドレスのためリダイレクトメッセージを返し、ライブラリは正しいアドレスでデータを保存する
3:正しいアドレスかを確認
4:OK