16 Nisan 2020 Perşembe

Health Check and Monitoring - .Net Core ( Servislerin Durumunu Kontrol Etme ve Görüntüleme)

     S.A. Arkadaşlar,
     Bugün .net core 2.2 ile gelen ve 3.1 ile olgunlaşan bir kavramı ele alacağız. Dağıtık bir yapınız var ve bunun içinde onlarca belki yüzlerce servis bulunmaktadır. Her bir servis kendi içinde çalışacağı için de hepsini kontrol etmek zor belki imkansız olacaktır. İşte bu ihtiyaçtan meydana çıkmış ve tüm servislerin durumlarını kontrol eden yapıya Health Check denmektedir. Bu yapıyı kullanıcı ara yüzü ile birlikte ayağa kaldıracağız. Hazırsak başlayalım.
     Dağıtık bir mimaride yüzlerce servis olabilir demiştik. Örneğin, ödeme servisimizde bir problem var. Sistem burada çalışmasına devam edecektir, fakat ödeme işlemi yapılamayacaktır (eski tekli yapıda olsaydı, sistem tamamen çökecekti, bu yüzden de hemen haberimiz olacaktı :) ). Burada bir hata oluşmasını anlık almak istiyoruz. Çünkü bu servisimiz bize direkt parayı kazandıran kısımdır. Bunu müşteriye yansıtmadan en hızlı şekilde çözmek isteyeceğiz. Bundan haberimiz olması için arka planda çalışan bir sistemin kurulu olması lazımdır. Böylelikle bu probleme en hızlı şekilde müdahale edebilelim.

     Burada başka bir konu ise sadece bozulan/çalışmayan servisleri ele almıyoruz. Ayrıca, tüm servislerin son durumları, cevap alma verme süresi, o servisteki yoğunluk gibi bir çok parametre bulunmaktadır. Tüm bunları çok rahatlıkla takip edebiliriz. Bir bakıma acil müdahale masası görevi görmektedir desek yanılmış olmayız herhalde.

     Bu yapı ayağa kaldırırken bir ara yüz de oluşturuyoruz. Böylece her şeyi çok daha rahat bir şekilde takip edebiliyoruz. Her hangi bir problemi ekranlardan kontrol edebiliyor, gerekli raporlar alabilir veya acil durumlar için alarmlar kurabiliriz.

     Şimdi kabaca ne iş yaptığını nasıl çalıştığını az çok anlattık. Artık biraz da kod tarafına geçmemiz gerekmektedir. Ama bunu yapmadan önce 2.x sürümlerden 3.x'lere geçerken büyük değişiklikler oldu. Bununla ilgili daha ayrıntılı bilgiye buradan ulaşabilirsiniz. O yüzden kodlarımızı mümkün mertebe her iki ortam için de paylaşmaya özen göstereceğim.

     Kod kısmına yavaştan geçme vakti geldi. .Net Core Web API projesi açarak işe başlıyorum. .Net Core 3.1 (LTS) kullanıyorum, ama 2.1 için de bazı uyarılarda bulunmaya çalışacağım.

     Şimdi Startup.cs açalım ve servisimizi oraya ekleyip çalışması gerektiğini söyleyelim.
