成り立ち
Google社内で使用されていたバージョンのSpannerは、「AdWords」や「Google Play」などのワークロードを処理するために開発された。Googleによれば、これらのサービスではもともと、MySQLを使用し、手動でシャーディングを行っていた。この手法の問題は、その手動でのシャーディングだった。この手法を採用することで、MySQLが本来対応していないスケールアウトが可能になったが、これは非常に扱いにくいもので、データベースの再シャーディングには年単位の処理を必要とした。
Googleは、柔軟にシャーディングを行える機能をネイティブに備え、リレーショナルなスキーマとストレージが使用可能で、ACIDに対応しており、ゼロダウンタイムをサポートしているデータベースを必要としていた。そのようなデータベースは存在していなかったため、Googleは自前で開発を行い、Spannerの原型が生み出された。その後10年近くにもおよぶ自社製品でのテストを経て、同社はCloud Spannerとその公開APIの一般提供にたどり着いた。
スケールアウトとACIDの両立
Spannerは、自動シャーディング機能を持っているにもかかわらず、まもなくリージョン間トランザクションにも対応する予定だ。そんなことが可能なのなら、従来のリレーショナルデータベースでは、何故それができなかったのだろうか。また、Spannerがスケールアウトに対応しながら、従来のリレーショナルデータベースが持つ性質も失っていないのに対し、これまでのプラットフォームがスケールアップモデルにしか対応できなかった理由は何だろうか。Spannerは、どうやってこの2つを両立しているのだろうか。
ポイントはトランザクションのコミット方法だ。従来のシステムでは、データベースが地理的に分散している場合、2相コミットと呼ばれるプロトコルを用いていた。この手法では、各サイトでの作業がすべて完了するまで、コミットが完了しなかった。しかしSpannerでは、各サイトにほかのサイトの完全な複製が用意されており、Paxosコンセンサスアルゴリズムを使用して、大半のサイトで作業が完了したはずの時点でトランザクションをコミットしている。更新が完了していないサイトのユーザーが、さらに処理を行った場合、そのサイトで処理が完了するまでの間、処理は完了済みのサイトにリルートされる。この方式では、タイミングによっては一部のユーザーに余分の遅延が発生するが、分散型の一般的なデータベースで見られる処理の渋滞を排除することができる。
さらなる工夫
特に重要なのはPaxosアルゴリズムだが、そのほかのソフトウェア的な工夫や、最適化されたネットワークやハードウェアも使い勝手に貢献している。例えば、書き込み操作中にデータをロックする際、Spannerの場合は、行全体をロックするのではなく、特定のセル(特定の行の特定の列にあるセル)だけをロックする。これによって競合を最小限に抑えることができるため、トランザクションのコミットを高速化しつつ、データベース全体の一貫性を確保することができる。また、少し古いバージョンのデータを「ステイル」(古い)データとして読み込み専用に提供することで、不必要な競合をさらに減らしている。
高速化のためのもう1つの工夫として、Spannerでは、子データを物理的に親データと一緒にストアしている。一般的なデータベースでは、これらのデータは別のテーブルにストアされる。これによって、階層的なデータを含むクエリ(例えば発注情報と品目名)を、テーブルの結合を経ずに一度に実行することができる。
CAP定理では、分断耐性と一貫性を保ちながら高い可用性を確保することは不可能だとされているが、Spannerは分散データベースにつきものの制約の一部を、最適化によってひとつずつ緩和することで、この定理を(よい意味で)上手に逃れている。