FacebookのユーザーDB — SQL?それともNoSQL?

Facebook(FB)が23億人以上のユーザーのプロフィールを保存するのに、どのデータベースを使用しているか気になったことがありますか?
SQLなのかNoSQLなのか?過去15年以上にわたって、FBのデータベース・アーキテクチャはどのように進化してきたのでしょうか?

2007年から2013年まで、FBのデータベース・インフラストラクチャ・チームのエンジニアとして、Yugabyte共同創設者でCTOのKarthik Ranganathanは、この進化を最前線で目の当たりにしてきました。近い将来、私たちの多くが全く同じ課題に直面することはないかもしれませんが、世界最大のソーシャルネットワークプラットフォームにおけるデータベースの進化をより良く理解することで、非常に貴重な教訓を得ることができます。なぜなら、FB のインターネット規模でグローバルに分散したアーキテクチャを支える基本的な考え方は、マルチテナント SaaSや社内のDBaaS、Eコマースサイト、オンラインゲームのリーダーズ・ボードなど、ビジネスに不可欠な多くの企業アプリに適用されているからです。

初期のアーキテクチャ

FBユーザーなら誰でも簡単に理解できるように、自分のプロフィールは、名前、Eメール、興味などの単なる属性のリストではない。実際には、友人や家族、グループ、チェックイン、「いいね!」、「シェア」など、すべての関係を保存するリッチなソーシャルグラフなのです。SQLの柔軟なデータモデリングと、FBが始まった当時のMySQLの普及を考慮し、このソーシャルグラフは当初、MySQLを永続データベースとして、memcacheを「ルックアサイド(look-aside)」キャッシュとして使用したPHPアプリケーションとして構築されました。

Facebookの初期のデータベースアーキテクチャ

ルックアサイドキャッシングパターンでは、アプリケーションはまずデータベースではなくキャッシュにデータを要求します。データがキャッシュされていない場合、アプリケーションはバックエンドのデータベースからデータを取得し、その後の読み込みのためにキャッシュに格納します。なお、この PHP アプリケーションは、間にデータ抽象化レイヤーを介さずに MySQL と memcache に直接アクセスしています。

成長に伴う課題

2005年以降のFBの快進撃は、前節で紹介したシンプルなデータベース・アーキテクチャに大きな負担をかけることになりました。FBのエンジニアが短期間で解決する必要のあった急激な成長に伴う課題を以下に列挙します。

開発者の俊敏性の欠如

リレーショナル・テーブルに永続的にデータを格納する MySQL マスター・スレーブ・ペアの大規模なコレクションと、SQL クエリの結果から(間接的に)得られたフラットな Key-Value ペアを格納・提供する memcache サーバーの同じく大規模なコレクションという、2 つの全く異なるデータ・ストアに対して作業をしなければならなかったのです。データベース層で作業するには、まずこの2つのストアがどのように連携して動作するのか、複雑な知識を身につけることが要求され、その結果、開発者の敏捷性が損なわれてしまったのです。

アプリケーションレベルのデータベースシャーディング

MySQL が 1 ノード以上の書き込み要求をスケールできないことは、データ量が飛躍的に増加するにつれて、致命的な問題となりました。MySQLのモノリシックアーキテクチャは、その特性上、早い段階でアプリケーションレベルのシャーディングを必要としました。つまり、アプリケーションは、どのMySQLインスタンスがどのユーザープロファイルの保存を担当しているかを追跡するようになったのです。このようなインスタンスの数が1個から100個に増え、さらに1000個になると、開発と運用の複雑さは指数関数的に増大します。このようなアーキテクチャに固執することは、アプリケーションがデータベースを使用してクロスシャードJOINやトランザクションを実行しないことを意味し、それによって水平方向に拡張するための(柔軟なクエリー言語としての)SQLのフルパワーをあきらめることになったことも特筆すべき点です。

マルチデータセンター、地理冗長レプリケーション

また、データセンターの障害への対応も重要な課題となり、MySQLスレーブ(および対応するmemcacheインスタンス)を地理的に冗長な複数のデータセンターに格納することになりました。フェイルオーバーを完璧にし、運用することは容易ではありませんでしたが、マスターとスレーブの非同期レプリケーションであるため、フェイルオーバーが行われた場合、直近でコミットしたデータが欠落したままになってしまいます。

キャッシュとDB間での一貫性の欠如

リモートリージョンのMySQLスレーブの前にあるmemcacheは、マスターとスレーブ間の非同期レプリケーションのために、強い(別名read-after-write)一貫した読み取りをすぐに提供することはできません。そして、その結果リモートリージョンで陳腐化したデータに対するリードが発生し、ユーザーを混乱させることになりかねない。例えば、ある友人へのリクエストが、一方の友人には受け入れられたと表示され、もう一方の友人には保留中と表示されることがあります。

TAO - シャードされたSQL上でのNoSQL Graph APIの導入

2009年初頭、FBはTAOの構築を開始しました。これは、シャードされたMySQL上で動作するように作られたFB特有のNoSQLグラフAPIです。その目的は、前節で強調した問題を解決することにありました。TAOは、「The Associations and Objects」の略です。TAOの設計は2013年に論文として発表されましたが、FBソーシャルグラフの特異な性質を考慮し、TAOの実装はオープンソース化されることはありませんでした。

