コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB
結果整合性
投稿した直後に、自分の投稿が見当たらない
コメントを送信した。成功と表示された。一覧に戻ったら、自分のコメントがない。もう一度読み込むと、今度は出てくる。
送信は 1 台目に届き、一覧の取得はまだ反映の終わっていない 2 台目から読んだ、というだけの話です。数秒待てば全台が揃います。この「最終的には全部が同じ値に落ち着く。ただし途中は揃っていない」という性質を結果整合性と呼びます。前の回のレプリカの遅れも、分断のときに古い値を返す側へ倒した結果も、行き着く先はここです。ACID に対して BASE と呼ばれるのも、この割り切りの側の設計を指しています。
厄介なのは、利用者から見ると単なるバグに見えることです。書き込みが失われたと思われれば、同じコメントを何度も送られます。
「そのうち揃う」を仕様として扱う
結果整合性は、放っておけば直る不具合ではありません。分散させると決めた時点で選んだ性質なので、揃っていない間の見え方まで設計で決めます。
守る優先順位ははっきりしています。まず、自分が書いたものは自分には必ず見えること。他人の投稿が数秒遅れて見えるのを気にする人はいませんが、自分の投稿が消えるのは耐えられません。書き込んだ直後の読み取りだけ Primary に向ける、あるいはその利用者の接続を書き込んだ台に固定する、といった形で実現します。
次に、後から読んだ方が古くならないこと。読むたびに別の台へ振り分けていると、1 回目に見えたコメントが 2 回目に消えることがあります。同じ利用者の連続した読み取りは、同じ台へ寄せます。
画面の側にも手当てができます。送信した内容をサーバから取り直さず、その場で一覧へ足しておく。「最終更新 3 秒前」と添える。実態が揃っていなくても、利用者の頭の中の整合性は保てます。
どこまで守るかは機能ごとに決めます。全部を強く守ろうとすれば、分散させた意味がなくなります。自分の書き込みが自分に見えることだけを全機能で守り、残りは古くてよいと決める。この線引きを文章にして残しておくと、後から入ったメンバーが「これはバグではないか」と調べ直す時間が減ります。
同時に書かれたとき、どちらを残すか
分断の最中に、別々の台で同じデータが更新されることもあります。復旧したとき 2 つの値が残っているので、どちらかに決めなければなりません。
いちばん簡単なのは、時刻の新しい方を残す方法です。実装は楽ですが、負けた方の書き込みは黙って消えます。しかも台ごとの時計は数ミリ秒ずれるので、「新しい方」が実際の順序と食い違うこともあります。
消したくないなら、そもそも衝突しないデータの持ち方にします。カウンタなら、合計値を上書きするのではなく、台ごとに自分が足したぶんだけを持ち、読むときに合算する。こうすればどの順で反映されても結果は同じです。共同編集ツールが同時編集を壊さずに済ませているのも、根は同じ考え方です。
どの方式を選んだとしても、衝突が起きた事実そのものは記録に残します。残っていないと、消えた書き込みに後から気づく手段がありません。
結果整合性は事故ではなく仕様です。仕様として書いておけば、障害報告ではなく想定内になります。