İçeriğe geç

Actuator ve Gözlemlenebilirlik — Sağlık, Metrik, İz

İleri 9 dk Çok sık karşılaşılır

Önce şunu oku: Auto-configuration — Bu Bean Nereden Geldi?

30 saniyede özet

Uygulaman iki farklı soruya cevap verir: 'yaşıyor musun?' (liveness) ve 'iş alabilir misin?' (readiness). Veritabanını ilk soruya bağlamak, küçük bir kesintiyi bütün uygulamanın yeniden başlamasına çevirir.

Veritabanı beş dakika kapalı kaldı. Sonra uygulama on beş dakika açılmadı. Arada bir satır bile kod değişmedi — sadece sağlık kontrolü yanlış yere konmuştu.

  1. Bayt: Veritabanı beş dakika kapalı kaldı, uygulama ise on beş dakika açılmadı!

  2. Sen: Veritabanı dönünce uygulama da dönmedi mi?

  3. Bayt: Dönmedi! Pod'lar durmadan yeniden başlıyordu.

  4. Bayt: Hastane iki ayrı soru sorar: yaşıyor mu, ve ziyaretçi alabilir mi? Hangisini yanlış cevapladık?

Actuator: uygulama kendini anlatır

spring-boot-starter-actuator, uygulamaya “nasılsın?” diye sorulabilecek adresler ekler: health, info, metrics, prometheus. Boot 3’te dışarıya varsayılan olarak yalnızca /actuator/health açıktır.

env, heapdump gibi uç noktalar ayarları ve belleği gösterir. Açacaksan ayrı bir management portunda, kimlik doğrulamanın arkasında aç.

Kafam karıştı, daha basit anlat

Actuator, uygulamaya “nasılsın” diye sorabileceğin kapılar açar. Sağlık kapısı herkese açık olabilir. Ayarları ve belleği gösteren kapılar ise kilitli durmalı.

Hızlı kontrolBaşlangıç

spring-boot-starter-actuator ekledin ve hiçbir ayar yazmadın. Spring Boot 3'te HTTP üzerinden hangi uç nokta açılır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Güvenlik taramasında /actuator/env ve /actuator/heapdump uç noktalarının internete açık olduğu görüldü. Asıl risk ne?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Liveness ve readiness

Veritabanı kontrolü liveness'ta. Veritabanı düştü ve liveness art arda üç kez başarısız oldu. Kubernetes ne yapar — bu veritabanını düzeltir mi? Cevabı göster

Pod’ları yeniden başlatır. Veritabanına dokunmaz, onu düzeltmez. Açılan pod’lar da aynı veritabanına bakıp yeniden düşer.

Yaşıyor musun ile iş alabilir misin aynı soru değil.
Adım adım oku
  1. Veritabanı düşer.
  2. Veritabanı kontrolü liveness'a bağlıysa Kubernetes sağlıklı pod'ları ölü sanıp durmadan yeniden başlatır.
  3. Kontrol readiness'a bağlıysa pod ayakta kalır; yalnızca trafikten çıkarılır.
  4. Veritabanı dönünce readiness yeniden olumlu olur ve ayakta bekleyen pod hemen iş almaya başlar.
Düşerse Kubernetes ne yaparNeye bakmalı
liveness probeKubernetes'in "bu süreç hâlâ çalışabilir durumda mı?" sorusu. Art arda düşerse pod yeniden başlatılır; bu yüzden yalnızca yeniden başlatmanın düzelteceği şeylere bakmalı.Sözlükte gör →Pod’u yeniden başlatırYalnızca yeniden başlatmanın düzelteceği şeylere
readiness probeKubernetes'in "bu pod şu an trafik almaya hazır mı?" sorusu. Düşerse pod yeniden başlatılmaz, yalnızca load balancer'dan çıkarılır.Sözlükte gör →Pod’u trafikten çıkarırO pod’a özgü geçici durumlara

Liveness’ı düşürmek “beni yeniden başlat” demektir. Dış bir bağımlılık yeniden başlatmayla düzelmez. Boot’un varsayılan liveness grubu bu yüzden dış sistemlere bakmaz.

