Maude Lemaire, Refactoring at Scale kitabının yazarı. Yaklaşık sekiz yıl Slack’te arka uç performans altyapısı ekibini yönetti, 2024’te veritabanı ölçeklemesi için GitHub’a geçti. Sohbetin kariyer kısımlarını atlayıp somut derslere odaklanıyoruz.
Thundering herd: Herkes aynı anda gelince
Thundering herd (gürleyen sürü), bir olayın ardından çok sayıda kullanıcının ya da makinenin aynı anda aynı şeyi yapmasıdır. Lemaire’in Slack örneği şöyle: Şirketin genel müdürü 100 bin kişilik kanala “Cuma izinlisiniz” yazıyor. Mesaj herkese gidiyor. Birkaç saniye içinde herkes bildirime tıklıyor, kanal geçmişini yüklüyor ve bir emoji bırakıyor. Her emoji de bağlı olan herkese tekrar dağıtılıyor (fan-out). Tek bir tepki 100 bin mesaja dönüşüyor. Kalabalığın kendi kendini beslediği bir başka örnek, GitHub’ın Ağustos’taki kesintisini uzatan tekrar deneme fırtınasıydı.
Videoya göre Slack’in cevabı önceliklendirmekti: Ağır yükte metin mesajları korunuyor, emoji tepkileri gerekirse düşürülüyor. Lemaire’in vurguladığı nokta, bunun mühendislik değil ürün kararı olması. Kalabalıkta neyin feda edileceğine ürünü bilen biri karar vermeli.
Bir de event flood var. Burada sunucu değil, senin istemcin boğuluyor. Lemaire’e göre IBM’deki bir yönetici aynı anda 30 kadar çalışma alanına bağlıydı. Ortak bir kanala gelen mesajı tekrarları ayıklanmadan 30 kez alıyor, uygulaması sürekli çöküyordu. En sadık kullanıcılar en kötü deneyimi yaşıyordu.
Yük testi: Gerçek tarayıcı yerine küçük sahte istemciler
Yük testi, sistemin beklenen kalabalığı kaldırıp kaldırmadığını, o kalabalık gelmeden sahte trafikle denemek demek. Slack’in ilk aracı Puppet Show, Kubernetes üzerinde binlerce başsız (headless) Chrome çalıştırıyordu. Slack’in blog yazısına göre bu çok pahalıydı ve 150 bin sanal kullanıcıya ulaşmak bir gün sürüyordu. Videoya göre tarayıcı başına beş saatlik bir test 37 sent tutuyordu; yüz binlerce kullanıcıda bu, tek bir test için altı haneli bir fatura demek.
Yerine gelen Koi Pond, “koi” denen hafif istemciler kullanıyor. Her koi bir WebSocket bağlantısı açıyor ve gerçek bir istemci gibi API çağrıları yapıyor. Davranışlar JSON ile tanımlanıyor; örneğin bir çağrının dakikada yapılma olasılığı veri ambarındaki gerçek kullanıma göre ayarlanıyor. “Formation” denen senaryolar ise kullanıcıların belli bir yüzdesinin birkaç dakika içinde aynı şeyi yapmasını, yani sürüyü taklit ediyor. Slack’e göre 2 milyon kullanıcılık bir test, eski araçla 150 bin kullanıcının maliyetinin yüzde 0,26’sına mal oldu. Testler artık sürekli çalışıyor ve bir ölçüt sınırı aşınca kendiliğinden duruyor; örneğin API başarı oranı beş dakika boyunca yüzde 95’in altında kalırsa.
Lemaire’in çıkardığı ders: Rastgele yük basma. Önce sisteminin geçmişte nasıl çöktüğünü bul, sonra tam o yolu ucuz ama yeterince gerçekçi biçimde taklit et. Denenmemiş kapasite de denenmemiş yedek gibi sadece bir varsayım.
Scatter sorgular: Parça sayısı neden artırılamıyor?
Büyük veritabanları shard denen parçalara bölünür. Slack önce her şeyi şirkete göre bölmüştü; Lemaire’e göre zamanla en mantıklı birimin kanal olduğu anlaşıldı ve veri MySQL’i parçalamayı kolaylaştıran Vitess üzerinde yeniden bölündü. Bölme anahtarını içermeyen bir sorgu ise bütün parçalara gitmek zorunda. Buna scatter query deniyor. Slack’in Şubat 2022 kesintisinde tam olarak bu oldu: Önbellek boşalınca, kullanıcıya göre bölünmüş bir tablodaki sorgu her açılışta tüm parçalara gitti ve veritabanını boğdu.
Lemaire 2024’te GitHub’a geçtiğinde, videoya göre pull request ve issue verisinin tamamı sadece 16 parçadaydı. Daha fazla parça eklenemiyordu, çünkü çok sayıda scatter sorgu her yeni parçayı ek yük yapacaktı.
Görünmeyen SQL
Sorunu çözmek neden zor? Lemaire’e göre Rails’in Active Record katmanı sorguları o kadar iyi gizliyor ki, beş satırlık bir fonksiyona bakıp hangi SQL’in çalıştığını göremiyorsun. Videoya göre bir deponun ana sayfası en az üç MySQL kümesine yüzden fazla sorgu atıyordu. Rails’in sorgu önbelleği de sadece aynı istek içinde birebir aynı sorguyu tekrar kullanıyor. GitHub 2021’de veritabanını bölerken tabloları alanlara ayırdığını ve farklı alanlara dokunan sorguları geliştirme ve CI aşamasında yakalayan bir linter yazdığını anlatmıştı. Görünmeyen sorguyu görünür yapmanın bir yolu bu. Lemaire’in önerisi daha basit: 99’dan büyük sayıları canlı sayma, “99+” yaz.
Düşün
- Senin uygulamanda “herkesin aynı anda geldiği” an hangisi? Onu hiç taklit ettin mi?
- Kullandığın ORM, bir sayfa açılırken kaç sorgu attığını sana gösteriyor mu?
Videoyu izle
Kaynaklar (8, İngilizce)
- The Pragmatic Engineer: Scaling Slack and GitHub with Maude Lemaire (video) (yeni sekmede açılır)
- Slack Engineering: Load Testing with Koi Pond (yeni sekmede açılır)
- Slack Engineering: Continuous Load Testing (yeni sekmede açılır)
- Slack Engineering: Flannel, an application-level edge cache to make Slack scale (yeni sekmede açılır)
- Slack Engineering: Slack's Incident on 2-22-22 (yeni sekmede açılır)
- GitHub Blog: Partitioning GitHub's relational databases to handle scale (yeni sekmede açılır)
- Rails Guides: Caching with Rails (SQL caching) (yeni sekmede açılır)
- Vitess on GitHub (yeni sekmede açılır)
Kendi cümlelerimizle yazılmış bir özettir, çeviri değildir. Tüm kaynaklar yukarıda.