こんにちは! 私はLewisです。Tangledでの初投稿です。 Tangledでの私の仕事は、Research & Developmentがたくさんあります。 つまり、いろいろ試して何かを発見するという意味です。今回の発見についてお話ししましょう。これが新しいTangled APIになりました。

BobbinはTangled向けの読み取り専用、API専用の AppView です。sh.tangled.*lexiconsXRPC経由で提供し、 クライアントがN個のPDSes にpingすることなく、gitリポジトリ、issue、pull request、 コメント、スター、フォローをレンダリングできるようにします。永続的なストレージはありません。知っていることはすべてRAMにのみ存在し、再起動のたびに上流からバックフィルされます。

私をはじめ多くの人が、「AppView」という用語は抽象的すぎるか、 あるいは不幸な命名だと思っています。atprotoでは、データセットは各ユーザーが所有するPersonal Data Server (PDS)に分散しているため、AppViewはデータセットをクエリできる単一のAPIであり、下流の各クライアントがすべてのPDSと接続を維持するのとは対照的です。AppViewはPDSへの負荷を軽減するために使用される多くのプログラムの1つであり、PDSが比較的安価でリソース効率の良い運用を可能にします。

TangledのAppViewに存在する問題点をいくつか挙げてみます。Bobbinに至る発見の旅が理解しやすくなるように:

  1. TangledのAppViewにはAPIがなく、SSR経由でWebクライアントとしても機能する。
  2. atprotoデータを簡単にバックフィルできないという点で脆い。
  3. 根本的なアーキテクチャが、それ自身がデータの信頼できる情報源であると仮定するWebプログラム向けに構築されている。
  4. 上記のすべてと、email -> user DIDの紐付けのようなプライベートデータが存在するため、Tangled向けのAppViewは1つだけであるべきだ。つまり、Tangledへのレイテンシはストックホルムのサーバーからの距離の関数になる。
  5. RAM危機の際にRAMを大量に消費する。

これらすべての逆を考えると、私の理想のAppViewが得られます。API専用で、簡単にバックフィルでき、簡単に分散でき、RAMに優しいプログラムです。

なぜ「API専用」なのか? 一度Tangledのデータを汎用XRPC API経由で簡単に取得できるようになれば、その上にさらに多くのプログラムを構築できます。代替フロントエンド、サードパーティクライアント、独自のターゲットダッシュボードなどがその例で、私の場合は良いCLIを可能にするためでした(ただし、それは代替フロントエンドに含まれるでしょう)。既存のTangled AppViewがWebクライアントでもあるということは、拡張可能なものが何もないということであり、スクレイピングの達人でない限り、Tangledのデータセットを世界中のPDSから取得する方法を自分で考えなければなりません。

そんなプログラムを面白半分で作ろうと考えていた頃、私は状態をどこに保存するかという危機にも直面していました。Tranquil PDSの自作埋め込みDBが新しい神秘的な方法で失敗するのではないかと冷や汗をかきながら目覚めることがあったからです。次のプログラムに耐久性があり、失敗する可能性のある状態を一切書き込まないようにするにはどうすればよいでしょうか? それに、AppViewはPDSの下流にあり、AppViewで状態を保持しようとすればするほど、現実から乖離する可能性が高くなります。AppViewが大きく誤った状態になるには、単一のレコードを見逃すだけで十分なので、AppViewが自分が知っていることを実際に真実であることと照合できることが最も重要です。

単純な人間である私は、キャッシュしてレコードを提供するだけのプログラムを作る最善の方法は、最初からディスクに一切触れないことだと考えています。再起動のたびにデータをゼロからバックフィルするようにしたいのです。その場合、現実との照合は再起動するだけで自動的に行われます! それは実現可能でしょうか? もしそのようなバックフィルに丸一日かかったらどうでしょう? それではデプロイが遅くなり、価値があるのでしょうか?

このコンセプトの最初のテストは有望な結果を示しました。Tangledのatprotoデータセット全体を約15分でバックフィルできる小さなサーバーを組み立て、 Hydrantをアグリゲーターとして使用しました。許容できるバックフィル時間は5分未満と判断したので、合理的なウォームアップ時間内でblue/greenデプロイ時に実行中のインスタンスを切り替えることが可能になります。

Hydrantは任意のatprotoデータセット向けのアグリゲーターで、ライブのfirehoseを追跡し、ネットワーク上のすべてのrepoCARをpullしてバックフィルし、websocket経由で提供します。Bobbinがしなければならないことは、接続を開き、カーソル0を要求し、結果として得られる大量のデータからインデックスを(再)構築することだけです。

DawnがHydrantを作ってくれたことに多大な感謝を! そして私の苦労を聞いて、面白半分で最適化してくれたことにも!