Kafam karıştı, daha basit anlat

Liveness, “beni yeniden başlat” demektir. Readiness ise “şu an müşteri alamıyorum” demektir. Veritabanı çöktüyse yeniden başlamak işe yaramaz, müşteri almayı bırakmak yeter.

Hızlı kontrolOrta

Kubernetes'te liveness ve readiness probe'ları düştüğünde ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Liveness ve readiness — veritabanı düşünce pod'lara ne olur?

Tohum 280193
PeriyotVeritabanı3 podKarşılanan

Oynat ya da adımla.

Hız
Adım 0

Şu an ne oldu?

3 pod, 5 periyotluk veritabanı kesintisi

Kesinti 2. periyotta başlıyor. İsteklerin yarısı veritabanı, yarısı önbellek istiyor.

Görevler0/3

  • Veritabanı kesintisini bir yeniden başlatma fırtınasına çeviraçık

    İpucu

    Kubernetes liveness düşen pod'u yeniden başlatır. Veritabanı, açılan pod'lar yeniden düşecek kadar uzun kapalı kalsın.

  • Veritabanı gerektirmeyen istekleri de reddettir — ama pod'ları yeniden başlatmadanaçık

    İpucu

    Pod'ların hepsi aynı anda "trafik almaya hazır değilim" derse?

  • Uzun bir kesintiyi hiçbir isteği load balancer'da kaybetmeden atlataçık

    İpucu

    Kesinti en az 5 periyot sürsün. Hiçbir sağlık grubu veritabanına bakmasın.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. Veritabanı iki grupta da: önce trafik kesiliyor, sonra üç pod birden yeniden başlıyor.
  2. Kesintiyi 9 periyot yap. Açılan pod’lar yeniden düşüyor: fırtına.
  3. Liveness’ı “yalnızca uygulama” yap. Yeniden başlatma yok — ama load balancer yine her şeyi reddediyor.
  4. Readiness’ı da “yalnızca uygulama” yap. Önbellekten gelen istekler kesinti boyunca karşılanıyor.
Hızlı kontrolOrta

Liveness grubuna veritabanı sağlık kontrolü eklendi. Veritabanı 5 dakika kapalı kalırsa ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Metrik, iz ve log

SinyalCevapladığı soruAraç
Metrik”Genel olarak nasılız?”Micrometer + Prometheus
İz (trace)“Bu istek zamanını nerede geçirdi?”Micrometer Tracing
Log”Tam olarak ne oldu?”Yapılandırılmış log + traceId
Gecikme için bir Timer
Timer.builder("orders.place")
.tag("status", result.name()) // sonlu bir küme
.publishPercentileHistogram() // p95/p99 Prometheus'ta hesaplanır
.register(registry)
.record(duration);

Ortalama, yavaş istekleri gizler. Kullanıcıların şikâyet ettiği yavaş istekler en yavaş %1’lik dilimdedir (p99) ve ortalamada kaybolur. Metrik etiketlerinin alabileceği değer sayısı (cardinalityBir metriğin etiket değerlerinin kaç farklı kombinasyon ürettiği. Her kombinasyon ayrı bir zaman serisidir; userId gibi sınırsız bir etiket metrik sistemini çökertir.Sözlükte gör →) da sınırlı kalmalı: her farklı değer ayrı bir veri serisi demektir.

Kafam karıştı, daha basit anlat

Ortalama, sıradaki en yavaş birkaç kişiyi gizler. En yavaş yüzde birlik dilime bakarsan, kimin gerçekten beklediğini görürsün.

Hızlı kontrolOrta

Her soruyu en iyi cevaplayan sinyale yerleştir.

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Sınıflandırılmamış

Metrik

