この動画は、人気のAIチャットサービスT3 ChatがMySQLからConvexへのデータベース移行時に発生した大規模システム障害について、創設者のTheoが包み隠さず詳細に解説した技術解説動画である。移行計画から実際の障害発生まで、そしてConvexチームとの協力による復旧作業まで、リアルな大規模サービス運用の現実を赤裸々に語っている。WebSocket接続の問題、クエリ負荷の急増、バックオフロジックの不具合など、複数の技術的要因が重なって起きた障害の根本原因分析と、今後の改善策まで含む貴重な事例研究となっている。
私のチャンネルをしばらく見ている方なら、ほぼ確実に知っている2つのことがあります。1つ目は、私がT3 Chatのデータベースを頻繁に変更し過ぎていることです。そして2つ目は、私がダウンタイムを本当に、本当に、本当に嫌っているということです。そのため、T3 Chatで初の大規模障害が発生したということで、この動画を作るのは少し悲しいことです。
過去には、私が変更を加えている間に数分間、数名のユーザーにとってサービスが停止するという軽微な問題はありました。しかし、先日の日曜日のように、数時間にわたってサイトがほぼ完全に使用不能になるような事態は過去に一度もありませんでした。この件について本当に透明性を持って率直にお話ししたいと思います。これは受け入れられないことです。
私たちはアップタイムを非常に真剣に考えており、今後皆さんが必要な時にT3 Chatを使用し、信頼できるよう、あらゆる手段を講じています。この動画の収録を始めながら必要な素材を準備していたところ、Twitterも同じくダウンしていることに気づきました。文字通りフィードに行って投稿を見ることができません。
どうやら私はTwitterに一度も投稿したことがないということになっているようですが、皆さんがご存知の通り、それは確実に間違いです。ありがたいことに、直接リンクがあれば、まだ大体動作するようです。そして非常に重くて壊れたウェブサイトで、この障害についての責任を取り、何が問題だったか、今後どのように防ぐ予定かを説明した私の元の投稿と、Convexの友人たちからのブログ投稿を見つけることができました。
この障害に対してConvexに責任を負わせたくはありませんが、彼らの側で正しく実装されていないものがあり、それが原因となったのは事実です。これは非常に興味深い動画になると思います。いつものような「なぜこの技術がクールなのか」や「このタイプのエラーを防ぐ方法」ではありません。むしろ、私たちがこの移行をどのように計画し、その過程でどのような問題に遭遇し、実際にゴーライブボタンを押した時に何が問題となって日曜日の問題を引き起こしたのかの詳細な分析になります。
数十万のユーザーを抱える実際の負荷での実際のエンジニアリング作業の詳細に興味があるなら、これは興味深い深掘りになるかもしれません。とはいえ、これは私たちに多額の費用と時間を要し、Convexの請求書も今や実際に支払わなければならないものになっています。
そのため、費用をカバーするために今日のスポンサーからの短いメッセージが必要で、その後すぐに本題に入ります。OpenAI、Anthropic、Cursorの共通点を知っていますか?ヒントをあげましょう。それはAI企業だということではありません。答えは、彼らが皆今日のスポンサーであるWorkOSを使っているということです。本当にそうなんです。彼らのサイトのいずれかを見れば確認できます。
CursorはWorkOSからのストック・サインインを使っており、これは面白いことですが、目的は十分に果たしています。そしてOpenAIとAnthropicの両方が、WorkOSの私のお気に入り機能の1つである管理者ポータルを使用しています。Anthropicの公式ドキュメント内でURLを見ることもできます。彼らは全く隠していません。
なぜこれらの企業やVercel、Fanta、Carta、FAL、Repletなど多くの企業がWorkOSに依存しているのでしょうか?それは彼らがエンタープライズ認証を正しく行ったからです。多くの企業が使おうとしている会社を構築した者として、WorkOSから始めていればよかったと思いますし、今まさに移行を計画しています。その管理者ポータルは素晴らしいのです。
大企業にあなたのサービスを採用させようとしているなら、多くの方はまだこれを経験したことがないかもしれませんが、私は経験があります。SAMLからOktaまで、覚えることもできないような他の奇妙な略語を、異なる会社間で設定しようとすることは、各社が独自の奇妙で異なる方法でAP全体に設定しているため、最悪の敵にも望まないことです。
WorkOSを使用している場合、リンクを送るだけで、彼らは自分たちのビジネスで好きなように設定することができます。相手側のIT担当者が特定の管理者ポータルを既に使用したことがある可能性が高いです。なぜなら、それがこれほど多くの企業で使用されているからです。
ちなみに、コストもそれほど悪くありません。最初の100万ユーザーまで無料というのは、かなり驚くべきことです。真剣なビジネスに出荷する準備ができているなら、soyv.link/worksで今日WorkOSをチェックしてみてください。
それでは、非常に高いレベルから始めましょう。何が問題だったのでしょうか?この障害とは何だったのでしょうか?ユーザーがサイトに行ってエラーやページをブロックするものを見たということではありませんでした。
問題は3つの側面がありました。主に、チャットが読み込まれないという問題でした。ただそこに座っていても何も読み込まれませんでした。新しいチャットの作成もほとんど機能せず、正直なところ、すべてが非常に遅れていました。その理由は、Convexで接続するWebSocket接続レイヤーに問題があったからです。
つまり、データを送信する実際のものは、単なる従来のHTTPリクエストではありません。Convexでは、クライアント上でWebSocket接続を作成し、クエリを購読します。そのため、サブスクリプションを作成した時に初期データを取得し、それが変更されたり、サービス上で他のことが発生したりした時に残りを取得します。
問題は、その接続レイヤーが完全に倒れてしまったことでした。この状況に至った問題を理解するために、この移行の簡単な概要とそれが私たちにとってどのようなものだったかを説明することで、理解しやすくなると思います。私が以前行ったデータベース変更についての動画からこの一部を認識するかもしれませんが、これはなぜこれを行っているのかの概要になります。
Convex移行前は、すべてのデータを従来のMySQL DBに保存していました。このDBはPlanetScaleにありました。私は今でもPlanetScaleを深く愛しています。今現在、彼らが私たちにとって適切な製品であることを願っています。問題は、これすべてを可能にするために、PlanetScaleの上で実質的にConvexを再構築している自分を発見したことで、それは2.5人から3.5人のチームにとって維持可能ではありませんでした。
Convexはデータ同期専門の本当に才能のある人々からなるもっと大きなチームで、私は彼らが持っているものが欲しくて、T3 Chatで以前のデータベースの上に構築したすべてのものを再構築するよりも、そこに移行する方がずっと簡単でした。理解すべきもう1つの重要なことは、MySQL DBからConvex同期エンジンへの切り替えは、データが保存される場所を変更するだけではないということです。
これは実質的にアプリ全体の書き直しでした。T3 Chatは約25,000行のコードです。私のPRはそのうち10,000行を変更しました。これはほぼ書き直しでした。そのため、これはデータストアを変更しただけではありませんでした。これは完全に新しいコードベースでした。そのため、データが一方のDBに行くか他方に行くかのフィーチャーフラグを単純に設置することはできませんでした。
これは完全に異なるデプロイメントで、ユーザーにとって完全に異なる体験でした。理論的には、どのトラフィックが新しいものに行き、どれが古いものに行くかを分割するURLにミドルウェアを置くことはできました。しかし、私が本当にやりたかったのは、日を選んでそれ以降は全員が新しいコードベースにいるというハードカットオフで、ユーザーがサインインしたり初めてページを開いたりした時に、その時点でConvex同期エンジンにデータを引っ張ってくることでした。しかし、それはいくつかの問題につながりました。
私がここで持っていた初期実装はかなり初歩的でした。理解すべき部分があります。従来のMySQL DBがありました。Convex同期エンジンがあります。VerscelのNext.js tRPCバックエンドとエンドポイントもあります。そして、ユーザークライアント体験もあります。これらが存在する4つの部分です。すべてのユーザーの古いデータを持つ古いMySQL DBがありました。
以前の動作方法は、ユーザー体験と従来のDBの間にバックエンドがある状態でした。ユーザーは同期データのリクエストを行います。リクエストはDBに行き、データを取得するためのDrizzle呼び出しのようなものを行います。これはかなり怠惰でした。通常、ユーザーとしてのすべてのデータを取得するだけでした。
つまり、すべてのスレッドとすべてのメッセージです。その後、すべてのデータを送り返し、それがあなたのところに戻り、IndexDBに保持されます。IndexDBはブラウザでデータを保存するために使用できるブラウザ内のデータストアです。以前はすべてのデータがブラウザに保存されていましたが、異なるブラウザで物事を行おうとする際に、Safari を動作させ、マルチタブを動作させるなど、非常に多くの問題に遭遇しました。
IndexDBは常に苦痛の源でした。IndexDBを適切に動作させることだけを試みている会社全体があります。使用可能にしてくれたDexieに感謝します。私が深く愛する素晴らしいライブラリでした。APIがひどいので、本来よりも長くIndexDBを使用するように私をほぼ騙したほど素晴らしかったです。
しかし、これが長い間私たちのセットアップでした。Convexが関与すると事情は大きく異なり、最初はより複雑に見えますが、そうではないことを約束します。人々も順序が右から左になっていることで混乱していたので、もう少し論理的になるように切り替えます。
しかし最大の違いは、以前はユーザークライアント、次にバックエンド、次に従来のDB、そしてDBがバックエンドの後ろにありました。Convexは、どちら側にも置くことができますが、適切に使用している場合に期待される場所はこの間です。必要に応じて、バックエンド機能があるので、Convexを全体のバックエンドとして使用することもできます。
現在T3 Chatで動作する方法は、スレッドデータのクエリでスレッドを取得し、Convexで記述した適切なTypeScript関数を呼び出し、データを取得するためにデータベースを呼び出してからそれらのスレッドを送り返します。この取得スレッド呼び出しはサブスクリプションを作成し、データを送り返し、別の変更が発生した場合、例えばバックエンドがConvexにスレッド名が変更されたという更新を送信した場合、Convexがウェブソケット経由で接続されているので、変更をユーザーに送信し、それが更新されたスレッドデータとなります。これが魔法です。
多くのことをずっとシンプルにしました。バックエンドがユーザーとデータベースの両方に適切なデータを送信し、すべてを同期に保ち、最善を期待する代わりに。削除のようなものでは、エッジケースの量は非常に複雑です。なぜなら、クライアントでスレッドやメッセージを削除したが、サーバーがまだ結果を生成している場合、何が起こるでしょうか。
そこでの適切な状態は何でしょうか?そして以前削除したスレッドを持つ別のデバイスを開いた場合、それを同期し直すべきでしょうか?それはすべてどのように動作するのでしょうか?削除されたメッセージが再表示されたり、生成されたメッセージが途中で止まって再開されなかったりするようなことです。
すべてのタイプの問題が非常に持続的でした。これが複雑だった理由は、以前はユーザーがメッセージ生成のリクエストを行い、バックエンドが実際にあなたに送信し、データベースに送信する必要があったからです。より安定であることがわかったのは、あなたに送信してから、その後DBに送信することでした。
明らかに、実際にはバックエンドを使用してそれを行いますが、私が言いたいのは、メッセージがあなたに送信され、その後DBに送り返すために別の関数が呼び出されるということです。クライアントがダウンした場合、バックエンドはもうどこにも送信しません。すべてがひどいです。しかし、変更されるたびにDBに送信すると、適切なスループットはばかげています。
ここで適切なバランスを取るのは本当に迷惑でした。Convexはそれを大幅に簡単にしました。データを取得すると、購読されます。バックエンドはConvexに変更を書き込むことができ、アップデートを取得するだけです。これを愛しています。多くのことをずっと簡単にしました。それでも、メッセージを生成する際に得られる法外なスループットを処理することはできませんでした。なぜなら、これらのメッセージは生成され、これらのモデルの一部では1秒間に300回更新されるからです。
Geminiのように、1秒間に200から300トークンを行うことができます。すべてをDBに書き込み、すべてを同期すると、変更のたびに行全体を取得します。それは非現実的な量のデータです。私たちが落ち着いた場所は、バックエンドがメッセージを楽観的更新としてストリーミングするが、最終状態をConvexに送信して永続化される、素晴らしいハイブリッドモデルです。
結果はずっときれいで、全体的に本当に良い感じですが、それは私たちがここで話すためのものではありません。Convexを愛する理由について完全に別の詳細分析をするかもしれません。コメントで興味があるかどうか教えてください。しかし今は、移行について話したいと思います。
現在、すべての部分があります。移行で物事がどのように動作するかは、少なくとも最初の試みです。ユーザークライアントは「移行したい」と言うリクエストをバックエンドに送信します。その後、いくつかのことを行います。まず、従来のMySQL DBに行き、すべてのデータを取得します。そのデータを送り返します。明らかに、これはSQLリクエストです。それがその動作方法です。ユーザーデータ。
その後、データをチャンク化し、添付ファイルのチャンクから始めて、すべてのチャンクを一つずつ書き込みます。添付ファイルチャンクを行い、複数を行います。100を超える添付ファイルがある場合、100のグループにチャンク化します。その後、スレッドチャンクを行い、その後メッセージチャンクを行い、これらすべてが完了したら、移行を完了する最後のパスを行い、これはConvexでこのユーザーが移行を完了したというフラグを設定するだけです。
すべてを考慮すると比較的シンプルです。私のすべてのテストでは、本当に大量のデータであっても、これは素晴らしく動作していました。それがすべて完了すると、移行完了というユーザーへの同期イベントを取得します。そして今、T3 Chatの使用を開始できます。これをすべて動作させることができました。かなり満足でした。ゴーボタンを押しました。
最初に起こったことは、多くのユーザーが移行が継続してループする奇妙な状態でスタックすることでした。私は以前のデータベース変更動画でこれについて少し話しましたが、何が問題だったかのTLDDRは、本当に古いバージョンのT3 Chatで初めてサインインしたユーザーのために持っていたJWTに、複数の異なるIDが含まれていたことです。
subjectがあり、これはユーザーIDでした。propertiesもあり、propertiesはIDを持つネストされたオブジェクトで、これもユーザーIDとメールなどでした。識別子としてsubjectを使用していました。得られていた問題は、ユーザーが移行を実行し、すべてがうまくいっているように見えるが、その後移行を続けようとし続けることでした。
これが起こる理由は、subjectが常に正しいIDではなかったからです。時々、それは間違ってフォーマットされていました。これは、私たちが使用している認証ライブラリであるOpenAuthのバグが原因です。独自の認証をロールするのは、これらの問題に遭遇し、なぜそれをしたのか疑問に思うまでは本当に楽しいものです。このバグのために失った膨大な時間を考えると、他の認証プロバイダーの価格を喜んで支払ったでしょう。
率直に言って、価値がありませんでした。このプロジェクトのために独自の認証をロールしたことを後悔しています。率直に。OpenAuthは素晴らしいライブラリです。実際にかなり楽しんでいますし、その時の選択としては正しいものでした。しかし、このバグは私に多くの時間とお金を要し、言葉にするのが難しいほどです。それが最初の移行が失敗した理由です。
常に正しくフォーマットされていたこのネストされたプロパティIDを使用し始めました。それは多くの問題を修正しましたが、全員に対してこれを単純にオンにしたくないほど心配でした。それがT3 Chat betaを導入した理由で、完全に異なるコードベースであることを覚えているので、異なるURLに行ってオプトインできました。beta.t3に行きます。
ここに行くと、最初に行った時に移行し、データを移行していると言う小さな読み込みスピナーがあります。これらすべてのことを行い、準備が整います。それははるかに良くなりました。多くの人に移行してもらいました。トラフィックを注意深く監視しました。実際に、信じられないことに、約4分の1のユーザーがベータに移行し、これは素晴らしいことでした。
T3 Chatベータを試すために時間を取ってくれたすべての人に大いに感謝しています。これすべてを可能にしたパフォーマンス特性の理解に大いに役立ちました。それは、移行を行うためのオンスイッチを押すのにかなり良い状況にあるという自信を与えてくれました。そこで、再び試しました。
再び失敗しました。約5分間ダウンしましたが、その障害はベータを完全にダウンさせました。物事が回復する間、ベータは約1時間ダウンしていましたが、古いビルドに戻しただけでした。私たちがそれを理解している間に2回これに当たったため、数人が2回リフレッシュしなければなりませんでした。
しかし、今回は調査するためのはるかに多くのデータがありました。2回目に移行を行った時に発見したのは、問題を引き起こしている膨大なスループットのミューテーションがあったことです。変更が出た時に同時にウェブサイトに500人がいた場合、500人全員が同時にこれを実行します。スレッドを最初に、次にメッセージ、次に完了する以外にキューイングを行っていませんでした。
しかし、10人のユーザーが同時にそれを行った場合、10人全員が一度に行きます。ベータでは、誰かがチャットでこれをキャッチしました。ベータを行った方法は、ユーザーがベータにゆっくりとロールインしたため、実質的にローリングアップデートになりました。したがって、そこのトラフィックは、代表的であったにもかかわらず、ベータからトラフィックを単純に4倍にした場合、すべてが完全に良くなったでしょう。
しかし、5分間ベータからトラフィックを4倍にしませんでした。ベータからトラフィックを400倍にし、そのスループットは多すぎました。少なくともそう思いました。これは実際に事態が面白くなり始める場所です。後でそこに到達します。なぜなら、私たちもConvexも、この旅の多くのポイントで反証されなければならない悪い仮定を持っていたからです。
これは、私たちがこれらの移行をキューイングする必要があることを認識するのに十分なほど心配なことでした。すべてを一度に実行するのではなく、並列化し、同時に実行できる数に制限を設ける必要がありました。おそらく最初からそうすべきでしたが、正直に言って、このハードカットを行い、先に進み、それについて心配する必要がないと思っていました。間違っていました。
Convexと協力していた時、彼らは実際に非常にクールで、これをずっと簡単にしてくれた、彼らがコンポーネントの1つとして持っていたパターンを私に紹介してくれました。そのパターンはworkpoolコンポーネントです。React開発者である私たちにとってコンポーネントという言葉は混乱しますが、コンポーネントに対する彼らのアイデアは、異なるタイプの作業を行うためにConvexコンテキスト内で動作する、彼らが構築したこれらの事前に作られたユーティリティです。
workpoolは非常にクールです。アプリ設定で定義することでworkpoolを作成します。現在、components.migration workpoolがあります。これは、私のアプリ定義convex設定で定義された存在するものです。migration workpoolという名前で定義されたworkpool。これはすべて存在します。
最大並列制限が10のmigration workpoolを定義するこのような他の場所でこれを呼び出すことができます。したがって、これは一度に10個のことしか実行できません。より多くのものをキューアップしようとした場合、他のすべてがキューに入れられます。そして今、移行すべきことを検出した時にユーザーが押すエンドポイントであるQ migration workがあります。
私がfixを設定したO関連の方法のために決して起こるべきではないが、Oでない場合はthrowします。そして今、彼らは特定の引数セットでworkpoolで行う作業をキューアップするinq actionでworkpoolを呼び出します。これはConvexなので、この内部移行、これは私が定義したAPIで、TRPCで行うようにcommand clickしてそれに行くことができます。非常に良いです。
もちろん、すべてタイプセーフでもあります。Do migration actionは、バックグラウンドでこれを実行し、移行を完了しないことができるように、ユーザーIDファイナライズを取る内部アクションです。以前はサーバーに保存されていなかったため、ユーザーがそれを送信して移行を開始できる方法が必要だったユーザープロンプトカスタマイゼーションとユーザー構成もあります。
その後、Vercelの私のバックエンドからデータを取得しますが、これは少し迷惑です。Convexバックエンドと私のVercel上のバックエンドとの関係は、Convexでまだ私のお気に入りではない唯一のことです。JavaScriptなので良いです。したがって、デプロイしているURLの環境変数を与えて動作させるような愚かなことをすることができます。
しかし、開発では、これは迷惑でした。実際にまだターミナルでEnrokタブを開いたままにしています。下の1番を見ると、Enrokがあります。これは、移行しなければならないデータを取得するためにConvexにバックエンドを呼び出させる方法だったからです。そのためのEnrok警告をスキップするヘッダーもまだ残っています。
失敗した場合のログがあるようにエラーアウトします。成功した場合は、Super JSONパースで解析します。日時が正しい形式になるように、通常のJSONの代わりにSuper JSONを使用します。数値から日付に変換する必要がありません。行うことがどれくらいあるかをログに記録します。そして今、このアクションでは、各チャンクを通過して移行します。
各スレッドチャンクを通過し、移行します。各メッセージチャンクを通過し、移行します。プロンプトカスタマイゼーションがある場合、それも含めます。ユーザー構成がある場合、それも含めます。そして完了します。ユーザー構成で移行が完了したことを設定するwrap-up migration関数を呼び出すことで、finalizeがtrueに設定されている場合は完了します。非常にシンプルです。
Convexでこのタイプのコードが何らかのクレイジーなカスタム構文ではないことは実際に非常に良いことです。これはすべて、この件のforループがその件を行う場合です。TypeScriptを書いているだけで、意味のあるパフォーマンスヒットを受けていないのがConvexの私のお気に入りの1つです。本当に、本当に良いです。
これをworkpoolに入れたので、この移行アクションは一度に10個しか実行できません。新しいものがキューアップされた場合、他の10個が完了するまでキューで待機します。同時に10個以上実行することは不可能です。ローンチで十分心配だったので、実際に3まで下げてから出荷し、動作しました。
少なくともそう思いました。約5分後、パフォーマンスが再び低下しました。今回は本当に悪い気分でした。ここで私が忘れていた追加の詳細があります。それは、T3 Chatのトラフィックが1日と週を通して大きく変動することです。平日の昼間は、トラフィックは圧倒的に最も高くなります。しかし、週末の真夜中頃は、トラフィックがずっと少なく、約半分になります。
そのため、土曜日の夜の真夜中頃に移行を行う予定でした。その後、データを再確認したところ、チェックした時に最低点にいることを確認しました。これは午後5時頃でした。UTC時間を見ていたことが判明し、PostHogがPSTに設定されていると確信していたにもかかわらずです。
低点はUTC真夜中で、これは私の時間で午後6時頃でした。最もスムーズなローリング移行が可能になるように、最低トラフィックのウィンドウ中に移行したかったので、その時に移行する決定を下しました。しばらくはうまくいきましたが、すぐにユーザーが問題を抱え始めました。
人々はWebSocketレイヤーに接続できませんでした。クエリが非常に遅くなっていました。本当にひどくなっていました。数字を見た時、本当にひどく見えました。クエリスループットがばかげていました。そして最も重要で、これが本当に怖い部分でしたが、ダッシュボードに行った時、ラグアウトしてクラッシュしました。Convexダッシュボードは救世主です。
とても、とても良いです。したがって、それが動作しないのは恐ろしいことでした。ユーザーにとって何が機能しているか、していないかについて全く見当がつかないような気がしました。そこで、再びロールバックする決定を下しました。これはConvexに移行する3回目の失敗した試みで、がっかりしました。他の試みとは異なり、Convexの創設者の一人であるJamieは、家族と映画を見に出かけていたため、手伝うことができませんでした。とても悪い気分でした。
それにもかかわらず、彼は実際に映画から出て、ベンチに座って、彼の携帯電話で私たちと、もう一人の共同創設者であるJamesと一緒にデバッグしました。そして非常に重要な詳細を発見しました。クエリスループットが最大の問題の1つであることが判明しました。これが負荷でした。午後7時30分頃に移行を行い、スパイクがあり、その後落ち着き、その後大幅にスパイクし、それがクラッシュした時でした。
私たちは確実に適切な制限内にいました。特に今は。以前は、書き込みミューテーションのスループットが問題だとかなり確信していました。それは確実にある程度の問題でしたが、私たちが見ていた問題を引き起こしている問題ではありませんでした。スループットのためにクエリが0にフラットラインになった問題を引き起こした問題では確実にありませんでした。
問題はもっと微妙なことがいくつかであることが判明しました。Convexの動作方法は、get thread関数を呼び出した時にスレッドを取得し、現在そのスレッドセットを購読していることです。変更が起こった場合、更新が下がってきます。移行が実行されているためにこれらのスレッドがすべて絶えず更新されている場合はどうなりますか?そのクライアントに送信されるデータがはるかに多くなり、この応答内でそれらの行の1つを書き込むたびに、応答全体が送り返されるため、はるかに多くのクエリが発生します。
実際に、私が行った別の変更で自分自身のために事態をはるかに悪化させたことが判明しました。私が非常に気にしていることの1つは、本当にキビキビしたナビゲーションです。サイドバーでスレッドをクリックした時に、即座にメッセージを表示してほしいのです。これを解決した方法は、上位20のスレッドを取得し、それらすべてに対してmy thread prefetcherを返すこの関数を持つことでした。
my thread prefetcherは、そのスレッドのメッセージに対するuse session queryで、nullを返します。これは、何もレンダリングしない、サイドバーにあるスレッドを購読するためだけに存在するコンポーネントです。ホバープリフェッチングなどでファンシーなことをできました。したくありませんでした。
これは、圧倒的に最もシンプルで最もキビキビした解決策でした。しかし、今は上位20のスレッドへの20のサブスクリプションがあります。そして私たちは古いものから新しいものへと移行していました。移行がこのように進行している時にクライアントにとってこれがどのように見えるかを見てみましょう。すべての添付ファイルを移行します。何も起こりません。クール。
次にスレッドを移行します。100のスレッドを移行します。上位20が購読されます。上位20がメッセージを取得するクエリを作成し、その後さらに100のスレッドが入ってきます。今度は上位20が変わり、メッセージを取得する新しい20のクエリです。これは、すべてのスレッドが移行されるまで起こります。したがって、スレッドのチャンクが入ってくるたびに20のクエリが発火または更新されます。
しかし、それは最悪の部分ではありませんでした。最悪の部分はメッセージチャンクに移行した時でした。なぜなら、それらのメッセージチャンクがそれらの上位20のスレッドのいずれかに触れた場合、それらの上位20のスレッドリスナーが待機しており、すべてのメッセージ書き込みがそれらのいくつかを更新するからです。したがって、メッセージチャンクが何百もの追加クエリを発火させ、これはすべて移行が実行されている間にバックグラウンドで起こっていました。
したがって、ユーザーとしてのあなたは、取得されているこのデータのいずれからも恩恵を受けていませんでした。まだ必要のないものを購読していただけで、それが私たちが必要としなかった法外な量のクエリトラフィックを引き起こしました。なぜ以前にこれをキャッチしなかったのでしょうか?これほどひどく進行していることに気づかなかったのはなぜでしょうか?
以前に話していたこの認証問題を覚えていますか?これには2つの部分がありました。最初の部分は、subject的なID不一致のことでした。もう1つの部分は、私たちのクッキーがHTTPオンリーだったことで、移行が実行されている時にまだHTTPオンリーでした。つまり、そのクッキーを使用してConvexに接続することはできず、移行が完了した後に認証を更新するということでした。
したがって、サブスクリプションを扱うクライアントで行っていたことは重要ではありませんでした。なぜなら、まだクライアントに接続していなかったからです。移行が完了した後、認証を更新する場所まで接続しませんでした。そのため、その場合にこれらのクエリを押す必要がありませんでした。しかし、今はバックエンドを通してトリガーする必要がないので、以前に認証を修正しました。
今はConvexを直接呼び出すことでトリガーしています。したがって、最初に認証を修正する必要があります。認証を修正し、その後Convexに接続し、その後件をトリガーしますが、今度はConvexに接続しています。したがって、今度は必要のない大量のクエリ更新の信じられない負荷があり、恩恵を受けることのない大量のトラフィックを行うことになり、実質的にConvexのデータベースレイヤーをDDoSすることになりました。
これの多くに対する正しい解決策は、移行が完了するまでこれらのいずれもレンダリングしないことでした。そのためにこれをここに追加しました。しかし、これも追加しました。これについては少し後で説明します。これをプッシュした時、負荷が40倍から70倍減少しました。移行を完了していない場合はプリフェッチしないというこの1行のコード。
その1行の変更により、すべてが大幅にスムーズになりました。この時点で、ほとんどの場合、私たちは森から出ていました。物事はスムーズでした。アプリは素晴らしい感じでした。本当に満足でした。その夜寝る前にいくつかの変更を加えました。なぜなら、サーバーの近くにいない人々にとって楽観的アップデートをより良くしたかったからです。これにより、変更を加えた時にUIでより早く見ることができます。
大幅に良い感じになりました。T3 Chatが以前にローカルファーストだった時よりも速いとさえ言えるでしょう。物事がどこにあるかに非常に満足でした。そして長い間で初めて、ぐっすりと眠りました。文字通り12時間ほど眠りました。午後10時30分から翌日の午前10時30分、もしかすると11時まででした。これらすべてを1ヶ月かけて完了させた後、必要だったので深く眠りました。
そして完全な混乱状態で目が覚めました。非常に多くのDM、非常に多くのサポートメール、非常に多くのタグ、非常に多くのメッセージ、非常に多くのTwitterでの返信、非常に多くのSlackメッセージとスレッドで目が覚めました。午前6時から8時の間に、物事が本当に遅くなり始めました。そして午前9時以降、物事は実質的にダウンしていました。その時点で軽減できるほぼすべてのことを軽減していました。
ここから先は、私たちが失敗を防ぐためにできることはあまりありませんでした。しかし、非常に明確にするために、それは私たちが責任を負わないということを意味しません。ずっと早く回復できるべきでした。私をより早く起こすための十分に良いページングシステムがなかったという事実は、私の側の大きな失敗です。
そして、今後、これらの問題をずっと早く修正できるように、それを修正するためにあらゆる方法を取っています。ここで問題は大幅により複雑になりました。私自身の言葉で話すこともできましたが、Convexは実際に、私たちの負荷が非常に興味深かったため、ここで何が問題になったかを詳述する独自のブログポストを作成しました。
この時点まで、私たちが抱えていた問題は、ほとんどの場合、認証データの奇妙な形状や、私たちの製品のサイズでは特に法外で非合理的なクエリとミューテーションスループットを引き起こした、私たちが書いた悪いコードでした。それらはほぼ完全に私たちが修正すべきものでした。Convexの責任ではありませんでした。
私たちがConvexの責任だと確信していた時もいくつかありました。彼らは最終的に私たちの責任であることがわかるまで、私たちのためにそれに付き合ってくれました。ワイルドな経験のセットでしたが、これは非常に異なる障害でした。ミューテーションとクエリスループットで非常に多くの問題があったという事実は、ここで問題を抱え始めた時に、私たちを間違った道に導いたようなものでした。ここの文言が大好きです。
Theoの割引コードが信じさせるかもしれないものにもかかわらず、これのどれもTheoの責任ではありませんでした。それはConvexの責任でした。それは気に入らないです。私たちは皆、ここで改善できることがあると思いますが、この障害は、どちら側でも問題を引き起こすとは予想されなかったようなものでした。私たちのトラフィックはConvexができることの範囲内に完全に収まるべきだったからです。
しかし、彼らが準備していなかった私たちのトラフィックには癖があります。割引コードといえば、まだT3 Chatに登録していない場合、コードblame Theoで登録すると、最初の月がたった1ドルになります。新規登録のみです。そして1ドルの返金を求めないでください。お願いします、皆さん。
通常8ドルの時にフルマンスで1ドル。すべてのモデルにアクセスできます。かなり良い取引だと思います。試してみてください。とにかく、Convexの大部分はオープンソースです。これは実際に非常にクールなポイントです。彼らがこれらの問題を修正し、これらの変更を行った時のConvexの差分を見ることができます。
また面白いことに、多くの人がConvexの割引を得るためにクーポンコードTheoを使おうとしました。Convexは割引に関してあまり多くのことをしていません。公平に言うと、それは本当に安いです。なぜそうするのかわかりません。彼らの無料ティアも本当に寛大です。私からのConvexの割引コードはありませんが、私のために彼らを試す場合は、私が送ったことを彼らに知らせてください。彼らは素晴らしかったからです。
私は約4年間Convexに非常に懐疑的でしたが、回り込んで、今では私のスタックでそれなしでは物を構築することを想像できません。私たちのトラフィックを奇妙にした部分は次のとおりです。最初のポイントは、他の高トラフィックConvex顧客よりもはるかに多くのテキスト検索を行うことです。そこに検索があります。
人々は本当にそれを使用するのが好きです。メッセージのインデックス作成をオフにしたため、今は良い状態ではありません。したがって、今はスレッドタイトルのみに基づいて検索しており、これが嫌いです。トラフィックスパイクが処理できるものであることを確信したら、これを非常にすぐに修正します。しかし、検索ボックスが問題を引き起こしていました。
しかし、より大きな問題、そしてこれは当時私たち誰も予想していなかったことですが、ユーザーは頻繁にT3をバックグラウンドタブで開いたままにしているため、チェックする必要がある時にそこにあります。これが問題でした。なぜなら、T3 Chatを積極的に使用していない多くの人々が、WebSocket接続を介してまだ接続されていたからです。実際のスループットは比較的低いにもかかわらず、私たちが持っていたWebSocket接続の数は法外に高かったのです。
チャットで人々が言っているように、T3 chatsは一日中私のために開いています。私も同じです。いつでも多くのT3 Chatタブを開いています。人々も同じです。24時間365日開いています。複数のデバイスでそれを行います。特定のT3 Chatユーザーが、WebSocketレイヤーへのアクティブな接続を持つ異なるデバイス間で5つのタブを開いている可能性があります。
幸い、そしてこれがそうであることに非常に感謝していますが、WebSocketを正しく実装した場合、特定のWebSocket接続は実際に非常に、非常に安価です。したがって理論的には、いつでも多くのこれらの接続がある場合、Convexサーバーの負荷に関してはそれほど重要ではないはずです。
何度も言及したように、ConvexはWebSocketを介してクライアント上でのデータのやり取りをすべて管理します。彼らがここで持っている重要な部分は、顧客を拡張してきた中で、ゆっくりと膨大なノブのリストを蓄積したことです。これらのノブは、より大きな顧客がスムーズに拡張できるように、ケースバイケースで調整できるランタイムカスタマイズ可能なパラメータです。
特定のConvexデプロイメントでのリソース、キャッシュサイズ、制限などがあります。彼らは文字通りバックエンドのRustコードをリンクしています。はい、ConvexはクレイジーにスケーラブルなWebSocketバックエンドのためにRustで書かれており、必要に応じて特定のデプロイメントのパフォーマンス特性を変更できるように、これらすべてのカスタムノブの設定を持っていることを示すコードをリンクしています。
彼らはすべてがスムーズに進むように、私たちのためにいくつかのことを上げてくれました。彼らは私の知る限りでは、これがあまり大きな問題になっていないもう1つの詳細をここで呼び出しましたが、彼らのテキスト検索は他のもののように積極的に拡張しません。したがって、検索される必要がある大量のテキストデータを持つ私たちにとって、彼らはまだ修正に取り組んでいるいくつかのエッジを発見し、すぐに修正されると確信しています。
オンにしようとして何が起こるかを見ることさえまだ気にしていませんが、すぐに良くなるはずです。重要な部分は、人々がT3 Chatに参加し、それを開いて、ただ開いたままにするため、非常に多くのWebSocket接続を作成していたことです。私たちが持っていたWebSocket接続の数は時間の経過とともにどんどん上がり、下がることはほとんどありませんでした。
そこではかなり一貫した成長でした。午前6時頃、Convexのオンコールエンジニアの1人が、一部のT3 Chatユーザーに対してエラー率の上昇に気づきました。エラーは治まり、負荷は正常に戻ったため、より多くのエンジニアがオンラインになるまで調査は棚上げされました。午前8時頃に悪化し始めました。しかし午前9時30分までに、エラーが大幅に戻ってきました。
数人のエンジニアがオンラインになると、チームはコードベース内の新しい制限に達していることを認識しました。より多くのT3 Chatユーザーが起きてアプリを使用するにつれて、リフレッシュする必要がある保留中のサブスクリプションの数。T3 Chatは定期的にサーバー関数実行でクエリ無効化の巨大なスパイクを持っていました。
より多くのユーザーがオンラインになると、これらのジョブがスパイク中に待機のキューをオーバーフローし始め、サーバーがWebSocket接続をドロップするようになりました。ここで起こったパターンは、彼らのテキストインデックス作成が30分ごとに自分自身を無効化することでした。それはクエリのキャッシュバストを引き起こし、その後WebSocketを介してアップデートを送信します。
しかし、それが起こった時にこれらの膨大なキューがあり、時々WebSocket接続をドロップさせることになります。私たちはT3 Chatが定常状態負荷の50 QPSから20,000+プラス/秒に散発的に上がる理由を理解していませんでした。しかし、私たちの最初の直感は、このハードコードされたQサイズ制限をノブに変えることで、すべてのクライアントがクラッシュして再接続することを引き起こさないようにすることでした。それは時間を稼いでくれるでしょう。
ここでの問題は、特定の時間に存在できる接続数がまだハードコードされていたことでした。まだノブにしていませんでした。それを変更して設定できるようにし、私たちの制限を10Kから100Kに上げました。その後、午前10時15分頃に私たちが抱えていた障害をシミュレートし、エンジニアチームはConvexクライアントがこの特定の障害が発生した時にバックオフしなかったことに気づきました。
これはおそらく最も重要で、最も興味深い詳細だと私は主張します。推測できるように、そのConvexクライアントに接続し、クライアント上ですべての状態を管理するのは迷惑です。そのため、彼らはそれを行ってくれる本当に良いJavaScriptライブラリを持っています。接続も管理します。接続が失敗した時には、指数バックオフを行うスケジュール再接続機能があります。
それが接続に苦労している時にサービスをDDoSしないようにします。問題は、特定の場合の下でそれを適切に呼び出していないことでした。これらの障害を引き起こしたsubscription worker fullエラーは、指数バックオフしないものの1つでした。単に急速に再接続を試み続けるでしょう。したがって、彼らのクライアントコードは接続が失敗した時にバックオフしていませんでした。
そしてそのため、彼らのサーバーをDDoSしていました。Convexのチームは、特にJavaScript側で私たちがこれを修正するために多くの変更を行っていたTomに、これを修正するための変更を急いで出しました。彼らは私たちのためだけにnpmにプッシュした2つのカスタムクライアントを出荷しました。
問題は、多くのユーザーがページの回復を待っているか、バックグラウンドタブを持っていたことでした。ユーザーのクライアントを強制的にリフレッシュすることはできませんでした。皆さんはT3 Chatが更新されていないという角の小さな通知を見たことがあるでしょう。リフレッシュするためにクリックしてください。それがすべて私たちにできることでした。クライアントを強制的に更新することはできませんでした。つまり、多くの異なるクライアントが、彼らのサービスをDDoSしていたこのJavaScriptパッケージの古いバージョンにありました。
接続負荷を減らすことを期待して、より優雅にバックオフする新しいコードを持つように、これらのクライアントのより多くが更新されるのを待たなければなりませんでした。彼らが言ったように、残念ながら、この負荷の大部分はバックグラウンドタブから来ており、それらのタブで強制リフレッシュするメカニズムがありませんでした。
したがって、古いConvexコードはバックエンドをハンマーし続け、キューをオーバーフローさせ、再び切断と再接続を引き起こしました。午前10時50分頃、彼らは最終的にバックエンドのビルドとすべてのテストの通過を完了しました。面白いことに、彼らのバックエンドはRustなので、ビルド時間がひどいため出荷するのがずっと困難です。Rustへようこそ。
RustがJavaScriptでビルドタイム問題を修正しようとしている間に、独自の大規模なビルドタイム問題を抱えているのは面白いです。最終的に、バックエンドの準備ができました。彼らはそれを出荷し、現在そのキューのサイズを増やすことができ、それが私たちのすべての問題を解決するように思われました。しかし、少し後で説明する別の問題が導入されました。
午前11時から12時まで、Thundering Herdは単にT3 Chat Convexデプロイメントを圧倒し続けました。何が起こっているのかわかりませんでした。アプリをプロファイルしました。Convexエンジンを高速化するいくつかの最適化機会を見つけました。私も自分の側でたくさん見つけました。それがこれが来た場所です。if outage returned null。
アプリで必要でない最も重いものすべてを通過し、それらを無効化し、コメントアウトし、ブロックし、アプリがより少ないトラフィックを行うように必要なことは何でもしました。チャットで人々が言っているように、障害が起こった時にたくさんの更新通知を見ました。それらはすべて、負荷を減らすためにクライアントバンドルを変更し、これらすべての異なる変更を出荷して、回復するために最善を尽くしていた私たちでした。
正直に言うと、この時点で再びレガシーバージョンにロールバックすることを考えていましたが、古いDB、古いIndexDB Indexセットアップに戻り、人々が過去12時間から24時間で行ったチャットを失わせることを私の一部も望んでいませんでした。これを機能させる必要があり、常に非常に近いと感じていました。
怖かったですが、それができることを知っていましたし、Convexチーム全体が起きて私たちと協力してくれることは大きな安心でした。誰かがなぜforce reloadを実装しないのかと尋ねました。なぜなら、クライアントが古い場合、異なるクライアントコードを実装できないからです。force reloadを追加したとしても、古いクライアントでそれを実行することはできませんでした。
リフレッシュをトリガーできるコードがユーザーのデバイスにありませんでした。したがって、これらの古いタブを更新する方法がありませんでした。おそらく今はそれがあり、将来的により可能性を高めるために何かをするでしょう。しかし、はい、jolly codingに感謝します。この障害について恐ろしい気持ちだからです。しかし、ClaudeとTwitterの両方が先週もっと長時間ダウンしていました。
したがって、私は過度に率直です。そして何かあるとすれば、TwitterもClaudeも彼らの障害が起こらなかったふりをして、人々がそれらを忘れているので、これは実際に私たちにとって悪く見えるかもしれません。ほとんどのユーザーは、日曜日で最もトラフィックが少ない日だったため、私が説明している障害に遭遇しなかったでしょう。
しかし、私はこれを本当に真剣に受け止めており、私がこれについてこれほど多く話すことは、おそらくアップタイムが滑稽なほど良いにもかかわらず、私たちのサービスを競合他社よりも不安定に見せるでしょう。
しかし、こすりつけようとしているわけではありません。透明で、起こったことについて可能な限り正直でありたいのです。この動画が興味深いと思うし、今後それを修正するために何をしているかを知ってもらい、今後私たちを信頼できるようにしたいからです。ダウンしないふりをするよりも、それがずっと重要だと思います。
とにかく、彼らはこの狂った量の負荷を下げるためにジッターとバックオフ接続に関する変更を彼らの側で見つけましたが、まだ第3の問題を完全に発見していませんでした。それが発見された場所です。私たちのチームのエンジニアが、障害中にT3 ChatのConvexデプロイメントに修正を手動でプッシュしている間に、誤ってデプロイメントを無料アカウントで使用されるデフォルトのハードウェアリソースに戻してしまったことに気づきました。
この時点での問題は、狂った再接続負荷と、プッシュで多くの手動作業を行っていたために実質的に無料ティアにいたことの両方でした。それは単なる正直で単純な間違いでした。問題は、特定のインスタンスがどのプロビジョンにあるかを追跡していた彼らのシステムが、その設定を尊重しなかったため、彼らが行っていたカスタムデプロイメントによって上書きされたことでした。正直な間違いです。
私はこのような間違いを非常に多く犯しました。言葉にするのが困難なほどです。特に、誰かのティアをpingで変更した時のアカウントプロビジョニングのようなもので。私は週に数十回このようなバグを引き起こします。これを彼らに対して全く恨みません。見つけてくれて嬉しいですが、これは見つけるのが迷惑なことだからです。
彼らはすぐにそれを修正することを議論しましたが、より弱いハードウェアがサイトをほぼオンラインに戻したような感じでした。したがって、すべてのクライアントを同期させる前にバックエンドを再び再開する前に、その問題の修正を数分間遅らせました。なぜなら、再開すると、それらの古いクライアントが再びDDoSモードに戻るからです。
十分な数の古いクライアントを接続できれば、DDoSを停止し、トラフィックがずっと合理的になるでしょう。しかし、その後、まだ十分に速く回復していないことを確認しました。したがって、最終的に私たちのサービスにとってもっと理にかなっている、はるかに強力なハードウェアで再デプロイする決定を下しました。その時点からほぼ即座に回復しました。
それがタイムラインでしたが、彼らはもっと深い根本原因分析を行いました。これについて多くのことを触れました。彼らが素晴らしい仕事をしたので、分解したいと思います。最初の部分は、クエリ無効化を引き起こす検索インデックス圧縮でした。これは本当に面白かったです。なぜなら、彼らが30分おきくらいに発生する単なる狂ったスパイクを示すこのグラフを送ってくれて、私たちのダッシュボードでも見ていなかったので、私は非常に混乱していたからです。
そしてJamesは、30分ごと、1時間ごとに実行されるクロンやスケジュールされたジョブなどがあるかどうか尋ねました。私が構築するものについて皆さんがどれくらい知っているかわかりませんが、私は可能な限りスケジュールされた作業を避けます。クロンは4文字の責任です。私たちが忘れた古いクロンが実行されることで抱えた問題の量は言葉にするのが困難です。
自動化ではなく、ユーザーによって駆動されることをずっと好みます。誰かがJamesがオンコールエンジニアだったかどうか尋ねました。いいえ、JamesはCTOで、Jamieは創設者の一人です。Convexの創設者が、これの多くを助けてくれた塹壕にいた人々でした。JamesはCTOで、JamieはCEOで、どちらも私たちのためにこれを機能させるために他のすべてを脇に置いて、これの深いところにいました。
これは私たちを助けようと必死に試みているランダムなオンコールエンジニアのようなものではありませんでした。これは、私たちのためにこれを機能させるためにすべてを脇に置いたConvexの中核でした。そして誰かが今尋ねました、バックグラウンドT3ジョブを閉じるべきですか?いや、T3 Chatを立ち上げて実行し続けてください。今日学んだことに基づいてT3 Chatの使用方法を変更しないでください。
T3 Chatは皆さんが使いたいようにすべて動作するべきです。そうでなければ、私に教えてください。修正します。これらすべてのことを見つけて修正し続けます。そうです。これは、30分ヒットのこのようなチャートを見た時に面白かったです。他の顧客だった場合、彼らがそれを引き起こしているクロンジョブで何かを持っていると仮定するでしょう。
それは合理的な仮定です。私も同じ仮定をしたでしょう。T3 Chatでは何かのために実行されている単一のクロンジョブがありません。したがって、これは私たちではあり得ませんでした。そして、ここでの彼らの文言が大好きです。私たちは自然にやってくることをしました。顧客を非難する。Convexに絶対に法外な量のクレジットを与えたいと思います。なぜなら、私が彼らのせいだと100%確信していた非常に多くのことで彼らのところに来たからです。
彼らのせいだと私がそうした6つの主要なもののうち、5つは私たちの責任で、1つはOpenAuthの責任でした。したがって、Convexに何をしているのかと言った6つのうち、6つすべてが彼らの責任ではありませんでした。これらの人々は本当に、本当にデータベースとスケーリングを理解しています。これがスケールでの大規模な失敗のように見えても、そのような問題を抱えていない人を知っていますか?PlanetScale。
データベース関連で私が知っている最も選り好みの激しい人は誰か知っていますか?PlanetScaleのCEOであるSam Lambertです。私はSamをJamesとJamieに紹介しました。そして彼は私に言いました、これを言うべきかどうかさえわからない。気にしません。可能であれば彼らを雇いたい。PlanetScaleで働いていない人々で、彼らと同じくらいデータベースのスケーリングと特性を理解している人と話すのは稀です。
それは安心できる会話でした。したがって、ConvexをこのJavaScript兄弟データベースソリューションやFirebaseの小さなアプリの代替のように考えているなら、理解していません。これらの人々はDropboxをスケールし、学んだことでConvexを構築しました。彼らは本当に何をしているかを理解しています。
そして今、私たちのConvexデプロイメントもMySQLベースです。そして将来の可能性があります。彼らは話し合いをしています。それについて公に行ったり来たりしています。ConvexがPlanetScaleで実行される未来があることを願っています。そうなれば、再びPlanetScaleに戻ることになり、面白いでしょう。
未来にそれが起こるかどうか見てみましょう。指を交差させて、未来に見てみましょう。しかし、彼らはスケールする方法を知っています。したがって、これのいずれかが彼らがスケーリング関連のことを知らないことを意味するとは思わないでください。特定のエッジケースを持つ奇妙なワークロードが偶然あっただけで、彼らは即座にノブを上げることができ、スケールを問題なく処理しました。
だから、Jamesはクロンをしないことを知らない私を非難する間違いを犯しました。これは私が彼らのせいではなかった非常に多くのことで彼らを非難したので、完全に合理的で理解できることでした。はい、これは完全に合理的で理解できることでした。そして、私の睡眠スケジュールがここで見せびらかされているのを見ることができます。昨日午前2時55分。
また、午後10時に私たちとのデバッグを手伝おうとしている彼らでも。運があったか、それらのスパイクが何であるかを理解することで?私は好奇心を持っています。AxiumでそれらをBelieve me自身見ていません。はい、我々はそれらを得ました。それは検索インデックスキャッシュエントリ無効化です。これを事後分析ポストに追加し、それらが起こることも防ぎます。彼らの検索インデックス作成は、すべてのインデックスフィールドのデータサイズを小さく保つために圧縮を実行していましたが、30分ごとに更新されていました。これがサブスクリプションを無効化し、多くのクエリを発火させることになりました。
Axiumが何かと疑問に思っている人のために、それは私の好きなサービスの1つです。本当に私にスポンサー取引を検討するよう圧力をかけた最初の2つの会社は、UpstashとAxiumでした。なぜなら、YouTubeで千人の登録者がいた時、私と私がしていることに非常に興奮していたからです。彼らが大好きです。
私のコミュニティを知っているなら、彼らがcreate T3 appの中核の人々の1人であるCJ、私が今まで見た中で最も好きなデザイナーの1人であるIgor、以前私の主要研究者で、現在はAxiumでエンジニアリング関連のことを運営するのに忙しすぎるGabrielを含め、ここから多くの人を取ったことを知っています。彼らが大好きです。
本当に、本当に良いプラットフォームです。正直に言うと、これらの障害まで、彼らがダッシュボードを再実行して以来、あまり使用していませんでした。これが彼らのクエリビルダーUIです。Axiumの大きなことは、恐ろしく大量のデータを処理できることです。彼らの価格を見れば理解できるでしょう。月額500ギガのデータまで無料で入手できます。何、何、非常に狂っています。
すべてのConvexを含むすべてのログダンプとしてAxiumに非常に満足しています。なぜなら、Convexには実際に小さな添付ボタンをクリックするだけで、すべてのログが私たちがする必要があることのためにAxiumに直接行くAxiumとの統合があるからです。
ここでは、データ関数パスが存在するすべての実行を取得します。実行を押すと、実行されたすべてのクエリが表示されます。しかし、もう少しやりたいことがあります。呼び出されている特定の関数に基づいてカウントしたいのです。だから、これをデータ関数パスに変更し、ここにPIIがある場合に備えて画面を隠し、そうです。
今、特定の関数パスに基づいて、いつでもトラフィックがどのように見えるかのグラフを自明に作成できます。最後の日をすることができます。1日を通して発生するスパイクとすべての異なる関数のすべての異なるトラフィックを見ることができます。見ることができるように、検索は1日に170万回のようにヒットされます。それをnerfしたと思いました。
私のnerfが通らなかったと思います。後でそれを調整しなければなりません。しかし、get thread by IDは1日に150万回ヒットされます。アイデアは得られます。今、多くのトラフィックを行っています。これは、このデータを視覚化する非常に良い方法です。すべてをログするための非常に良いサービスです。Axiumはクールです。
まだやっていないなら、試してみるべきです。彼らは今私をスポンサーしていません。何度も断ってきました。おそらくそうすべきです。彼らはうまくやっています。おそらく彼らに連絡を取り直すべきです。本当に彼らが好きです。そのために良かったです。しかし、私が言っていたように、Convexで彼らが見ていたスパイクを私がAxiumで確認しに行った時には見えませんでした。つまり、それは彼らの側にあったに違いありません。
したがって、それがログコードの様子です。どのコード?これがそれがどのように見えるかです。ConvexやVerselなどの設定に行き、Axiumに接続します。今はコードがなく、すべてのログがAxiumに行くだけです。非常に、非常に、非常にシンプルです。努力なし。それが私が彼らをとても好きな理由の一部です。
それが私がConvexからAxiumにすべてを取得した方法です。すべてそのことについての深い分析について申し訳ありません。人々が質問しています。私たちが実際にこれらのことをどのように監視するかを見るのが有用かもしれないと思いました。GraphfanaやDataDogが数十億ドルもかからず、実際に気にかけている人々によって作られたインターフェースを持っていたらこんな感じです。
とにかく、私たちが議論していた最初の問題、Convexが列挙した3つの問題の最初は、彼らの側にあった検索インデックス作成問題でした。Convexは本当に速いので、これがどのくらい頻繁に起こっているかに気づきませんでした。クエリの数がキューサイズより大きくなって、クライアントがこれらの再試行ループに入るまで気づきませんでした。
問題2、バックオフロジック。これについては以前に話しましたが、十分に微妙ではありませんでした。何らかの形で接続に成功した場合、指数を即座に0にリセットします。問題は、接続し、エラーを取得し、その後切断することでした。つまり、何度も何度も再接続することになりました。
接続を管理するたびに、切断されてから再作成されます。したがって、指数が何度も0に設定されていたため、その指数バックオフが適用されていませんでした。したがって、彼らのサービスへのDDoSを引き起こすことになりました。彼らが言ったように、バックオフが機能していれば、T3はおそらく無料ティアのより安価で品質の低いハードウェアでも再び適切に実行されるようになったでしょう。
しかし、それは問題3につながります。これは、運用ツールがアカウント固有のプロビジョニングルールを強制していなかったことでした。したがって、この緊急事態を処理するための彼らのような運用ダッシュボードにいた時、私のアカウントに設定していた設定を持続しませんでした。この場合、より強力なボックスにいるための設定でした。そのため、私たちのトラフィックを処理するのに十分な強力さではないボックスではなかったため、物事が倒れました。
障害中にクラスターで手動でコードをプッシュするために使用したツールは、アカウントに以前に適用されたプロビジョニングされたリソースを保持せず、急いで修正しようとしている時に手動で上書きすることを忘れました。これは、本当に一生懸命に件を修正しようとしている時にのみ起こる間違いです。それが再び、なぜ私が彼らをそれに対して決して責めることがないかの理由です。
彼らは件を修正しようと一生懸命試みていたので、件を修正しようとするのが困難だった3つのバグを彼らのシステムで発見しました。T3 Chatがダウンしていた複雑なアーキテクチャ的理由を1時間以上探していました。問題が実際には間違ったVMタイプで実行されていたためCPUが過負荷になったという単純なものだった時に。
ストレス下で人間は間違いを犯すことが許されています。したがって、ツールはそれらの間違いから彼らを保護する必要があります。これが私が本当に強調したい部分です。私はこれのいずれに対してもConvexを全く責めません。特に私たちも十分に良いツールを持っていなかったので、可能な限り合理的である限り多くの責任を取ります。
間違いを防ぐだけでなく、それを発見した時に問題をエスカレートするためです。そのツールのいずれもまだ配置されておらず、今それを行うために一生懸命働いています。彼らのフォローアップアクションを通過し、その後私たちの側で計画していることも通過します。即座のためのConvexのフォローアップアクションは、すべてのツールがデプロイメントごとのコード化されたハードウェアクラスとリソース割り当てを確実に尊重するようにすることです。
したがって、Convex内部でどのツールを使用しているかを心配する必要はありません。設定が常に尊重されることを知っています。データが実際に変更されていない時にクエリを無効化しないように検索インデックス作成圧縮を最適化し、より包括的なバックアップ動作で新しいクライアントライブラリを出荷します。彼らが既にこれを行ったと思います。正直に言うと、彼らはおそらく今これら3つすべてを行ったでしょう。これらの人々は速く動きます。
今後、彼らはサブスクリプションエンジンのCPU最適化を行い、読み取りポイントで計算されるのではなく、キーが保存されるようにして、そこで大幅な計算節約になることを計画しています。彼らはまた、私たちが当たったDOSケースの周りで新しいベンチマークと負荷テストを作成したいと思っています。
Convexセッションにサーバーサイドバッファリングとバックオフを追加して、サーバーがあなたの接続を遅くできるようにし、クライアントがDOSを引き起こすことを心配する必要がないようにします。そしてもちろん、非アクティブなタブからWebSocketをドロップするためのConvexクライアントでのより多くの設定を追加して、バックグラウンドタブが切断されるように私たちがカスタムコードを書く代わりに、バックグラウンドで実行されているのを見た時に自動的に切断し、戻って開いた時に再接続できるようにします。
これは素晴らしい投稿でした。これを書いてくれたJamieと、この全てを通してJamesとTomと他のすべてのConvexの皆さんに大きな感謝です。彼らは移行を実現するために不可欠だっただけでなく、アプリ内部のことをデバッグし、Convexが行うこと、行わないことすべてのより深い理解を得るのを助けてくれました。
このような障害で、本当にすべての手がこれを実現するためにデッキにあったような気がしました。Convexからこれ以上求めることができるものはありません。彼らは私が期待したり求めたりするよりもこれを真剣に受け止めました。私について知っているように、私は厳しいかもしれませんが、非常に寛容です。
何かを修正するために正直な努力をするなら、基本的に決してそれをあなたに対して恨むことはありません。そして彼らはここで非常に深い努力をしたので、それを見て彼らを使用する可能性が低くなるのではなく、高くなるべきです。私たちのような引用符付きの小さな顧客であっても、これほど深く顧客のことを気にかけていることを知ることは、Convexを使用する全員にとって適切なソリューションになるよう彼らがどれほど一生懸命働いているかの深さを示すべきです。
それでは、T3 Chat側で今何ができるでしょうか?まあ、最初にできることはTwitterを修正することです。そうすれば、このタブを開くたびに上にスクロールし直す必要がありません。しかし、Twitterが修正されたら、これが私の詳細でした。私たちが回復している最中にこれを文字通り投稿しました。午後12時45分にライブだと言いました。この投稿は午後12時49分でした。私の目標は、私たちがどこにいるか、その時に知っていたことについて可能な限り透明であることでした。
ついにこの移行が完了したことに興奮していると呼びました。低トラフィックウィンドウ中に行いました。すべてがうまくいっているように見えました。12時間眠りました。ここで呼び出した最大の部分は、WebSocket接続DOSのことでした。しかし、これが私が修正する予定のことです。最初の大きなものは、実際のステータスプラットフォームとアップデート計画、およびアプリ内レポートです。
ステータスページを持つべきでしょうか?おそらく。しかし、アプリ内で何が起こっているかも知るべきです。他のすべてのシステムから分離された、アプリ内で今日何が問題だったか、何が起こっているか、知る必要があることを教える方法を持つべきです。UIのどこに置くかをまだ理解中です。今の時点では、何よりもデザインの問題ですが、UIに場所を持って、この時間より古いメッセージの一部が移行に失敗した可能性があります、設定に行ってこのボタンをクリックしてください、のようなことを知らせます。
または、Claude関連の障害を軽減中です。Claudeモデルが今劣化しています。または、この場合、すべてが申し訳ありません。すぐに戻ります。本当にこれをしたいと思います。非常にすぐにあるでしょう。少なくともできることです。おそらく1ヶ月前にこれを持っているべきでしたが、物事が構築された方法はあまり意味がありませんでした。
また、障害について知った時までに、通常はそれを修正する半ばだったので、修正するのに5分かかることが半分の時間ありました。この障害以外の私たちの障害のほとんどは、すべて5分未満でした。そのためにはステータスページはあまり役に立ちません。ポイント2、ページングシステムが必要です。面白いです。
実際にページングシステムが構築されているのですが、新しいモデルが出た時にすぐに出荷できるように、数人のコミュニティメンバーにアクセスを与えて私にページできるように、自分のために行ったカスタム実装されたものですが、障害のためのものは何もありません。そして、この障害の大部分の間、私はベッドで居心地よく眠っていました。
それは気に入りません。明らかに私だけがそれを修正できるからではありません。ここでは、大量の負荷を引き起こす一部の関数をコメントアウトする以外にほとんど何もしませんでした。これらのことが発生した時に、そこにいてコミュニケーションを実行し、チームを助けたいだけです。そして悲しいことに、私のチームや彼らのチーム、または他の誰かが物事が悪くなった時に私にページする良い方法がありませんでした。
エラー率が上がった時にページされるように自動エラー検出も欲しいと思います。それらすべてをこっそり入れるより良い場所を見つけています。そこでの最大の問題は、面白いことに、私たちのユーザーのほとんどがアドブロックを使用していることです。私たちのサービスが十分に人気になったので、SentryからのエラーやAnalyticsデータのようなものを送信するエンドポイントを選ぶたびに、エラーが発生していることを知るために使用する製品フィードバックエンドポイントを、アドブロックの狂信者がそれらのAnalyticsエンドポイントをブロックします。
ユーザーがエラーを抱えていると言った回数を数えることができません。ログに行きました。私たちにはそのログがないと言います。アドブロッカーを持っているかどうか尋ね、毎回Braveを実行しています。とても迷惑です。ユーザーが自分のデータを保護したいことは理解します。アドブロッカーをインストールしたためにSentryがログを送信することをブロックすることは理解できません。
それは通常の人の頭の中では広告をブロックするツールをインストールすることが、使用している製品がエラーに遭遇した時に知らないことを意味するとは一致しません。それらは通常の人の頭の中で一致しません。そして、ここで何をしても、非常に多くのユーザーがアドブロック上にいるため、クライアント側エラーを追跡する良い方法を決して持てないような気がするので、本当に最悪です。
そしてそうあるべきです。アドブロックはインターネットをより安全にします。しかし、もしダウンしているなら、私たちのエンドポイントのブロックを解除してください。サーバーはプロキシされていないのか?とGabrielが言いました。これは一般的なことです。私たち、深く雑草に入っています。より深く行くことができます。なぜだめなのでしょうか?
通常、Post Hogを例として使用する何かのようなものを使用する時。クライアント、Verselバックエンド、Post HogやAxiumやSentryなど他のものがあります。線を取ります。ユーザーがバックエンドで何かを行います。応答を取得します。その後、何らかの理由でクライアントがエラーになります。
クライアントで何かが問題になって、PostThogに連絡しようとします。しかし、PostThogは私が思うにusでホストされています。hog.com/event slash何でもそれからイベント情報のような。このURLは世界中のすべてのアドブロックによってブロックされています。非常に迷惑です。だから、ほとんどのサイトがすることは、これは基本的に今日必要ですが、自分のバックエンドでプロキシを作成することです。
だから私はslash api eventか何かに送信し、その後これがプロキシされてpost thogに行くので、アドブロッカーがそれをブロックしているにもかかわらず、彼らはこのURLをブロックしています。彼らは私のサービスのエンドポイントをブロックしていません。問題は、T3 Chatでこれらのイベントをどのパスに送信するかを変更するたびに、新しいパスがこれらすべてのブロックリストでブロックされたURLとして設定されることです。
したがって、us.postthogがブロックされているかどうかは関係ありません。なぜなら、現在t3.hativentこのURLが現在すべてのアドブロッカーでブロックされているからです。死にたいです。再び変更することができます。何度も何度も変更し続けるでしょう。私ができるもう1つのことは、このデータをAPI chatのような他のことに使用されるエンドポイントに送信することです。これはメッセージ送信に使用され、これらの他のイベントのためのカスタムフラグを持ち、それらをその方法で手動でプロキシすることです。
しかし、ユーザーがそれほど愚かであるために、愚かな方法で私たちのアーキテクチャを変更したくありません。本当にそれをしたくありません。将来的にはしなければならないかもしれません。どのようにしてそれがプロキシされていることを見つけるのでしょうか?ネットワークタブを開いて、どのトラフィックがどこに行くかを見て、クライアントでのものをブロックすることをテストし、T3 Chatが壊れるかどうかを見ます。
これを防ぐために基本的に何もすることができません。悲しいことに、以前は単に異なるエンドポイントにプロキシすることで素晴らしく動作していましたが、彼らは今エンドポイントもブロックするでしょう。だから、今の私たちの唯一のオプションは、他のことにエンドポイントを再利用し、彼らがまだそれをブロックしてT3 Chatを壊すリスクを負うことです。はい、人々が尋ねています、これはターゲットにされているのですか?これは絶対にターゲットにされています。
十分に人気があるか、あなたに注意を払う人々がアドブロックコミュニティに関与していて、あなたをあまり好きでない場合、彼らは執拗にこれを行います。私がこのURLを変更してからそれがブロックされるまでの時間は、現在約24時間から72時間です。なぜなら、これらの人々は執拗で狂っているからです。そのため、ほとんどのユーザーのデバイスがエラーに当たった時に実際に知りません。なぜなら、イベントを取得しないからです。はい、それは最悪です。
それを修正するために努力を払うつもりです。なぜなら、物事がエラーになった時に知りたいからです。しかし、アドブロックのおかげで、クライアント側エラーがいつ発生するかを知ることは基本的に不可能です。サーバーでのみ知ることができます。サーバーエラーを執拗にログし、それらを追跡し、それらのために毎日物事を変更します。しかし、エラーを見ている時に知りたいので、十分なユーザーがエラーに当たった時にページされて、起きて件を修正しに行くことができます。
アドブロッカーのおかげでこれを実現するために多くの作業を投入しなければなりませんが、そうします。もう1つの部分は、Convex記事で出てきたものです。クライアントで最新への更新フローが必要です。物事が壊れている時にリフレッシュボタンをクリックすることに頼ることはできません。緊急時にクライアントを切断させるか、理想的にはリフレッシュして最新バージョンを取得させる方法が必要です。
また、非常に大きな取引として、現在依存しているすべてのプロバイダーを通過し、私たちが持っている負荷と負荷特性に対して準備されていることを確認する必要があります。特に、狂ったように拡張しているT3 Chatが今拡張しているからです。まだ期待していなかった方法で成長し続けています。
このサービスが私の会社に資金を提供するだけでなく、夏にインターンを雇い、来年もビジネスがここにあることを快適に知ることができるほど十分にお金を払ってくれるものになるとは決して思いませんでした。T3 Chatで得たサポートの量は信じられません。私たちが協力するパートナーから得た支援の量、私たちがホストするプロバイダ、そしてアプリを使用し、物事が間違っている時に私たちに伝え、他の人とも共有してサービスが拡張し成長し続ける原因となっている皆さん一人ひとり。
今、非常に長い間拡張し続けるために今日使用しているすべてのものについて、かなり深い監査を行ったことに比較的確信しています。しかし、このようなことが再び起こらないことを確実にするために、今後これをより注意深く監視し続ける必要があります。このような障害が嫌いです。これを信じられないほど真剣に受け止めています。T3 Chatに非常に一生懸命取り組んでいるので、動画のスケジュールがバラバラになっています。
40本以上の動画のバックログがありました。最近週に最大3本の動画を撮影し、これにすべてを集中しているため、5本程度まで減っています。再びそれをするのがとても幸せです。ほぼ毎日10時間コーディング。先月のほとんどすべての日にコミットまたはPRを出荷し、たった2日を除いて、それを愛し、これを可能にしてくれた皆さん全員を愛し、このような障害が戻ってくることを止めないことを願っています。
しかし、もしそうだとしても理解します。信頼できるツールが必要です。質問がある時にそこにあり、情報が必要な時にそこにあり、欲しい時にそこにあるT3 Chatのような私たちが使用するものが必要で、そこにないたびに戻ってくる可能性がずっと低くなります。とはいえ、Claudeも使用できません。だからT3 Chatを使い続けてください。
私たちがどこにいるかにとても満足しています。私たちの安定性問題はここで解決されたと思いますし、将来これらのことを修正するのに時間ではなく分かかるようにあらゆる方法を取るつもりです。誰も障害の免疫はありません。私の言語が私たちがダウンできないことを暗示したことは決してないことを願います。
そして、他のサービスがダウンすることについて文句を言った時が、私たちはダウンしないと言っているように見えないことを願います。欲しいのは説明責任と透明性です。この件でいくつかの人が私を貶そうとして、「Twitterがダウンしていることについて文句を言っていたばかりじゃないか」と言いました。いいえ、Twitterが3日間ダウンしていて、それについてのすべてのコミュニケーションがサーバー会社が燃えたことを非難するElonがしたランダムな返信だったことについて文句を言っていました。
そこには説明責任、所有権、透明性、何もありませんでした。私が気にしていることは、障害の重大性と障害についてのコミュニケーションの重大性の比率です。私たちは小さな障害を過剰にコミュニケートします。彼らは大規模なものを過小にコミュニケートします。そして、それらの間違いを犯す企業を常に呼び出すでしょう。なぜなら、それらは許しがたいからです。
私がまだTwitterフィードを読み込めないという事実を考慮すると、人々が私たちのダウンタイムを笑い物にすることは馬鹿げています。しかし同時に、文字通り毎日何万もの人々がいて、T3 Chatを使用し依存していて、これらのことが起こった時に私たちに伝えてくれるので、より速くそれらの上に立ち、より積極的にこれらを修正し、皆さん一人ひとりに最高のサービスを出荷できることに非常に感謝しています。
これらのことをどれほど真剣に受け取っているかを理解していただけることを願います。これはもはやYouTuberの副プロジェクトではないことを理解していただけることを願います。これは、可能な限り真剣に受け取っている非常に現実的な会社の非常に正当なアプリケーション、非常に現実的な製品です。これがその信頼の一部を回復し、今後の私たちの計画を示すのに役立つことを願います。
または少なくとも、ここで共有したことから規模での出荷についていくつかのことを学ぶことができるでしょう。皆さんがどう思うか教えてください。次回まで、とどまってください。


コメント