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.


← Çıkarılan Dersler'e dön

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.