Zaman içinde toplanmış sayılar

    İz (trace)

    Tek bir isteğin servisler arasındaki yolculuğu

      Log

      Tek bir olayın ayrıntısı

        Panoda ortalama cevap süresi 80 ms, ama kullanıcılar yavaşlıktan şikâyet ediyor. En olası açıklama?

        Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

        Tuzaklar

        Paylaşılan bağımlılık readiness’ta. Bütün pod’lar aynı anda trafikten çıkar; veritabanı istemeyen sayfalar da kapanır.

        Etikette kullanıcı kimliği. Her kullanıcı için ayrı bir veri serisi oluşur ve izleme sistemi (Prometheus) bu yükün altında ezilir.

        Herkese açık Actuator. env ve heapdump şifreleri ve kullanıcı verisini gösterebilir.

        Ağır sağlık kontrolü. Probe birkaç saniyede bir çalışır. Her seferinde pahalı bir sorgu atan kontrol, kendi başına bir yük olur.

        Hızlı kontrolOrta

        Bu metrik eklendikten birkaç gün sonra Prometheus'un belleği tükeniyor. Hangi satır?

        Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

        Hatalı satıra dokun, sonra kontrol et.

        OrderMetrics.java
        Java 21UTF-8LF

        Aşağıdaki örnek bir bankanın kart provizyon servisinden: probe’lar için doğru health grupları, kart ağı bağlantısı için kendi health kontrolün, kart numarası taşımayan düşük kardinaliteli metrikler ve actuator’ı dışarıya kapatan ayrı bir port.

        Derinleş · Kart provizyon servisinin gözlemlenebilirliği 5 dosya · ~117 satır · ilk okumada atlayabilirsin
        Proje dosyaları

        src/main/resources/ application.yml Probe'lar, health grupları, ayrı yönetim portu ve metrik etiketleri tek dosyada.

        src/main/resources/application.yml
        management:
        server:
        port: 8081 # not exposed through the public ingress
        endpoints:
        web:
        exposure:
        include: health,info,metrics,prometheus
        endpoint:
        health:
        probes:
        enabled: true
        show-details: when-authorized
        group:
        # Liveness: only "is this JVM stuck?". Never external dependencies.
        liveness:
        include: livenessState
        # Readiness: can this pod take traffic right now?
        readiness:
        include: readinessState,db
        # For dashboards and the on-call engineer, not for Kubernetes.
        dependencies:
        include: db,cardNetwork
        metrics:
        tags:
        application: card-authorization # every metric carries it; one fixed value
        observations:
        annotations:
        enabled: true # makes @Observed work (Boot 3.2+)
        key-values:
        region: eu-central

        src/main/java/com/bank/ops/ CardNetworkHealth.java Kart ağı bağlantısı için health kontrolü. Liveness'a girmez: dış bağlantı koptu diye pod yeniden başlatılmaz.

        src/main/java/com/bank/ops/CardNetworkHealth.java
        @Component("cardNetwork") // the name used in the health groups above
        class CardNetworkHealth implements HealthIndicator {
        private final CardNetworkConnection network; // long-lived link to the card scheme
        CardNetworkHealth(CardNetworkConnection network) {
        this.network = network;
        }
        @Override
        public Health health() {
        try {
        Duration latency = network.echoTest(); // scheme echo message, short timeout
        return Health.up().withDetail("latencyMs", latency.toMillis()).build();
        } catch (RuntimeException ex) {
        return Health.down().withDetail("error", ex.getClass().getSimpleName()).build();
        }
        }
        }

        src/main/java/com/bank/card/ AuthorizationMetrics.java İş metrikleri: etiketler sınırlı değerli (kanal, sonuç); kart numarası ve müşteri id'si asla etiket olmaz.

        src/main/java/com/bank/card/AuthorizationMetrics.java
        @Component
        class AuthorizationMetrics {
        private final MeterRegistry meters;
        AuthorizationMetrics(MeterRegistry meters) {
        this.meters = meters;
        }
        // Tag values come from enums: a handful of time series, whatever the traffic.
        void approved(Channel channel, BigDecimal amount) { // POS, ECOMMERCE, ATM
        meters.counter("card.authorizations", "channel", channel.name(), "result", "APPROVED").increment();
        DistributionSummary.builder("card.authorization.amount")
        .baseUnit("TRY")
        .tag("channel", channel.name())
        .register(meters)
        .record(amount.doubleValue()); // fine for a histogram; never for the ledger
        }
        void declined(Channel channel, DeclineReason reason) { // INSUFFICIENT_FUNDS, SUSPECTED_FRAUD, …
        // NOT tag("pan", …) or tag("customerId", …): a card number in a metric is a data
        // leak, and one time series per card would sink the metrics backend anyway.
        meters.counter("card.authorizations", "channel", channel.name(), "result", reason.name()).increment();
        }
        }

        src/main/java/com/bank/card/ AuthorizationService.java Provizyonu hem metrik hem trace olarak ölçen tek anotasyon.

        src/main/java/com/bank/card/AuthorizationService.java
        @Service
        class AuthorizationService {
        private final AuthorizationMetrics metrics;
        private final CardAccountRepository cards;
        AuthorizationService(AuthorizationMetrics metrics, CardAccountRepository cards) {
        this.metrics = metrics;
        this.cards = cards;
        }
        // One annotation, two signals: a timer metric and a span in the trace.
        // The merchant's terminal is waiting, so this timer is the number the on-call watches.
        @Observed(name = "card.authorize", contextualName = "card.authorize",
        lowCardinalityKeyValues = {"flow", "online"})
        @Transactional
        public AuthorizationResult authorize(AuthorizationRequest request) {
        CardAccount card = cards.findByTokenForUpdate(request.cardToken()).orElseThrow();
        if (card.available().compareTo(request.amount()) < 0) {
        metrics.declined(request.channel(), DeclineReason.INSUFFICIENT_FUNDS);
        return AuthorizationResult.declined(DeclineReason.INSUFFICIENT_FUNDS);
        }
        card.hold(request.amount()); // blocked until the merchant settles
        metrics.approved(request.channel(), request.amount());
        return AuthorizationResult.approved(card.nextAuthCode());
        }
        }

        src/main/java/com/bank/ops/ ManagementSecurity.java Actuator yalnızca iç ağdan; health dışında her şey yetki ister.

        src/main/java/com/bank/ops/ManagementSecurity.java
        @Configuration
        class ManagementSecurity {
        // Matches only requests to actuator endpoints (on the management port).
        @Bean
        @Order(0)
        SecurityFilterChain actuator(HttpSecurity http) throws Exception {
        return http
        .securityMatcher(EndpointRequest.toAnyEndpoint())
        .authorizeHttpRequests(auth -> auth
        .requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll()
        .anyRequest().hasRole("OPS"))
        .httpBasic(Customizer.withDefaults())
        .build();
        }
        }

        Kendini sına

        Şimşek turu1/5

        Liveness, uygulamanın yeniden başlatılması gerekip gerekmediğini sorar.

        Soru 1/2İleri

        Veritabanı kontrolü readiness grubunda. Bütün pod'lar aynı veritabanını kullanıyor ve veritabanı düştü. Veritabanı gerektirmeyen, önbellekten verilen katalog sayfası ne olur?

        Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

        Aklında kalacak üç şey

        1. 1 Liveness yalnızca yeniden başlatmanın düzelteceği şeylere bakmalı. Dış bir bağımlılığı oraya koymak, onun arızasında bütün pod'ları yeniden başlatır.
        2. 2 Readiness pod'u yalnızca trafikten çıkarır. Bütün pod'ların paylaştığı bir bağımlılığı oraya koymak, onun arızasını tam bir kesintiye çevirir.
        3. 3 Metrik etiketleri sınırlı sayıda değerden gelir ve gecikme ortalamayla değil yüzdelikle izlenir. Tek bir isteğin ayrıntısı log ve trace'in işidir.
        Sonraki kapı @Async yazdın ama iş yine de arka plana geçmedi. Kim çağırıyordu? @Async ve Thread Havuzu — Max Neden Hiç Dolmuyor? · 9 dk

        5 kart sonraki derste seni bekliyor

        0/5 kart bu dersten toplandı

        Bu dersin üstüne kurulanlar

        Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.