バックフィルを5分以内に達成した後、目標を面白半分で変更し、許容バックフィル時間を90秒以下にしました。これは今日私たちが近づいている数値で、上流のHydrantインスタンスがどれだけ温かいかによって異なり、最良の場合で30秒、HydrantがPDSからレコードをゼロからpullする災害時には20分になります。

はい、皆さんもこれらを立ち上げて、Tangled全体を20分以内で注文できます。さもなくば返金します。(€0の)

遭遇した小さな難問があります。バックフィルがまだウォーミングアップしている間にプログラムに何を提供させるかです。集計/リンクされたデータが正しくない可能性がある間にリクエストを提供させるべきでしょうか? そうは思いません。それでは、バックフィル時間中に何も提供しないプログラムにするべきでしょうか? 最悪の場合20分かかる可能性がありますが、私はそうしませんでした。代わりに、 Slingshotにポイントルックアップを委ね、少なくとも正確なデータを即座に取得できるようにしました。プログラム自体がまだそのデータを見ていない場合でもです。

Slingshotはatprotoレコード&アイデンティティのための素晴らしいエッジキャッシュです。Bobbinは単一レコードとアイデンティティのルックアップをSlingshotに依頼し、新しく生まれたBobbinが自身のインデックスがウォームアップする前に個別のクエリに正確に回答できるようにします。Slingshotは microcosmプロジェクトの一部で、コミュニティ運営のatprotoインフラストラクチャのバンドルです。作ってくれた Figに感謝します!

Bobbinになっていくプログラムは、Tangledのatprotoデータセット全体を約200MBのRAMで保持できましたが、ある程度の圧縮で100MBになりました。さらに圧縮できる余地はまだあります。「プラットフォーム全体のソーシャルレイヤー全体のデータがこんなに少ないなんてすごい!」と皆さんは思うかもしれませんが、逆にこれは今日以降、データセットが最も小さくなる可能性が高いことを忘れないでください。スペースの節約は本質的です。

BobbinはSlingshotをリアルタイムのレコード/アイデンティティリゾルバーとして使用し、RAMにまだ保持していない、またはHydrantから必ずしも受信していないものに使用します。Figの作品は素晴らしいですが、Slingshotに依存したのは時間を節約するための妥協でした。Bobbinに対する主要なアーキテクチャ変更の1つは、それをインライン化して、BobbinがSlingshotにpingする必要がなく、同じデータをより速く取得できる方法を見つけることです。

AppViewプログラム自体にHydrantの埋め込みインスタンスを投入し、特定のatprotoデータセットの提供をHydrantデータの薄いラッパーにする tempted になるかもしれません。しかし、私はプログラムのインスタンスを数百個立ち上げることを簡単にしたいのです。何百ものHydrantが常にPDSにpingするのはかなり無駄です。1つのHydrantインスタンスは、汗をかくことなく何百ものBobbinを提供できます。

Knot関連のデータにはHydrant/relayに相当するものが存在しないため、BobbinはKnot関連のリクエストを指定されたknotに直接プロキシします。knotstreamアグリゲーターが必要だと思います。おそらくHydrantのプラグインとして、両方を提供するものになるでしょう。BobbinとKnot Mirrorは1つのサービスに統合すべきだと思いますが、それは私の意見です。

「ステートレス」なAppViewでは、データベースとその問題(マイグレーション、"真の"データセットとわずかに異なる場合の本番マッサージなど)を心配する必要がありません。機能の変更/追加をしたいときはいつでも、Bobbinを再起動するだけで操作は完了します。もう1つの利点は、Bobbinが「クラウドネイティブデプロイメント」(企業が言うところの)に適していることです。TangledのフラッグシップインスタンスはCloudflare Containers上で実行されています。

以上のことを述べましたが、私は必ずしもBobbinがディスクに一切触れないという考えに固執しているわけではありません。1つの可愛い改善策として、RAMに保存されたデータの内容を1時間ごとにスナップショットとしてダンプし、起動時に差分をバックフィルするというものがあります。しかし今は、Bobbinが執筆時点で200MBで健全に実行できることを考えると、この道を進み続ける余地があると思います。また、私の元の要件であるRAMに優しいという点は今も満たされていますが、重くなりすぎた瞬間がBobbinが実行時にディスクに一部を動的にオフロードするポイントになります。「重くなりすぎ」とはどのように定義するのか、と皆さんは聞くでしょう。私は心の中を見て、1GBのRAMは無駄、10GBは受け入れられないと告げています。Bobbinはユーザーにもサービスを提供しなければならず、各APIリクエストはTangledデータセットの保存以外にもRAMにさらに圧力をかけます。

以上です! これで、ディスクストレージなし、サブ90秒のバックフィル、APIリクエストを提供する小さなエンジンとしての楽しいAppViewができました。これを使えば、誰でもTangledデータセットを使ってプログラムをより簡単に構築できます。

Bobbinのインスタンスは api.tangled.orgにあり、自分のものをホストすることも簡単だと思います。Bobbinのソースは 私たちのモノレポにあります。