Veritabanını Çökerten Autoscaling
Kubernetes cluster'ımız kusursuz ölçekleniyordu. Fazlasıyla kusursuz.
Olay:
- Sabah 10'da trafik sıçraması
- HPA pod'ları ölçekledi: 5 → 50
- Her pod: 20 veritabanı bağlantısı
- Toplam bağlantı: 100 → 1.000
- PostgreSQL max_connections: 200
- Her yeni pod'da “FATAL: too many connections”
Kaskad:
Yeni pod'lar bağlanamadı, health check'lerinden kaldı ve yeniden başlatıldı — ve her yeniden başlatma, zaten limitte olan veritabanına karşı taze bir bağlantı denemesi dalgası açtı. Dakikalar içinde cluster çırpınmaya (thrashing) başlamıştı: pod'lar döngüde, her döngüde bir bağlantı fırtınası ve asıl trafik sıçraması hâlâ karşılanmamış.
Çözüm:
PostgreSQL'in önüne transaction pooling modunda çalışan PgBouncer: uygulama tarafındaki 1.000 bağlantı, yaklaşık 100 gerçek sunucu bağlantısına çoklandı (multiplex). Mod seçimi önemli. Session pooling bir sunucu bağlantısını ömrü boyunca tek bir istemciye sabitler; yani sayımızı hiç düşürmezdi. Transaction pooling sunucu bağlantısını her transaction'dan sonra serbest bırakır — 10:1 çoklama oradan gelir — ama oturum durumu (session state) varsayan her şeyi bozar: oturum düzeyindeki advisory lock'lar, LISTEN/NOTIFY, oturum düzeyindeki SET değişkenleri ve eski sürücülerdeki prepared statement'lar. Önce bunları denetledik; advisory lock kullanan tek servis kendi küçük session-mode havuzunu aldı.
İkinci olarak HPA'nın izdihama kalkmasını engelledik. Yukarı ölçekleme artık hız sınırlı; böylece alt sistemler her adımı sindirecek zaman buluyor ve maksimum replica sayısı veri katmanının gerçekten taşıyabileceği değere sabitlendi:
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Pods
value: 4
periodSeconds: 60
maxReplicas: 30
AWS'de yönetilen alternatif RDS Proxy: aynı çoklama fikri, IAM auth, işletecek bir şey yok — vCPU başına fiyatlandırmayla ve şu çekinceyle: oturum durumu bağlantıları “sabitler” (pin) ve para ödediğiniz çoklamayı sessizce devre dışı bırakır.
Bilinçli olarak yapmadığımız şey:
Readiness probe'larını bir veritabanı bağlantısına bağlamak. Kulağa mantıklı geliyor, ama paylaşılan bir bağımlılığa dayanan readiness şu demek: veritabanı bir an sendelediğinde tüm pod'lar aynı anda unready olur, Service tüm endpoint'lerini kaybeder ve kısmi bir bozulma tam kesintiye dönüşür — tam da durdurmaya çalıştığımız kaskad. Probe'lar pod'u doğrulamalı, paylaşılan altyapı hakkında oy kullanmamalı; bu arıza modunu yalan söyleyen health check'ler yazısında ele alıyoruz.
Ders: Autoscaling, alt sistemlerin limitlerini bilmez. Onları siz dayatmak zorundasınız — pooler'da, HPA politikasında ve autoscale olmayan tek bileşenin kapasite planlamasında. Bu zinciri uçtan uca boyutlandırmak sonradan akla gelen bir ince ayar değil, DevOps mühendisliğinin çekirdek işidir.
Bu tür olaylar önlenebilir. AWS Yönetilen Hizmetler ekibimiz müşteri ortamlarını yapay zekâ destekli izleme ve nöbetteki kıdemli mühendislerle 7/24 gözetir — böylece bu tür hikâyeler arşivde kalır.