インフラ・DevOps
分散システムエンジニアのためのATProto
ATProto for Distributed Systems Engineers (atproto.com)
要約
この記事は、AT Protocolがどのようにしてスケーラブルで分散型のバックエンドシステムを構築するかを、従来のWebアーキテクチャと比較しながら解説しています。従来の単一SQLデータベースや、それに続くNoSQLとストリーム処理を用いたアーキテクチャの限界を説明した後、AT Protocolがどのようにしてこれらのサービスを公開APIとして提供し、誰でもインスタンスを構築・参加できる分散型ネットワークを形成するかを説明します。共有データモデル(ユーザーデータリポジトリ、レコード、コレクション)と、データフローの仕組み(イベントログ、ビューサーバー)に焦点を当てています。
全文翻訳
ストリーム処理を用いたバックエンドを構築したことがあるなら、これから探求するシステムの種類に馴染みがあるでしょう。もしそうでないなら、心配いりません!ステップを踏んで説明します。
従来のWebバックエンドのスケーリング
古典的で理想的なWebアーキテクチャは、アプリサーバーの後ろにある「単一の巨大なSQLデータベース」です。アプリはデータベースと通信し、フロントエンドからのリクエストを処理します。
アプリケーションが成長するにつれて、パフォーマンスの限界に達するため、スタックにキャッシュを追加します。次に、シャーディングとレプリカを通じてデータベースを水平にスケーリングするとしましょう。これはかなり良いですが、私たちは何億ものユーザーを持つソーシャルネットワークを構築しています。このモデルでさえ限界に達します。
問題は、私たちのSQLデータベースが「強く一貫性がある」ということです。これは、システム全体で状態が一様に同期されていることを意味します。強い一貫性を維持することはパフォーマンスコストを伴い、それがボトルネックになります。システムを「最終的な一貫性」を使用するように緩和できれば、より大きくスケーリングできます。
まずNoSQLクラスターに切り替えます。これはスケーリングには良いですが、SQLなしではクエリの構築が難しくなります。SQLデータベースには、JOINや集計クエリのような多くの便利な機能があることがわかります。実際、私たちのNoSQLデータベースは単なるキーバリューストアです。機能の記述が面倒になってきています!
これを修正するために、データセットの事前計算されたビューを生成するプログラムを記述する必要があります。これらのビューは、基本的にキャッシュされたクエリのようなものです。正規化されたデータをこれらのビューに複製して、非常に高速にします。これらをビューサーバーと呼びます。
次に、ビューサーバーをNoSQLクラスターの正規化されたデータと同期させ続けることが難しいことに気づきます。ビューサーバーがクラッシュして更新を見逃すことがあります。ビューが確実に最新の状態に保たれるようにする必要があります。
これを解決するために、イベントログ(Kafkaなど)を導入します。そのログは、NoSQLクラスターへのすべての変更を記録し、ブロードキャストします。ビューサーバーは、再起動が必要な場合でも、更新を見逃さないように、そのログをリッスンし、再生します。
これでストリーム処理アーキテクチャにたどり着きました。さらに多くの詳細をカバーできますが、今はこれで十分です。良いニュースは、このアーキテクチャがかなりうまくスケーリングすることです。私たちは強い一貫性を犠牲にし、時には読み取りクエリが最新のデータバージョンから遅れることがありますが、サービスは書き込みをドロップしたり、不正な状態に入ったりしません。
ある意味で、私たちはデータベースを裏返しにしてカスタムビルドしました。正規化されたストレージをNoSQLクラスターに単純化し、ビューサーバーで独自のクエリエンジンを構築しました。構築するのははるかに不便ですが、スケーリングします。
高スケールのバックエンドの分散化
AT Protocolの目標は、ユーザーアカウントやコンテンツを含むバックエンドが状態を共有できるように、アプリケーションを相互接続することです。どうすればそれができるでしょうか?図を見ると、システムのほとんどが外部世界から隔離されており、アプリサーバーだけが公開インターフェースを提供していることがわかります。私たちの目標は、この隔離を打破し、他の人々が私たちのNoSQLクラスター、イベントログ、ビューサーバーなどに参加できるようにすることです。
これがどのように見えるかです。
これらの内部サービスのそれぞれが、外部サービスになりました。それらは誰でも利用できる公開APIを持っています。さらに、誰でもこれらのサービスの独自のインスタンスを作成できます。私たちの目標は、単一のNoSQLクラスターや単一のビューサーバーだけでなく、これらのサーバーの多くが連携して動作するようにすることです。
だから、実際にはもっとこのようになります。
これらのサービスすべてを連携させるにはどうすればよいでしょうか?
データモデルの統一
「ユーザーデータリポジトリ」と呼ばれる共有データモデルを確立します。各データリポジトリにはJSONドキュメントが含まれており、これを「レコード」と呼びます。整理のために、これらのレコードを「コレクション」にバケット化します。
次に、NoSQLサービスに意見を述べ、それらがすべてこのデータリポジトリモデルを使用するようにします。覚えておいてください:データリポジトリサービスは依然として基本的にNoSQLストアですが、非常に特定の構造で編成されています。
各ユーザーはデータリポジトリを持っています。
各リポジトリにはコレクションがあります。
各コレクションは、JSONドキュメントの順序付けされたキーバリューストアです。
データリポジトリは誰でもホストできるため、URLを与える必要があります。そのついでに、レコードにも完全なURLスキームを作成しましょう。素晴らしい!また、これらのレコードをインターネット全体で同期させるので、それらが本物であることを知るために暗号署名するのが良いでしょう。
データフローの追跡
高スケールの分散バックエンドを設定したので、atprotoでアプリケーションが実際にどのように機能するかをマッピングしましょう。新しいアプリを作成するので、2つのものが必要になります:アプリサーバー(APIとフロントエンドをホストする)とビューサーバー(ネットワークからデータを収集する)。アプリサーバーとビューサーバーをバンドルすることがよくあるため、単に「Appview」と呼ぶことができます。そこから始めましょう。
ユーザーはOAuthを使用してアプリにログインします。その過程で、彼らは自分のデータリポジトリをホストしているサーバーを私たちに伝え、それに読み書きする許可を与えます。これで順調です。ユーザーのリポジトリ内のJSONドキュメントを読み書きできます。もし彼らが(プロフィールのような)他のアプリからのデータを持っているなら、それも読むことができます。
シングルプレイヤーアプリを構築していたなら、これで完了です。しかし、JSONドキュメントを書き込んだときに何が起こるかを追跡しましょう。これはドキュメントをリポジトリにコミットし、リポジトリをリッスンしているイベントログへの書き込みをトリガーします。そこから、イベントはリッスンしているすべてのビューサービスに送信されます。それには私たち自身のものも含まれます!
書き込みを行っているのに、なぜイベントストリームをリッスンしているのでしょうか?なぜなら、書き込みを行っているのは私たちだけではないからです!多くのユーザーリポジトリがイベントを生成し、多くのアプリがそれらに書き込んでいます!
したがって、書き込みがデータリポジトリにコミットされ、イベントログを通じてビューサーバーに発行され、そこでアプリケーションによって読み取られるという、分散バックエンド全体での一種の循環データフローを見ることができます。そして(願わくば)このネットワークは、容量を追加するだけでなく、このオープンアプリケーションネットワークで共有される、より多様なアプリケーションを作成するためにスケーリングし続けます。
実践的なオープンシステムの構築
AT Protocolは、p2p技術と高スケールシステムの実践を融合させています。私たちの設立エンジニアは、コアIPFSとDatエンジニアであり、Martin Kleppmann(Data Intensive Applicationsの著者)はアクティブな技術アドバイザーです。Blueskyが開始される前に、「後戻りはしない」という明確な要件を設定しました。私たちは、ネットワークがそれ以前のすべてのソーシャルアプリと同じくらい便利でグローバルに感じられるようにしたかったのです。同時に、オープンネットワークとして機能するようにしました。
だからこそ、フェデレーションとブロックチェーンを見たとき、それらのアーキテクチャのスケーリング限界が際立っていたのです。私たちの解決策は、高スケールバックエンドの標準的な実践を取り入れ、次にピアツーピアシステムで使用したテクニックを適用してオープンネットワークを作成することでした。
さらに学習する準備はできましたか?仕様、ガイド、SDKはここで見つけることができます。