開発者のためのRedisチュートリアル(3)

レプリケーション(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プロセスがダウンした場合、メモリ内に保存されたデータは失われます。マスターノードに接続されたレプリカノードがある場合は幸いにもそのデータがレプリカノードに残っていますが、運用中のサービスでは、アプリケーションがマスターに接続されている場合に、以下の手順を手動で実行する必要があります。

  1. レプリカノードに接続し、REPLICAOF NO ONEコマンドを使ってマスター接続を解除する
  2. アプリケーションコードからRedisの接続設定を変更する(マスターノードのIP -> レプリカノードのIP)
  3. 配布

実際に運用されているサービスで、これらを解決するまでには長い時間がかかるでしょう。また、この期間中にデータが失われる可能性もあります。アプリケーションがマスターノードにアクセスできないとき、データを取得するために一時的に多くのコネクションが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サーバー自体は、不正な接続に対して直接データを移動させたりコマンドを伝達するのではなく、ただ正しいアドレスを伝達します。

サービスにおいては、ほとんどがJedisredis-pyなどのライブラリを通じてRedisを利用していると思いますが、このようなRedisクライアントは、リダイレクトメッセージを受信すると、正しいアドレスへ接続を変更し、再度同じメッセージを送信します。

簡単にいうと、アプリケーションはシャーディングを考慮せずに、どこに投げてもライブラリとRedisサーバーが自動で行ってくれます。

1:誤ったアドレスに保存する
2:無効なアドレスのためリダイレクトメッセージを返し、ライブラリは正しいアドレスでデータを保存する
3:正しいアドレスかを確認
4:OK

Reference

TOAST Meetup 編集部

TOASTの技術ナレッジやお得なイベント情報を発信していきます
pagetop