Pod'larımız sağlıklı olduğunu bildiriyordu ama trafik sunamıyordu. Nasıl?

Health check:

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  periodSeconds: 10

Handler:

@GetMapping("/health")
public String health() {
    return "OK";  // always returns OK
}

Uygulama başlıyor, veritabanı bağlantısını kaybediyor, cache'e karşı zaman aşımına düşüyor — ve “OK” yanıtlamaya devam ediyordu. Kubernetes her pod'u rotasyonda tuttu, load balancer yönlendirmeyi sürdürdü ve kullanıcılar, platformun sapasağlam diye yemin ettiği pod'lardan hata aldı.

İlk düzeltme işleri daha da kötüleştirdi:

Bariz yama — veritabanı, cache ve dış API kontrollerini /health'e bağlamak — aynı liveness probe'una girdi. Üç gün sonra veritabanı failover yaptı ve yaklaşık 30 saniye erişilemez kaldı. Her pod'un liveness probe'u tek bir probe döngüsü içinde başarısız oldu ve kubelet, liveness hatalarının gerektirdiği şeyi yaptı: 40 pod'un tamamını öldürüp yeniden başlattı. Her yeniden başlatma, toparlanmanın ortasındaki bir veritabanına karşı bağlantı havuzlarını yeniden açtı ve cache'leri ısıttı. Health check'lerin kendisi aşırı yüke dönüştü — herkesin beklediği bağımlılığı döven bir restart fırtınası. 30 saniyelik bir sendeleme 20 dakikalık kesintiye dönüştü.

Önemli olan ayrım:

  • Liveness: “Bu süreç kilitlendi mi?” Yalnızca süreci kontrol eder — deadlock'lar, takılmış bir olay döngüsü. Asla paylaşılan bağımlılıkları değil. Başarısızlık yeniden başlatma demektir ve 40 pod'u yeniden başlatmak bozuk bir veritabanını düzeltmez.
  • Readiness: “Bu pod şu anda hizmet verebilir mi?” Başarısızlık, pod'u yeniden başlatmadan Service endpoint'lerinden çıkarır; kontrol geçince yeniden katılır. Bağımlılık kontrollerinin yeri — eğer bir yeri varsa — burasıdır; ama paylaşılan bağımlılıklara dikkatle kapı koyun, çünkü veritabanı herkes için çöktüyse tüm pod'lar birlikte unready olur ve hiçbir şey sunamazsınız. Çoğu zaman bozulmuş (degraded) bir yanıt, hiç endpoint olmamasından iyidir.
  • Startup: yavaş başlatmayı kapsar; böylece liveness probe hâlâ açılmakta olan bir pod'u öldürmez.

Şimdi çalıştırdığımız:

livenessProbe:
  httpGet:
    path: /health/live     # process only, no dependencies
    port: 8080
  periodSeconds: 10
  failureThreshold: 3
readinessProbe:
  httpGet:
    path: /health/ready    # pod-local checks, e.g. warm caches
    port: 8080
  periodSeconds: 5
  failureThreshold: 2
startupProbe:
  httpGet:
    path: /health/live
    port: 8080
  periodSeconds: 5
  failureThreshold: 30
@GetMapping("/health/ready")
public ResponseEntity<HealthStatus> readiness() {
    HealthStatus status = healthService.check();
    return status.canServe()
        ? ResponseEntity.ok(status)
        : ResponseEntity.status(503).body(status);
}

Bağımlılık sağlığı probe'lardan tamamen çıktı; ne yapılacağına kubelet'in değil insanların karar verdiği metriklere ve alarmlara taşındı. Yeniden başlatmaların toparlanan bir veritabanını bağlantıyla boğduğu ilgili kaskadın kendi yazısı var: veritabanını çökerten autoscaling; probe semantiğini doğru kurmak Kubernetes ve DevOps incelemelerimizin standart bir maddesidir.

Ders: Sağlığı kontrol etmeyen bir health check hiç olmamasından kötüdür — ve fazlasını kontrol eden bir liveness probe bunu kanıtlamak için cluster'ı yakıp kül eder.


← Çı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.