TAOは、データ項目をノード(オブジェクト)、データ項目間の関係をエッジ(アソシエーション)で表現していました。FBアプリケーションの開発者は、MySQLやmemcacheの知識がなくても、アプリケーションロジックに必要なデータベースの更新やクエリを簡単に管理できるようになったため、このAPIを気に入りました。

アーキテクチャ

下図に示すように、TAO は主に FB の既存の何千ものマニュアルでシャードされた MySQL マスターとスレーブのペアを、スケーラブルで自動シャードの地理分散型データベースクラスタに変換したものです。同じシャード内のすべてのオブジェクトとアソシエーションは、同じMySQLインスタンスに永続的に保存され、各キャッシングクラスターの同じサーバーセットでキャッシュされます。個々のオブジェクトやアソシエーションの配置は、必要に応じて作成時に特定のシャードに対して割り当てられます。データのコロケーションの度合いを制御することで、低遅延のデータアクセスを提供するための重要な最適化が可能となりました。

TAOでは、このような低遅延性を保証する手段として、シャード間のACIDトランザクションやJOINなどのSQLベースのアクセスパターンを禁止しています。しかし、アソシエーション更新の観点(2つのオブジェクトが2つの異なるシャードに存在する可能性がある)では、非アトミックな2シャードの書き込みをサポートしました。1つのシャードの更新後、2つ目のシャードの更新前に障害が発生した場合、非同期の修復ジョブが後日、「ぶら下がった」アソシエーションを後でクリーンアップします。

シャードは、同じクラスタ内の別のサーバーに移行したりクローンしたりすることで、負荷のバランスをとり、負荷の急増をスムーズにすることができます。ロードスパイクは通常、数千万人のユーザーのニュースフィードに同時に表示されるような、一握りのオブジェクトやアソシエーションが非常に人気となったときに起こります。

TAO アーキテクチャ (Source: FB Engineering Blog)

企業のための汎用的なソリューションはないのか?

FBは、ユーザーのソーシャルグラフを担当するMySQLデータベースレイヤーを大規模に拡張する以外に選択肢がなかったのです。MySQLも、当時利用可能だった他のSQLデータベースも、単独でこの問題を解決することはできませんでした。そこでFBは、その強力なエンジニアリング力を駆使して、シャード化されたMySQLデータベースを抽象化するカスタムデータベースクエリレイヤーを実質的に作成したのです。そうすることで、開発者は柔軟なクエリ API としての SQL に完全に見切りをつけ、TAO のカスタム NoSQL API を採用することを余儀なくされたのです。

企業では、Facebook のような大規模な問題はないものの、SQL データベースをオンデマンドでスケールアウトさせたいと考える人がほとんどでしょう。私たちは、その柔軟性と普遍性からSQLを愛しています。つまり、SQLをあきらめることなく拡張したいと考えているのです。私たちのような企業のための汎用的なソリューションはないのでしょうか?その答えはあります!

分散SQLの登場

モノリシックなSQLデータベースは、水平スケーリングの問題を解決するために、10年以上前から分散化を試みてきました。我々のブログポスト。”Rise of Globally Distributed SQL Databases “で強調しているように、そのようなデータベースの最初の波はNewSQLと呼ばれ、Clustrix、NuoDB、Citus、Vitessなどのデータベースがを含まれていました。これらは、手動でシャード化されたSQLデータベースを置き換えるという点では、限られた成功しか収めておりません。その理由は、新たに生み出される価値が、開発者や運用者の経験を根本的に簡素化するのに十分でないからです。ClustrixとNuoDBは、専門的で信頼性の高い低遅延のデータセンター・インフラを義務付けているため、最新のクラウド・ネイティブ・インフラとは正反対の方針に見えます。CitusとVitessは、データベースを自動シャーディングすることである程度運用を簡素化しますが、単一の論理的な分散SQLデータベースを開発者に提供しないため、ハンディキャップを背負うことになります。

10年前、Facebookはこれらの機能をアプリケーション層に組み込まなければなりませんでしたが、現在我々が取り組んでいるのは、大規模なスケーラビリティとグローバルなデータ分散がデータベース層に組み込まれた、第二世代の分散SQLデータベースです。

Google Spannerからの影響

FBがTAOを構築している間、Googleは全く新しいグローバルに一貫性を持ったデータベースであるSpannerを構築し、非常によく似た課題を解決に取り組んでいました。Spannerのデータモデルは、ソーシャルグラフというよりも、Googleのユーザー、顧客組織、AdWordsクレジット、GMailプリファレンスなどを管理する従来のランダムアクセス型OLTPワークロードのようなものだったのです。Spannerは、2012年にデザインペーパーという形で初めて公開されました。2007年にトランザクション型のキーバリューストアとしてスタートしましたが、その後、SQLデータベースへと進化していきました。SQLを唯一のクライアント言語とする傾向は、Googleのエンジニアが、特にインフラ面で過去の高信頼性プライベートデータセンターに比べて、よりもずっと動的で故障しやすいクラウドネイティブ時代において、SQLがアジャイルアプリ開発に適した構造をすべて備えていることに気づいたことから加速しました。今日、複数の最新のデータベース(YugabyteDBを含む)が、Google Spannerの設計を完全にオープンソースで実現させています。

