コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB
NewSQL と分散 SQL
分けたら、SQL が書けなくなった
書き込みが 1 台で足りなくなり、データを複数のサーバへ分けた。ここまでは狙いどおりです。ところがその後、開発の手が止まります。
集計は、各サーバへ投げて足し上げるコードを自分で書くことになります。別のサーバにあるテーブルとの結合は、両方から引いてきてアプリのメモリ上で突き合わせることになります。2 つのサーバにまたがる更新は、片方だけ成功した場合の後始末を自分で書くことになります。SQL 1 行で済んでいたものが、そのたびにアプリ側の処理へ移っていきます。
分散はしたい、けれど SQL とトランザクションは手放したくない。この要求に応えようとしているのが、分散 SQL と呼ばれる系統のデータベースです。利用者から見ると 1 台の RDB に見え、内部では自動でデータが分割され、必要ならサーバをまたいだトランザクションも張れます。
順番さえ決められれば、分けたままで揃う
分けた状態で ACID を保つのが難しいのは、「どちらの書き込みが先か」を全体で一致させられないからです。各サーバの時計は少しずつずれているので、時刻を見るだけでは順番が決まりません。
やり方は 2 段構えです。
まず、同じデータの塊を持つサーバどうしで多数決を取ります。変更はまず代表役のサーバに届き、代表が他の複製へログを送り、過半数が受け取ったところで確定とします。過半数で決めるので、少数側が落ちても止まりません。3 台なら 1 台まで、5 台なら 2 台までの故障に耐えます。
過半数で決めることには、もう 1 つ効果があります。分断で 2 つに割れても、確定を進められるのは過半数を保てた側だけなので、両側が別々の答えを確定させることが起きません。少数側は書き込みを受け付けられなくなり、前の回でいう「エラーを返す」側の振る舞いになります。
その上で、全体を通した順番を決める仕組みを置きます。番号を配る役を中央に 1 つ立てる方式と、各サーバのローカル時計に論理的なカウンタを足して補正する方式があります。どちらも目的は同じで、離れた場所で起きた 2 つの書き込みに、矛盾しない前後関係を与えることです。
その遅さを払えるか
いいことばかりではありません。書き込みは毎回、過半数の返事を待ってから確定します。1 台のディスクで完結する場合と比べれば、確実に遅くなります。データは通常 3 か所へ複製されるので、ディスクもサーバ台数も増えます。故障時の挙動や複製の配置を理解していないと、運用でつまずきます。
ですから、データが数百 GB で書き込みが秒間数百程度なら、普通の PostgreSQL や MySQL の方が速くて簡単です。分散 SQL が効いてくるのは、1 台では受け切れないところまで書き込みが伸びたときに、それまでのアプリのコードを書き直さずに済ませたい場合です。
選ぶ前に、いま困っているのが本当に 1 台の書き込み上限なのかを確かめてください。索引の張り忘れや、1 リクエストで何十回も走るクエリが原因だった、という話は規模の大きい現場ほどよくあります。台数を増やす判断は、そこを潰した後の話です。
トランザクションの中身から、遅いクエリの追い方、台数を増やしたときに何が壊れるかまで通ってきました。製品が変わっても、土台は同じところにあります。