Steven
Steven5 menit baca

Hari Ketika Aplikasi Kami Men-DDoS Dirinya Sendiri

Tumpukan unggahan yang tertunda, dilepas semuanya sekaligus saat startup, mengubah setiap klien GeekBye menjadi serangan denial-of-service kecil terhadap server kami sendiri. Perbaikannya — dan tangga liveness koneksi yang terpaksa kami bangun karenanya — adalah salah satu hal paling berguna yang diajarkan v2 kepada kami.

Keandalan
Jaringan
Engineering
Rilis GeekBye
Hari Ketika Aplikasi Kami Men-DDoS Dirinya Sendiri

Setiap engineer sistem terdistribusi cepat atau lambat berjumpa dengan thundering herd: sekumpulan klien yang semuanya melakukan hal yang sama pada saat yang persis sama, dan sumber daya bersama di belakangnya yang ambruk. Biasanya itu klien orang lain. Di GeekBye v2.0.1 itu klien kami, dan penyerangnya adalah aplikasi kami sendiri.

Bagaimana sebuah notetaker menyerang dirinya sendiri

GeekBye bisa mengunggah rekaman ke Google Drive Anda. Kalau sebuah rekaman tak bisa diunggah segera — Anda sedang offline, aplikasi tertutup, Drive tersendat — ia masuk ke tumpukan untuk dicoba lagi nanti. Masuk akal.

Kegagalannya ada di kapan "nanti" itu terjadi. Pada peluncuran berikutnya, aplikasi akan mencoba menguras seluruh tumpukan sekaligus. Satu pengguna dengan rekaman tertunda seminggu menjadi ledakan request unggahan serentak begitu ia membuka aplikasi. Kalikan dengan setiap pengguna yang membuka aplikasi di pagi hari, dan backend kami diminta mengautentikasi, mengecek rate, dan memproses tembok lalu lintas dalam beberapa detik yang sama — dari klien yang, secara teknis, semuanya berperilaku baik.

Backend kami melakukan hal yang benar dan me-rate-limit banjir itu. Dan di situlah kerusakan tingkat-dua dimulai. Respons rate-limit adalah HTTP 429, dan 429 sangat mirip dengan kegagalan lain kalau Anda tidak hati-hati:

  • Pengambilan profil saat startup mendapat 429 dan aplikasi memperlakukannya sebagai auth gagal — sebentar membuat pengguna ter-logout dari sesi yang benar-benar valid.
  • Koneksi transkripsi mendapat 429 generik dan menampilkan prompt upgrade batas-audio-tercapai — memberi tahu pengguna berbayar bahwa mereka mencapai kuota yang sebenarnya tidak mereka capai.

Jadi satu akar penyebab — tumpukan tanpa ritme — menghasilkan tiga gejala yang terlihat: beban server, logout palsu, dan upsell palsu. Bentuk klasik dari self-DoS: bebannya buruk, tapi salah tafsir atas gejala beban itulah yang benar-benar dirasakan pengguna.

Perbaikannya, dalam dua lapis

Hentikan stampede. Tumpukan unggahan kini diatur ritmenya — request disebar dengan backoff, dan cooldown setelah setiap 429 supaya klien mundur dari server yang tertekan alih-alih makin menekannya. Sebuah thundering herd berubah menjadi antrean yang tertib.

Hentikan salah tafsir. 429 atau 5xx sesaat saat startup tak lagi membuat Anda ter-logout — klien membedakan "server sedang sibuk sebentar" dari "sesi Anda tidak valid." Dan 429 rate-limit generik di jalur transkripsi tak lagi menyamar sebagai error kuota audio; hanya respons kuota yang asli yang menampilkan prompt upgrade. Pelajaran yang membekas: sebuah kode error bukanlah sebuah makna error. 429 berarti "pelan-pelan," bukan "logout" dan bukan "kamu kehabisan kuota" — dan klien harus tahu bedanya.

Tangga liveness yang menyusul