インターネットレベルでスケールするデータボリュームを簡単に管理

Spannerアーキテクチャでは、シャーディングは完全に自動化されています。さらに、新しいノードが追加されたり、既存のノードが削除されたりすると、シャードは利用可能なすべてのノードに対して自動的にバランスされるようになります。大規模な書き込みスケーラビリティを必要とするマイクロサービスでは、FBアーキテクチャで見られたような新しいインフラ層を追加するのではなく、データベースに直接依存することができるようになりました。インメモリーキャッシュも、シャード管理を行うTAOのようなアプリケーションレイヤーも不要になります。

障害に強い回復性

Spanner と前節でレビューした従来の NewSQL データベースとの主な違いは、Spanner ではシャード単位の分散コンセンサスを使用し、障害が発生しても各シャード(単に各インスタンスではなく)が高い可用性を維持できるようにしている点です。TAOと同様、インフラの障害は常にデータのサブセット(リーダーがパーティショニングされたシャードのみ)にのみ影響し、クラスタ全体が影響を受けることはありません。また、残りのシャードレプリカが数秒で新しいリーダーを自動選択できるため、障害が発生した場合でもクラスタは自己回復機能を発揮します。アプリケーションは、このようなクラスタ構成の変更に対して透過的であり、停止や速度低下もなく正常に動作し続けます。

グローバルにシームレスなレプリケーション

グローバルに一貫性のあるデータベースアーキテクチャの利点は、マルチゾーンやマルチリージョンの書き込みシナリオで絶対に正しいデータを必要とするマイクロサービスが、最終的にデータベースに直接依存することができることです。過去の典型的なマルチマスターの展開で見られた競合やデータ損失は発生しません。テーブルレベルおよび行レベルのジオパーティショニングなどの機能により、ローカル地域に関連するデータが同じ地域に優先されたままであることが保証されます。これにより、一貫性の高い読み取りパスが、リージョンやWANをまたぐレイテンシーを発生させることがありません。

SQLと分散ACIDトランザクションの強力な組み合わせ

レガシーなNewSQLデータベースとは異なり、SpannerアーキテクチャではSQLとACIDトランザクションを完全な形でサポートすることができます。シングルキー操作は、デフォルトで強い一貫性とトランザクション性を持っています(技術用語では線形化)。単一シャードのトランザクションは、定義上、単一シャードで管理されるため、分散トランザクション・マネージャーを使用せずにコミットすることができます。多シャード(別名分散)ACIDトランザクションは、ノード間のクロックスキューも追跡する分散トランザクションマネージャを使用した2フェーズコミットを伴います。マルチシャードハードJOINも同様に、ノード間でデータを参照することで処理されます。ここで重要なのは、すべてのデータアクセス操作が開発者にとって透過的であり、開発者は通常のSQL構文を使ってデータベースと対話するだけでよいという点です。

まとめ

FBやGoogleを含むテクノロジージャイアントにおけるデータインフラスケーリングの話は、素晴らしいエンジニアリングの勉強になります。FBでは、TAOを構築することで、シャード化されたMySQLへの既存の投資を維持する道を選びました。アプリケーションエンジニアは SQL を使用する能力を失いましたが、その他の多くの利点を得ることができました。Googleのエンジニアも同様の問題に直面しましたが、彼らはSpannerという全く新しいSQLデータベースを開発し、水平方向に拡張でき、シームレスに地理的に複製でき、インフラの障害にも容易に耐えられるという異なる道を選びました。FBとGoogleはどちらも素晴らしいサクセスストーリーなので、どちらか一方だけが優れているということは言えません。しかし、汎用的なエンタープライズ・アーキテクチャに視野を広げると、このブログポストで取り上げたすべての理由から、SpannerがTAOより先行します。YugabyteDBのストレージ・レイヤーをSpannerアーキテクチャ上に構築することで、巨大テクノロジー企業の開発者の敏捷性を今日のあらゆる規模のエンタープライズ企業にもたらすことができると信じています。

本記事は、The Distributed SQL Blogsにて2017年8月29日に公開(2019年3月に更新)されたFacebook’s User DB — Is it SQL or NoSQL?を翻訳および一部訳注を追加しております。最新情報は英語版の記事を参照してください。

より詳細を知るには

より詳細を知りたい方、試しに使ってみたい方は、ぜひ以下の情報もチェックしてください。

  • YugabyteDBはすぐ利用できます ダウンロードはこちら!
    インストールは数分で完了します
  • Slack に参加してください!より多くのコミュニティメンバーや、Yugabyteのエンジニアリングチームとのコミュニケーションとつながりましょう!

また、今年で4回目の開催となる年次イベントDistributed SQL Summitが2022年9月に開催です。ぜひご登録ください!

--

--