Steven
Steven5 minit bacaan

Hari Aplikasi Kami Men-DDoS Dirinya Sendiri

Satu longgokan muat naik yang tertunda, dilepaskan sekali gus semasa permulaan, menjadikan setiap klien GeekBye satu serangan denial-of-service kecil terhadap pelayan kami sendiri. Penyelesaiannya — dan tangga vitaliti sambungan yang ia paksa kami bina — ialah salah satu perkara paling berguna yang v2 ajarkan kepada kami.

Kebolehpercayaan
Rangkaian
Kejuruteraan
Keluaran GeekBye
Hari Aplikasi Kami Men-DDoS Dirinya Sendiri

Setiap jurutera sistem teragih akhirnya akan berjumpa dengan thundering herd: sekumpulan besar klien yang semuanya melakukan perkara yang sama pada saat yang sama, dan sumber dikongsi di belakang mereka yang tumbang. Biasanya ia klien orang lain. Dalam GeekBye v2.0.1 ia klien kami, dan penyerangnya ialah aplikasi kami sendiri.

Bagaimana sebuah notetaker menyerang dirinya sendiri

GeekBye boleh memuat naik rakaman ke Google Drive anda. Jika satu rakaman tak dapat dimuat naik serta-merta — anda di luar talian, aplikasi ditutup, Drive tersekat — ia masuk ke satu longgokan untuk dicuba semula kemudian. Munasabah.

Kegagalannya ada pada bila "kemudian" itu berlaku. Pada pelancaran berikutnya, aplikasi akan cuba mengosongkan seluruh longgokan sekali gus. Seorang pengguna dengan rakaman tertunda seminggu menjadi satu letusan permintaan muat naik serentak pada saat mereka membuka aplikasi. Darabkan dengan setiap pengguna yang memulakan pada waktu pagi, dan backend kami diminta mengesahtaraf, menyemak kadar, dan memproses satu tembok trafik dalam beberapa saat yang sama — daripada klien yang, secara teknikal, semuanya berkelakuan baik.

Backend kami melakukan perkara yang betul dan mengehadkan kadar banjir itu. Dan di situlah kerosakan peringkat-kedua bermula. Satu respons had kadar ialah HTTP 429, dan 429 amat menyerupai kegagalan lain jika anda tak berhati-hati:

  • Pengambilan profil semasa permulaan mendapat satu 429 dan aplikasi melayannya sebagai auth gagal — melog keluar pengguna seketika daripada satu sesi yang benar-benar sah.
  • Sambungan transkripsi mendapat satu 429 generik dan menunjukkan satu gesaan naik taraf had-audio-dicapai — memberitahu pengguna berbayar bahawa mereka mencapai satu kuota yang sebenarnya tidak mereka capai.

Jadi satu punca utama — satu longgokan tanpa rentak — menghasilkan tiga gejala yang kelihatan: tekanan pelayan, log keluar palsu, dan jualan tambahan palsu. Bentuk klasik sebuah self-DoS: bebannya buruk, tetapi salah tafsir terhadap gejala beban itulah yang benar-benar dirasai pengguna.

Penyelesaiannya, dalam dua lapisan

Hentikan rempuhan. Longgokan muat naik kini diberi rentak — permintaan disebarkan dengan backoff, dan satu tempoh penyejukan selepas mana-mana 429 supaya klien berundur daripada pelayan yang tertekan dan bukannya bersandar lebih kuat padanya. Satu thundering herd menjadi satu barisan yang teratur.

Hentikan salah tafsir. Satu 429 atau 5xx sementara semasa permulaan tak lagi melog anda keluar — klien membezakan "pelayan sibuk seketika" daripada "sesi anda tak sah." Dan satu 429 had kadar generik pada laluan transkripsi tak lagi menyamar sebagai satu ralat kuota audio; hanya satu respons kuota yang tulen menunjukkan gesaan naik taraf. Pengajaran yang melekat: satu kod ralat bukanlah satu makna ralat. 429 bermaksud "perlahankan," bukan "log keluar" dan bukan "anda kehabisan kuota" — dan klien mesti tahu bezanya.

Tangga vitaliti yang menyusul

