データベース●●●○○

レプリケーション

同じデータを複数のノードに複製し、可用性と読み取り性能を高める仕組み。

概要

レプリケーション(複製)は、同じデータを複数のノードにコピーして持たせ、可用性(落ちにくさ)と読み取り性能を高める仕組みです。データが1台にしかなければ、その1台が壊れた瞬間にデータもサービスも失われますが、同じ内容を複数台に複製しておけば、1台が倒れても別の複製で処理を続けられます。データベースの世界でまず登場する冗長化の基本形です。

もっとも典型的なのが「プライマリ/レプリカ」構成です。書き込みを一手に引き受ける代表ノード(プライマリ)が1台あり、その内容を複製した従属ノード(レプリカ)が複数ぶら下がります。読み取りリクエストを多数のレプリカに振り分ければ、RDBMSの読み取り負荷を水平に分散でき、プライマリが故障してもレプリカの一つを新たなプライマリに昇格させて復旧できます。

レプリケーションは、同じデータを複数の場所に分けて置くシャーディング(データを分割して別々のノードに分ける)とよく対で語られますが、目的は逆です。シャーディングが「1台に載りきらないデータを分けて容量と書き込みを稼ぐ」のに対し、レプリケーションは「同じデータをあえて重複させて可用性と読み取りを稼ぐ」ものです。

なぜ生まれたか

データベースが1台しかない構成には、二つの根本的な弱点があります。一つは可用性です。その1台がハード故障やメンテナンスで止まれば、サービス全体が止まります。データそのものが失われれば復旧すらできません。もう一つは読み取り性能です。ユーザーが増えて読み取りが殺到すると、1台では処理しきれず応答が遅くなります。多くのサービスは書き込みより読み取りがはるかに多いため、この読み取りの詰まりは深刻でした。

レプリケーションは、この二つを「データを複製して持つ」という一つの手で同時に解きました。複製があれば1台失っても代わりが利き(可用性)、読み取りを複数の複製に分担させられます(読み取りスケール)。データを別のデータセンターへ複製しておけば、災害でひとつの拠点が丸ごと失われても事業を継続できる(ディザスタリカバリ)という価値も生まれました。「壊れる前提」で系を組む分散システムの発想を、データストアに持ち込んだ最初の一歩がレプリケーションだと言えます。

詳細

プライマリ/レプリカの基本構成

最も普及した形が、1台のプライマリと複数のレプリカからなる構成です。アプリケーションからの書き込み(INSERTやUPDATE)はすべてプライマリに集約され、プライマリは自分に加えた変更を「変更ログ」としてレプリカに送り、レプリカはそれを再生して自分のデータを同じ状態に追いつかせます。読み取りはプライマリでもレプリカでも行えるため、読み取りをレプリカ群に振り分けて負荷を分散します。書き込みは1台に集中する一方で、読み取りだけが横に伸びる非対称な構成である点が要点です。

アプリプライマリ書き込みを集約レプリカ 1レプリカ 2レプリカ 3書き込み変更ログを複製読み取りはレプリカに分散
プライマリ/レプリカ構成 — 書き込みは1台に集約し、読み取りをレプリカに分散する

同期レプリケーションと非同期レプリケーション

プライマリの変更をレプリカへ「いつ反映するか」で、大きく二方式に分かれます。同期(synchronous)レプリケーションは、プライマリが書き込みをレプリカに送り、レプリカが受け取ったと返事するのを待ってから、アプリに「書き込み完了」を返します。非同期(asynchronous)レプリケーションは、レプリカの返事を待たずに即座に完了を返し、複製は裏で追いかけて進めます。この待つか待たないかの一点が、性能と安全性のトレードオフをまるごと決めます。

レプリカプライマリアプリレプリカプライマリアプリ同期レプリケーション非同期レプリケーション書き込み変更を送る反映しました書き込み完了書き込み書き込み完了変更を後で送る

同期方式は、完了が返った時点で少なくとも1台のレプリカにデータが渡っているため、プライマリが直後に壊れてもデータは失われません。安全な代わりに、毎回レプリカの応答を待つぶん書き込みが遅くなり、レプリカが1台でも詰まると書き込み全体が止まるもろさがあります。非同期方式は待たないので書き込みが速く、レプリカの遅延がプライマリに波及しません。ただし、複製が届く前にプライマリが壊れると、まだ複製されていなかった直近の書き込みが失われる可能性があります。多くのシステムは、両者の中間として「複数レプリカのうち1台の応答だけ待つ(準同期)」といった折衷を採ります。

レプリケーションラグと読み取りの一貫性

非同期レプリケーションでは、プライマリへの書き込みがレプリカに届くまでにわずかな遅れが生じます。これを「レプリケーションラグ(複製遅延)」と呼びます。ラグがあると、たとえばユーザーが自分の投稿を書き込んだ直後にレプリカから読むと、まだ届いておらず「投稿したのに表示されない」という現象が起きます。これはCとAのトレードオフを扱うCAP定理、そして「時間が経てば全複製が同じ値に収束する」という結果整合性の、最も身近な現れです。対策として、書き込み直後の読み取りだけはプライマリに向ける、といった一貫性の作り込みが実務では必要になります。

フェイルオーバーと運用上の落とし穴

プライマリが故障したとき、レプリカの一つを新プライマリに昇格させて処理を引き継ぐのが「フェイルオーバー」です。自動化されていることが多いものの、ここには難所が潜みます。非同期構成では、昇格したレプリカに未反映の書き込みがあると、それらは失われます。さらに、実は旧プライマリが生きていて分断していただけの場合、新旧二つのプライマリが同時に書き込みを受け付けてしまう「スプリットブレイン」が起き、データが取り返しのつかない形で食い違うことがあります。これを防ぐため、過半数のノードで合意(コンセンサス)が取れた側だけがプライマリを名乗れる、といった仕組みが用いられます。レプリケーションは「複製すれば安心」ではなく、遅延・データ損失・スプリットブレインという固有のリスクとセットで設計する対象だと理解しておくことが肝心です。