
Uygulamamızın Kendini DDoSladığı Gün
Bekleyen yüklemelerden oluşan bir birikim, açılışta bir anda serbest bırakılınca, her GeekBye istemcisini kendi sunucularımıza yönelik küçük bir hizmet reddi saldırısına dönüştürdü. Çözüm — ve bizi inşa etmeye zorladığı bağlantı-canlılık merdiveni — v2'nin bize öğrettiği en faydalı şeylerden biri.
Her dağıtık sistem mühendisi eninde sonunda thundering herd ile tanışır: hepsi aynı anda aynı şeyi yapan bir istemci yığını ve arkalarındaki paylaşılan kaynağın çökmesi. Genelde başkasının istemcileridir. GeekBye v2.0.1'de bunlar bizimkilerdi ve saldırgan bizim kendi uygulamamızdı.
Bir not asistanı kendine nasıl saldırır
GeekBye kayıtları Google Drive'ınıza yükleyebilir. Bir kayıt hemen yüklenemezse — çevrimdışıydınız, uygulama kapandı, Drive takıldı — daha sonra yeniden denemek üzere bir birikime düşer. Mantıklı.
Hata, "daha sonra"nın ne zaman gerçekleştiğindeydi. Bir sonraki açılışta uygulama tüm birikimi bir anda boşaltmaya çalışıyordu. Bir haftalık bekleyen kaydı olan tek bir kullanıcı, uygulamayı açtığı anda eşzamanlı yükleme isteklerinden oluşan bir patlamaya dönüşüyordu. Bunu sabah açılış yapan her kullanıcıyla çarpın, ve backend'imizden aynı birkaç saniye içinde bir trafik duvarını kimlik doğrulaması, oran kontrolü yapması ve işlemesi isteniyordu — hepsi de teknik olarak düzgün davranan istemcilerden.
Backend'imiz doğru olanı yaptı ve seli oran sınırladı. İkincil hasar da işte burada başladı. Bir oran sınırı yanıtı bir HTTP 429'dur ve 429, dikkatli değilseniz diğer hatalara çok benzer:
- Açılıştaki profil getirme bir
429aldı ve uygulama bunu auth başarısız olarak ele aldı — kullanıcıları tamamen geçerli bir oturumdan kısa süreliğine attı. - Transkripsiyon bağlantısı genel bir
429aldı ve bir ses-limiti-doldu yükseltme istemi gösterdi — ücretli kullanıcılara, aslında ulaşmadıkları bir kotaya ulaştıklarını söyledi.
Böylece tek bir kök neden — ritme sokulmamış bir birikim — üç görünür belirti üretti: sunucu yükü, sahte oturum kapatmaları ve sahte yükseltme satışları. Bir self-DoS'un klasik biçimi: yük kötüdür, ama kullanıcıların gerçekten hissettiği şey yükün belirtilerinin yanlış yorumlanmasıdır.
Çözüm, iki katmanda
Kaçışı durdur. Yükleme birikimi artık ritme sokuluyor — istekler backoff ile yayılıyor ve herhangi bir 429'dan sonra bir soğuma süresiyle istemci, zorlanmış bir sunucuya daha çok yüklenmek yerine ondan geri çekiliyor. Bir thundering herd, düzenli bir kuyruğa dönüşüyor.
Yanlış yorumlamayı durdur. Açılış sırasındaki geçici bir 429 ya da 5xx artık sizi oturumdan atmıyor — istemci "sunucu kısa süreliğine meşgul" ile "oturumunuz geçersiz"i birbirinden ayırıyor. Ve transkripsiyon yolundaki genel bir oran sınırı 429'u artık bir ses-kotası hatası gibi davranmıyor; yalnızca gerçek bir kota yanıtı yükseltme istemini gösteriyor. Akılda kalan ders: bir hata kodu, bir hata anlamı değildir. 429 "yavaşla" demektir, "yetkin yok" değil ve "kotan bitti" değil — ve istemci farkı bilmek zorunda.
Ardından gelen canlılık merdiveni
Sürüyü ritme sokmak, daha sessiz bir sorunu açığa çıkardı: bir bağlantı yük altında gerçekten bozulduğunda, bunu ne kadar hızlı fark ediyorduk? İstediğimizden daha yavaş. Bu yüzden v2.0.4, gerçek zamanlı transkripsiyon için bir bağlantı-canlılık merdiveni inşa etti:
- Heartbeat'ler — transkripsiyon soketi sabit bir aralıkta pinglenir, böylece sessizce ölmüş bir bağlantı, bir sonraki ses parçasının başarısız olmasını beklemek yerine saniyeler içinde tespit edilir.
- Bir ağ-geri-geldi yeniden bağlanma tekmesi — işletim sistemi ağın geri geldiğini bildirdiğinde, uygulama keşfe tökezleyerek varmayı beklemek yerine bağlantıyı proaktif olarak yeniden kurar.
- Control ping/pong canlılığı — sadece "soket açık" değil, "diğer uç gerçekten yanıt veriyor" olduğunu da doğrulayan, uygulama düzeyinde bir gidiş-dönüş.
- Servise ait bir yeniden bağlanma kapısı — uygulamanın birkaç parçasının bunu yapmak için yarışıp birbirinin ayağına basması yerine, yeniden bağlanılıp bağlanılmayacağına tek bir yer karar verir.
Bunların hiçbiri gösterişli değil. Hepsi, bir v2 oturumunun sadece... bağlı kalıyormuş gibi hissettirmesinin sebebi.
Bu hafta yine oldu — bir kademe aşağıda
İşte bunu bir savaş hikâyesinden fazlası yapan kısım. Aynı hata sınıfı günler önce, bizim bir kademe altımızda yeniden su yüzüne çıktı. Tek bir istemci 400 milisaniyeden kısa sürede 21 transkripsiyon-oturumu başlatması ateşledi — ve konuşma sağlayıcımızın hesap genelindeki 15 eşzamanlı istek limitini aştı. Paylaşılan altyapıya karşı bir kaçış, tıpkı yükleme birikimi gibi, sadece kendi backend'imiz yerine bir bağımlılığa yöneltilmiş.
Biçim aynı, çözüm de öyle: kaçışı başlatan istemcinin, tek bir niyet için yirmi başlatma ateşleyememesi adına bir single-flight guard'a ihtiyacı var; ve paylaşılan kaynağın da tek bir istemcinin havuzu tüketememesi adına kullanıcı-başına bir üst sınıra ihtiyacı var. Bunun istemci tarafı sürümünü daha önce inşa etmiştik — yükleme ritmeleyici tam da bu desen. Şimdi bunu oturum başlatmalarına uyguluyoruz. Thundering herd bir kez düzelttiğiniz bir hata değildir; istemcilerin paylaşılan bir limitle karşılaştığı her yerde tanımayı öğrendiğiniz bir biçimdir.
Alınacak üç ders
- Kendi istemcileriniz, planlamadığınız bir yük testidir. Açılışta-toplayan, açılışta-yeniden-deneyen ya da uyanışta-yeniden-bağlanan her şey, yeterince kullanıcıyı bekleyen bir thundering herd'dür. Onlara sahip olmadan önce ritme sokun.
- Kodu anlamdan ayırın.
429, var olan en yanlış okunan durum kodudur. "Yavaşla", "oturumu kapat" değildir ve "bize para öde" değildir. Her hatayı gerçekte ne anlama geldiğine yönlendirin. - Canlılık bir merdivendir, bir bayrak değil. "Bağlantı canlı mı?" sorusunun farklı katmanlarda birkaç dürüst yanıtı vardır — soket açık, baytlar akıyor, diğer uç yanıt veriyor, ağ mevcut. Sağlam bir uygulama birden fazlasını kontrol eder.
Bu, GeekBye v2'nin sakinliğinin altındaki gösterişsiz mekanizma. Mümkün kıldığı güvenilirlik özellikleri için, AI not asistanınız neden kötü Wi-Fi'de duruyor ve güvenlik duvarı WebSocket'leri engellediğinde canlı transkripsiyon (v2.0.8) yazılarına bakın. Bu serideki komşu sürümler için ise AI not asistanınız neden toplantının ortasında kaydı durduruyor (v2.0.9).