Blog'a Dön

Justin Bieber, Like Fırtınası ve Instagram’ı Çökerten “Bieber Bug”

Justin Bieber, Like Fırtınası ve Instagram’ı Çökerten “Bieber Bug”

2015 yılında Instagram hâlâ büyüme aşamasındayken Instagram'ın kullanıcı sayısı milyonlara ulaşmıştı ve bilinen en meşhur sanatçılardan biri olan Justin Bieber bir fotoğraf paylaştı. Dakikalar içinde bu gönderiye çok yüksek sayılarda beğeni ve yorum yağdı. Uygulama önce yavaşladı hatta çöktü. Bu backend mimarisinin gerçek hayattaki bir yansımasıydı. Bu noktada sorulması gereken soru şuydu:

Tek bir kullanıcının gönderisi nasıl olur da tüm sistemi etkiler?

Cevap: COUNT(*)

O dönemde Instagram, bir gönderinin beğeni sayısını hesaplamak için şuna benzer bir sorgu çalıştırıyordu:

SELECT COUNT(*) FROM likes WHERE postId = ?

Ya da bazı varyasyonlarda:

SELECT COUNT(*) FROM db WHERE postId IN user.likedPosts

Normal bir kullanıcı için bu sorgu sorun olmayabilirdi ancak bir ünlünün gönderisi için aynı durum söz konusu değildi. Ortada sürekli artan bir veri ve aynı anda paralel yapılan COUNT sorguları vardı.

Bu sorgu: • Index taraması yapıyor • Satırları sayıyor • CPU kullanıyor • Disk I/O oluşturuyor

COUNT(*) Sorgusunu Bu kadar tehlikeli yapan neydi?

Büyük veri üzerinde: • Table scan yapabilir • Index bile olsa milyonlarca satırı okumak zorunda kalır • Aynı anda yüzlerce thread çalıştırır

Ünlü birine ait gönderideki problem ise: • Kullanıcı beğeni atıyor • Aynı anda 100.000 kişi akışı yeniliyor • Her yenilemede beğeni sayısı yeniden hesaplanıyor

Yani: High write load + High read load + Expensive aggregation query

Bu üçlü birleşince: • DB CPU %100 • Query queue birikmesi • Uygulama çöküşü

Instagram’ın önünde bir memory cache vardı. Ama sorun şuydu: Beğeni hızı cache’in güncellenme hızından fazlaydı.

Cache miss olduğunda: → Sistem tekrar DB’ye gidiyordu → DB tekrar COUNT(*) çalıştırıyordu

Buna cache stampede denir. Ünlü gönderisi adeta cache’i ezip geçiyordu.

Çözüm: Denormalizasyon

Bu noktada kritik bir karar alındı. Beğeni sayısı her seferinde hesaplanmayacaktı. Bunun yerine her post tablosuna bir alan eklendi:

totalLikes INT

Artık: • Kullanıcı like attığında • totalLikes = totalLikes + 1

Yani: Aggregation yok. COUNT(*) yok. Expensive query yok.

Bu, klasik bir denormalizasyon örneğidir.

Eventual Consistency:

Bir diğer kritik karar ise kullanıcı gönderiyi beğendiğinde beğeni sayısı birkaç saniye gecikmeli olarak güncellenecek ve sistem kısa süreliğine tutarsız olsa da doğru sonuca ulaşacak. Bu kararın avantajı: • Yazma işlemleri kuyruğa alınabilir • Batch update yapılabilir • Trafik zamana yayılır

Sonuç

Instagram kötü bir yazılıma sahip değildi ama postların bu kadar beğeni alamayacağı yönündeki varsayımı hatalıydı. Bu yüzden tasarlanan sistemler ortalama bir trafiğe göre değil pik trafiğe göre tasarlanmalıdır. Sonuç olarak şunu söyleyebiliriz ki mükemmel mimariler bu tarz olaylardan alınan dersler ile ortaya çıkar. Yazılım mühendisliği ise beklenmeyen yük altında sistemi ayakta tutabilmektir.