ユユユユユ

webエンジニアです

同期レプリケーションか、非同期レプリケーションか

 書き込みログをネットワーク越しにリードレプリカに転送するジョブは、基本的には軽量で高速動作する。ただしネットワークの不調やリードレプリカの予期せぬ故障など外部要因によって無制限の遅延が発生する可能性は常に存在する。

同期レプリケーション

 リーダーノードとリードレプリカの間のレプリケーションを常に同期的に実行するとする。ノード間のネットワークが遅延していても、リードレプリカに正しく疎通がとれるまでリーダーノードは書き込みリクエストに対して ok を返さない。

 このときクラスタ全体が常に最新のデータを持つことを保証できる。またリーダーがダウンしてもリードレプリカが読み取りリクエストを処理しつづけることができる。他方で、リードレプリカが一台でも落ちてしまうと、リーダーノードは疎通が取れるようになるまで書き込みリクエストをブロックせざるを得ない状況に陥ってしまう。

 つまり、クラスタ全体にわたって同期レプリケーションを実施するというのは、一台でもノードが落ちるとシステム全体が落ちてしまうということにほかならない。分散データベースが要請される前提条件が崩れることになるので、これは許容できない選択となるだろう。

非同期レプリケーション

 他方でレプリケーションを非同期で行うとすると、原理的にデータの損失が発生しうる。とはいえ多少のデータ損失を許容できるのであれば、これは有効な選択肢となろう。データ損失など多少なりとも許容できない! と息巻く気持ちはわかるが、100%の安全性を要件とするのはそもそも不健全だし保証不可能なので、どの程度の損失を許容できるかを明確化し、運用コストとの落とし所を探るのが賢明だろう。その意味で、データ損失を覚悟のうえ非同期レプリケーションを検討するのは有効であるはずと繰り返し述べておく。

 どういうときにデータの損失が起こりうるか? それはリーダーノードが受け付けた書き込みをリードレプリカに転送する前に不意にダウンしてしまうときである。リードレプリカのうち任意の一台が新しいリーダーノードに昇格することで、全体としての可用性は守られるが、クライアントから見ると成功したはずの書き込みが消失してしまうケースが生じうることは避けられない。

 実際、データ損失のリスクというトレードオフを飲んでも非同期レプリケーションを採用する事例は多い。特に書き込みクライアントが世界中に散らばっていて、リーダーノードが一台しか存在しない場合であれば、レスポンスタイムの最短化を最優先に考慮してレプリケーションは非同期で行うという選択肢は少なからず有効だろう。

半同期レプリケーション

 それでもデータ損失のリスクは受け入れがたいというのであれば、 Facebook 社にて採用されている半同期( semi-synchronous )パターンこそがもっとも中庸の落としどころといえるかもしれない。

 これはリードレプリカのうち任意の一台について同期レプリケーションを行い、残りのリードレプリカに対しては非同期でレプリケーションを行う方式である。つまり最新のデータが最低でもリーダーのほかにもう一台に存在することが保証されるので、リーダーノードがダウンしてもデータの損失なしにフェイルオーバーできるといえることとなる。

 この方式の出典はマツノブ・ヨシノリ氏の公開記事に記載があるので、詳細についてはこれをよく読むのが良い。