Memberi rentak kepada kawanan itu mendedahkan satu masalah yang lebih senyap: apabila satu sambungan memang rosak di bawah beban, sepantas mana kami perasan? Lebih perlahan daripada yang kami mahu. Maka v2.0.4 membina satu tangga vitaliti sambungan untuk transkripsi masa nyata:

  • Heartbeat — soket transkripsi di-ping pada satu selang tetap, supaya satu sambungan yang mati secara senyap dikesan dalam beberapa saat dan bukannya menunggu ketulan audio seterusnya gagal.
  • Satu tendangan sambung semula bila rangkaian kembali — apabila OS melaporkan rangkaian telah kembali, aplikasi secara proaktif membina semula sambungan dan bukannya menunggu untuk tersandung menemuinya.
  • Vitaliti control ping/pong — satu perjalanan pergi-balik pada peringkat aplikasi yang mengesahkan bukan sekadar "soket terbuka" tetapi "hujung sebelah lagi benar-benar menjawab."
  • Satu pintu sambung semula milik service — satu tempat memutuskan sama ada untuk menyambung semula, dan bukannya beberapa bahagian aplikasi berlumba melakukannya dan berlanggar antara satu sama lain.

Tiada satu pun daripada ini yang menawan. Kesemuanya ialah sebab mengapa satu sesi v2 terasa seperti ia cuma... kekal bersambung.

Ia berlaku lagi minggu ini — satu tingkat di bawah

Inilah bahagian yang menjadikan ini lebih daripada sekadar kisah perang. Kelas kegagalan yang sama muncul semula beberapa hari lalu, satu tingkat di bawah kami. Satu klien tunggal melepaskan 21 permulaan sesi transkripsi dalam kurang daripada 400 milisaat — dan melanggar had seluruh akaun pembekal suara kami sebanyak 15 permintaan serentak. Satu rempuhan terhadap infrastruktur dikongsi, tepat seperti longgokan muat naik, cuma disasarkan kepada satu dependency dan bukannya backend kami sendiri.

Bentuknya serupa, dan begitu juga penyelesaiannya: klien yang mencetuskan rempuhan memerlukan satu single-flight guard supaya ia tak boleh melepaskan dua puluh permulaan untuk satu niat, dan sumber dikongsi memerlukan satu had setiap-pengguna supaya satu klien tak boleh menghabiskan seluruh kolam. Kami telah membina versi sebelah-klien bagi ini sebelum ini — pemberi rentak muat naik ialah corak ini. Kini kami menerapkannya pada permulaan sesi. Thundering herd bukanlah satu pepijat yang anda betulkan sekali sahaja; ia satu bentuk yang anda belajar mengenalinya di mana-mana sahaja klien bertemu satu had dikongsi.

Tiga perkara untuk dibawa pulang

  1. Klien anda sendiri ialah satu ujian beban yang anda tak jadualkan. Apa-apa yang mengelompok-semasa-permulaan, mencuba-semula-semasa-pelancaran, atau menyambung-semula-semasa-bangun ialah satu thundering herd yang menunggu cukup ramai pengguna. Beri rentak sebelum anda memilikinya.
  2. Bezakan kod daripada maknanya. 429 ialah status paling salah dibaca yang wujud. "Perlahankan" bukan "log keluar" dan bukan "bayar kami." Halakan setiap kegagalan kepada apa yang ia benar-benar maksudkan.
  3. Vitaliti ialah satu tangga, bukan satu bendera. "Adakah sambungan itu hidup?" mempunyai beberapa jawapan jujur pada lapisan yang berbeza — soket terbuka, bait mengalir, hujung sebelah menjawab, rangkaian hadir. Satu aplikasi yang kukuh menyemak lebih daripada satu.

Inilah jentera tak menawan di sebalik ketenangan GeekBye v2. Untuk ciri kebolehpercayaan yang ia mungkinkan, lihat mengapa AI notetaker anda berhenti apabila Wi-Fi teruk dan transkripsi langsung apabila tembok api menyekat WebSocket (v2.0.8). Untuk keluaran jiran dalam siri ini, mengapa AI notetaker anda berhenti merakam di pertengahan mesyuarat (v2.0.9).