ストリーム処理を使用してバックエンドを構築したことがある場合は、これから説明する種類のシステムに精通していることになります。そうでない場合も心配しないでください。順を追って説明します。
従来のウェブバックエンドのスケーリング
従来の、使いやすいウェブアーキテクチャは、アプリサーバーの背後にある「1つの大きなSQLデータベース」です。アプリはデータベースと通信し、フロントエンドからのリクエストを処理します。
アプリケーションが大きくなるにつれて、パフォーマンスの限界に達するため、スタックにキャッシュをいくつか投入します。
次に、シャーディングとレプリカを使用してデータベースを水平方向にスケーリングするとします。
これはかなり良いですが、何億人ものユーザーを抱えるソーシャルネットワークを構築しているため、このモデルでも限界に達します。問題は、SQLデータベースが強い一貫性を持つことです。つまり、状態はシステム全体で均一に同期されています。強い一貫性を維持するとパフォーマンスコストが発生し、それがボトルネックになります。
システムを緩和して結果整合性を使用できれば、さらに拡張できます。まず、NoSQLクラスターに切り替えます。
これは拡張には適していますが、SQLがないとクエリの構築が難しくなります。SQLデータベースには、JOINや集計クエリなど、多くの便利な機能があることがわかりました。実際、NoSQLデータベースは単なるキーバリューストアです。機能の作成は面倒になってしまいます。
これを修正するには、データセットの事前計算済みビューを生成するプログラムを作成する必要があります。これらのビューは、本質的にはキャッシュされたクエリのようなものです。これらのビューに標準データを複製して、非常に高速にします。
これらをビューサーバーと呼びます。
ここで、ビューサーバーをNoSQLクラスター内の正規データと同期させ続けるのは難しいことに気が付きました。ビューサーバーがクラッシュして更新が失われることがあります。ビューが確実に最新の状態に保たれるようにする必要があります。
この問題を解決するために、イベントログ(Kafkaなど)を導入します。このログは、NoSQLクラスターへのすべての変更を記録してブロードキャストします。ビューサーバーは、再起動が必要な場合でも更新を見逃さないように、このログをリッスンして再生します。
これでストリーム処理アーキテクチャに到達しました。さらに詳しく説明できる点はたくさんありますが、今のところはこれで十分です。
良いニュースは、このアーキテクチャの拡張性が非常に高いことです。強い一貫性はあきらめ、読み取りクエリがデータの最新バージョンより遅れることもありますが、サービスが書き込みをドロップしたり、誤った状態になったりすることはありません。
ある意味、私たちが行ったのはデータベースを裏返しにして、データベースをカスタム構築したことです。標準ストレージをNoSQLクラスターに簡素化し、ビューサーバーを使用して独自のクエリエンジンを構築しました。構築の利便性は大幅に低下しますが、拡張性があります。
大規模バックエンドの分散化
ATプロトコルの目標は、アプリケーションを相互接続して、バックエンド間でユーザーアカウントやコンテンツなどの状態を共有することです。
どうすればそれができるでしょうか。図を見ると、システムの大部分が外部から分離されており、アプリサーバーのみがパブリックインターフェイスを提供していることがわかります。
私たちの目標は、この分離を解消して、他の人がNoSQLクラスター、イベントログ、ビューサーバーなどに参加できるようにすることです。
次のようになります。
これらの内部サービスはそれぞれ外部サービスになりました。これらには、誰でも使用できるパブリックAPIがあります。さらに、誰でもこれらのサービスの独自のインスタンスを作成できます。
私たちの目標は、誰もがこの分散型バックエンドに貢献できるようにすることです。つまり、1つのNoSQLクラスターや1つのビューサーバーだけが必要なわけではありません。多数のサーバーが連携して動作することが必要です。したがって、実際には次のようになります。
では、これらすべてのサービスを連携させるにはどうすればよいでしょうか?
データモデルの統合
ユーザーデータリポジトリと呼ばれる共有データモデルを確立します。
すべてのデータリポジトリには、JSONドキュメント(ここではレコードと呼びます)が含まれます。
整理のため、これらのレコードをコレクションとしてまとめます。
次に、NoSQLサービスに意見を表明して、すべてのサービスがこのデータリポジトリモデルを使用するようにします。
振り返りましょう。データリポジトリサービスは基本的にNoSQLストアのままですが、明確に定められた方法で整理されるようになりました。
- 各ユーザーにはデータリポジトリがあります。
- 各リポジトリにはコレクションがあります。
- 各コレクションは、JSONドキュメントの順序付けられたK/Vストアです。
データリポジトリは誰でもホストできるため、URLを指定する必要があります。
ついでに、レコード用のURLスキーム全体も作成しましょう。
すばらしい!また、これらのレコードをインターネット上で同期するため、本物であることを確認するために暗号署名することをお勧めします。
データフローを図に表す
大規模な分散型バックエンドをセットアップしたので、atprotoでアプリケーションが実際にどのように動作するかを図にしてみましょう。
新しいアプリを作成するので、2つのものが必要になります。アプリサーバー(APIとフロントエンドをホスト)とビューサーバー(ネットワークからデータを収集する)です。アプリサーバーとビューサーバーはバンドルされることが多いため、単に「AppView」と呼ぶことができます。まずはそこから始めましょう。
ユーザーはOAuthを使用してアプリにログインします。その過程で、ユーザーはデータリポジトリをホストするサーバーを私たちに伝え、そしてそれを読み書きする権限を私たちに与えます。
順調なスタートです。ユーザーのリポジトリでJSONドキュメントを読み書きできます。他のアプリから既にデータ(プロフィールなど)がある場合は、そのデータも読み取ることができます。シングルプレイヤーアプリを作成している場合は、すでに完了しています。
ただし、JSONドキュメントを書き込むと何が起こるかを図にしてみましょう。
これにより、ドキュメントがリポジトリにコミットされ、リポジトリをリッスンしているイベントログへの書き込みが開始されます。
そこから、イベントはリッスンしているすべてのビューサービスに送信されます。これには、私たち自身のサービスも含まれます。
書き込みを行っているのに、なぜイベントストリームをリッスンしているのでしょうか。書き込みを行っているのは私たちだけではないからです。イベントを生成するユーザーリポジトリは多数あり、それらに書き込むアプリも多数あります。
このように、分散バックエンド全体で一種の循環データフローが見られます。書き込みはデータリポジトリにコミットされ、イベントログを通じてビューサーバーに送信され、アプリケーションで読み取ることができます。
そして、このネットワークが拡張され続けることを願っています。容量を増やすだけでなく、このオープンアプリケーションネットワークで共有されるアプリケーションの多様性を高めるためです。
実用的なオープンシステムの構築
ATプロトコルは、P2Pテクノロジーと大規模システムの実践を融合します。atprotoの原型を作ったエンジニアは、IPFSおよびDatのコアエンジニアであり、Data Intensive Applicationsの著者であるMartin Kleppmannは、アクティブな技術アドバイザーです。
Blueskyを始める前に、私たちは「後退しない」という明確な要件を設定しました。ネットワークが、これまでのすべてのソーシャルアプリと同様に便利でグローバルでありながら、オープンネットワークとして機能することを望んでいました。そのため、フェデレーションとブロックチェーンを検討したときに、これらのアーキテクチャのスケーリングの限界が際立っていました。私たちの解決策は、大規模なバックエンドの標準的な方法を採用し、ピアツーピアシステムで使用した手法を適用してオープンネットワークを作成することでした。