Mengatur ritme kawanan itu menyingkap masalah yang lebih senyap: ketika sebuah koneksi memang rusak di bawah beban, seberapa cepat kami menyadarinya? Lebih lambat dari yang kami inginkan. Maka v2.0.4 membangun sebuah tangga liveness koneksi untuk transkripsi real-time:

  • Heartbeat — soket transkripsi di-ping pada interval tetap, supaya koneksi yang mati diam-diam terdeteksi dalam hitungan detik alih-alih menunggu potongan audio berikutnya gagal.
  • Tendangan reconnect saat jaringan kembali — ketika OS melaporkan jaringan sudah kembali, aplikasi secara proaktif membangun ulang koneksi alih-alih menunggu tersandung menemukannya.
  • Liveness control ping/pong — sebuah perjalanan bolak-balik di tingkat aplikasi yang mengonfirmasi bukan cuma "soketnya terbuka" tapi "ujung satunya benar-benar menjawab."
  • Sebuah gerbang reconnect milik service — satu tempat memutuskan apakah akan reconnect, alih-alih beberapa bagian aplikasi berlomba melakukannya dan saling menginjak.

Tak ada satu pun dari ini yang glamor. Semuanya adalah alasan kenapa sesi v2 terasa seperti ia cuma... tetap terhubung.

Ini terjadi lagi minggu ini — satu tingkat di bawah

Inilah bagian yang membuat ini lebih dari sekadar kisah perang. Kelas kegagalan yang sama muncul kembali beberapa hari lalu, satu tingkat di bawah kami. Satu klien tunggal menembakkan 21 start sesi transkripsi dalam kurang dari 400 milidetik — dan menyentuh batas seluruh akun penyedia suara kami sebesar 15 request concurrent. Sebuah stampede terhadap infrastruktur bersama, persis seperti tumpukan unggahan, cuma diarahkan ke sebuah dependency alih-alih backend kami sendiri.

Bentuknya identik, dan begitu pula perbaikannya: klien yang memicu stampede butuh single-flight guard supaya ia tak bisa menembakkan dua puluh start untuk satu niat, dan sumber daya bersama butuh batas per-pengguna supaya satu klien tak bisa menghabiskan seluruh pool. Kami sudah pernah membangun versi sisi-klien dari ini — pengatur ritme unggahan adalah pola ini. Sekarang kami menerapkannya pada start sesi. Thundering herd bukan bug yang Anda perbaiki sekali; ia adalah bentuk yang Anda pelajari untuk dikenali di mana pun klien bertemu sebuah batas bersama.

Tiga hal untuk dibawa pulang

  1. Klien Anda sendiri adalah load test yang tak Anda jadwalkan. Apa pun yang menumpuk-saat-startup, retry-saat-peluncuran, atau reconnect-saat-bangun adalah thundering herd yang menunggu cukup banyak pengguna. Atur ritmenya sebelum Anda memilikinya.
  2. Bedakan kode dari maknanya. 429 adalah status yang paling salah dibaca yang ada. "Pelan-pelan" bukan "logout" dan bukan "bayar kami." Arahkan setiap kegagalan ke apa yang sebenarnya ia maksud.
  3. Liveness adalah sebuah tangga, bukan sebuah flag. "Apakah koneksinya hidup?" punya beberapa jawaban jujur di lapisan yang berbeda — soket terbuka, byte mengalir, ujung satunya menjawab, jaringan tersedia. Aplikasi yang tangguh memeriksa lebih dari satu.

Inilah mesin tak glamor di balik ketenangan GeekBye v2. Untuk fitur keandalan yang dimungkinkannya, lihat kenapa AI notetaker Anda berhenti saat Wi-Fi jelek dan transkripsi langsung ketika firewall memblokir WebSocket (v2.0.8). Untuk rilis-rilis tetangga di seri ini, kenapa AI notetaker Anda berhenti merekam di tengah meeting (v2.0.9).