public void ConfigureServices(IServiceCollection services)
{
    //aşağıda PingHealthCheck adında sınıfımızı oluşturacağız.
    // bu şekilde 3 çağrıda bulunacağız
    // Paketi kurulumu isterse nuget manager üzerinden aşağıdaki komutu çalıştırabilirsiniz
    //  Install-Package Microsoft.Extensions.Diagnostics.HealthChecks
    services.AddHealthChecks().
       .AddCheck("ping1", new PingHealthCheck("google.com", 100))
       .AddCheck("ping2", new PingHealthCheck("google.com", 10))
       .AddCheck("ping3", new PingHealthCheck("1.2.3.4", 100));
    
    //Servislerin durumunu görüntülemek için kullanılır
    //AspNetCore.HealthChecks.UI paketi nuget'ten indirilmelidir.
    services.AddHealthChecksUI(setupSettings: setup =>
        {
             setup.AddHealthCheckEndpoint("endpoint", "/healthz"); 
        });
}
// 2. parametre olarak 3.1 için IWebHostEnvironment, 2.1 IHostEnvironment olmalı.
public void Configure(IApplicationBuilder app)
{
    app.UseRouting();app.UseEndpoints(config =>
    {
         //AspNetCore.HealthChecks.UI.Client paketi nugetten indirilmelidir.
         config.MapHealthChecks("/healthz", new HealthCheckOptions
         {
              Predicate = _ => true,
              ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
         });
         config.MapHealthChecksUI();
     }); 
}

    Şimdi örnek senaryomuzu anlattıktan sonra koda devam edebiliriz. Belirli URL veya IP adreslerine ping atacağız. Buna göre 3 tane cevap alma ihtimalimiz var. Bunlar:
  •    Healthy: Her hangi problem yaşanmaz ve cevap dönerse dönmektedir.
  •    Unhealthy: Cevap başarılı olmazsa cevap dönmektedir.
  •    Degraded: Cevap başarılı fakat belirlenen sürede dönmezse bu cevap dönmektedir.

    Şimdi örnek bir sınıf oluşturup IHealthCheck implemente edelim.
public class PingHealthCheck : IHealthCheck
 {
     private readonly string _host;
     private readonly int _timeout;

     public PingHealthCheck(string host, int timeout)
     {
         _host = host;
         _timeout = timeout;
     }
     //IHealthCheck birlikte geliyor. İçini dolduruyoruz.
     public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
     {
         try
         {
             using var ping = new Ping();
             var reply = await ping.SendPingAsync(_host, _timeout);
             if (reply.Status != IPStatus.Success)
             {
                 return HealthCheckResult.Unhealthy();
             }

             if (reply.RoundtripTime >= _timeout)
             {
                 return HealthCheckResult.Degraded();
             }

             return HealthCheckResult.Healthy();
         }

         catch
         {
             return HealthCheckResult.Unhealthy();
         }
     }
 }

     Tüm ayarları yaptıktan sonra şuana kadar yaptıklarımıza tek tek bakalım.

//localhost:port/healthz 
{"status": "Unhealthy","totalDuration": "00:00:01.3719082","entries": {"ping1": {"data": {},"duration": "00:00:01.2409108","status": "Unhealthy"},"ping2": {"data": {},"duration": "00:00:01.1894751","status": "Unhealthy"},"ping3": {"data": {},"duration": "00:00:00.1491420","status": "Unhealthy"}}}
//localhsot:port/healthchecks-api buradan da api'ye bakabiliriz
[{"id": 1,"status": "Unhealthy","onStateFrom": "2020-04-11T15:46:37.5861565+03:00","lastExecuted": "2020-04-11T15:48:54.1799232+03:00","uri": "/healthz","name": "endpoint","discoveryService": null,"entries": [{"id": 1,"name": "ping1","status": "Healthy","description": null,"duration": "00:00:00.0488270"},],"history": []}]
//localhost:port/healthchecks-ui buradan da ui kısmına bakabiliriz

    Genel durum sağlıksız, çünkü çalışmayan en az 1 tane servis bulunmaktadır. Eğer tüm koşullar sağlıklı olsaydı, genel durum da sağlıklı olacaktı.

     Şimdi tek tek durumları incelersek;
  • 1.ping sağlıklıdır. Belirlenen adres ve sürede her hangi bir sorun meydana gelmemiştir.
  • 2.ping belirtilen adrese ping atmıştır fakat beklenen sürede gerçekleşmemiştir.
  • 3.ping ise böyle bir adrese ping atamamıştır. Bu yüzden sağlıksızdır.

    Böylece bir yazımızın daha sonuna gelmiş bulunduk. Elimden geldiğince yalın bir şekilde anlatmaya özen gösterdim.

   Her daim sağlıklı servisler çalıştırmak dileğiyle.
 
   Kaynaklar:

Hiç yorum yok:

Yorum Gönder