Dr.Net Core — Health Check Operasyonları

Semih Şenvardar
hesapkurdu-development
7 min readJun 15, 2020

Merhaba,

Geliştirdiğimiz uygulamalardaki çalışabilirliği direkt olarak etkileyen pek çok bileşen bulunmakta. Örnek vermek gerekirse; uygulamanın host edildiği sunucunun disk kapasitesi, veritabanı bağlantısı, caching için kullanılan key-value database ile olan bağlantısı, bağımlı olduğu url adresleri…
Örnekleri epeyce arttırmak mümkün. Monolitik bir uygulamada bile dependent component’lerin anlık durumlarını kontrol etmek pek çok açıdan gerekli iken, mikroservis mimaride birbirleriyle anlık olarak haberleşen çok sayıdaki yapıda neler olup bittiği hakkında kesinlikle bilgi sahibi olmak ve durumlarını takip edebilmek isteriz. Hatta monitoring için kullanabileceğimiz ve customize edebileceğimiz bir dashboard , herhangi bir alarm durumunda bizi haberdar edecek webhook’lar da (örnek slack notification’ları) pastamızın çileği olarak bizleri mutlu edebilir !

Niçin Kullanıyoruz ?

T anında herhangi bir servis instance’ı arka planda çalışır durumda olmasına rağmen kendisine gelen request’leri handle edemeyebilir. (Örneğin veritabanı bağlantısının kaybolması) Bu gibi durumlarda uygulamanın unhealthy duruma gelmesine neden olan sorunu tespit etmek gerekiyor. İmdadımıza yazımızın da konusu olan health check mekanizmaları koşuyor.

Ekibimize Yansıması

Bizim gibi AWS üzerinde application-level load balancer kullanıyorsanız siz de muhakkak health check yapısının ne kadar kritik olduğunu farketmişsinizdir. Container’lar içindeki fargate servis’ler ile çalıştırdığımız task’ları target eden load balancer’lar için de benzer bir health check yapısı mevcut. Load balancer tanımı yaparken belirttiğiniz target group’a ait health check url’i, threshold, timeout ve interval değerleri ile uygulamanızın hangi koşullar altında sağlıklı olduğunu belirtmiş oluyorsunuz. Eğer ELB(Elastic Load Balancer) target group’u içerisinde yer alan task’lara belirttiğiniz değerlerle health check kontrolü yaptığında healthy yanıtı alamazsa fargate servisi o an çalışan task’ı target-group içerisinden deregister ediyor, durduruyor ve yeni bir task ayağa kaldırıyor ta ki health check kontrolünden healthy yanıtı alana kadar. (service foo (port 80) is unhealthy in target-group Foo-TG due to (reason Health checks failed with these codes: [500]). Bu gibi durumlarla daha efektif başa çıkabilmek, uygulamalara bağımlı bileşenleri daha sıkı takip edebilmek ve sorun anında daha hızlı çözüm üretebilmek için Ortadoğu’da kartları tekrardan dağıtmamız gerekiyordu.

Nasıl Uygularız ?

İster mikroservis mimarisi ile tasarlanmış isterse de monolitik yaklaşımla oluşturulmuş yapılarda çözüm yolumuz aynı olacak. Her bir servisin ya da monolit uygulamanın anlık health state’ini (Healthy/Unhealthy/Degraded) bizlere yanıt olarak dönecek olan health check API endpoint’ini kullanacağız. Bu endpoint bizim tanımlayacağımız gerekli health check kontrollerini gerçekleştirecek. Ardından bir dashboard aracılığıyla olan biteni izleyebileceğiz. Failure durumlarında da development ekibimize gidecek olan bir slack notification’ı ile uçtan uca denetimlerimizi sağlayacağız.

İlk olarak yukarıda da belirttiğimiz health status’leri açıklamaya çalışalım:

Healthy: Bileşenlerimizin tümü sağlıklı.
Unhealthy: Bileşenlerimizin en az birinde bir sorun var ya da health check kontrolü yapıldığı esnada unhandled bir exception fırlatılmış olabilir.
Degraded: Bu ise bileşenlerin tümünün sağlıklı olduğunu ancak kontrollerin yavaş veya unstable olduğunu belirtiyor. (Basit bir database sorgusu ile başarılı yanıt alıyoruz ancak execution süresi beklediğimizden yüksek)

ASP.Net Core 2.2 ve sonrası versiyonlarda yer alan built-in middleware’ler aracılığı ile yapılacak olan çok fazla iş hazır setler halinde elimizin altına gelmiş oluyor. Microsoft tarafından resmi olarak destek verilen Microsoft.Extensions.Diagnostics.HealthChecks kütüphanesinden faydalanabileceğimiz gibi, kullanmış olduğumuz pek çok bileşeni hali hazırda destekleyen open-source çözüm AspNetCore.Diagnostics.HealthChecks ‘i de tercih edebilirsiniz. Biz ikincisini tercih ettik çünkü dashboard ve timeline desteği, webhook feature’ı ve desteklediği component sayısının fazlalığı bizim işimizi epey kolaylaştırdı.

İmplementasyon

Asp.Net Core uygulamamız içerisindeki Startup.cs içerisine ConfigureServices ve Configure section’larına built-in health check middleware’lerimizi ekliyoruz.

Uygulamayı çalıştırıp tarayıcıda “/hc” adresine gittiğimizde bizleri Healthy yanıtı karşılıyor olmalı. Şu an kontrol ettiğimiz herhangi bir component olmadığından dolayı uygulamamız healthy durumda. Bu noktadan sonra isterseniz Microsoft’un resmi olarak destek verdiği Microsoft.Extensions.Diagnostics.HealthChecks kütüphanesindeki IHealthCheck interface’ini kullanarak kendiniz ihtiyacınız doğrultusunda custom health check’ler yazabilirsiniz. (Dökümantasyonu burada.) İsterseniz de biraz önce bahsetmiş olduğum AspNetCore.Diagnostics.HealthChecks içerisindeki hazır middleware’ler ile bağımlı component’leri ekleyebilirsiniz. Biz ekip olarak her iki yolu da deneyimledik ancak daha önce de belirttiğim gibi yazımızı AspNetCore.Diagnostics.HealthChecks üzerinden ilerleteceğiz.

AspNetCore.Diagnostics.HealthChecks kütüphanesinin bizlerin kullanımına sunduğu hali hazırdaki health check yapılarından bazıları ise şunlar ;

System, Network, SqlServer, MongoDb, Elasticsearch, Solr, Redis, RavenDb, Kafka, RabbitMQ, Oracle, AWS.S3, Hangfire, SignalR, Kubernetes...

Sql bağlantımızın health check kontrolünü yapabilmek için ilk olarak aşağıdaki komutu Nuget console üzerinde çalıştırmamız gerekiyor :

Install-Package AspNetCore.HealthChecks.SqlServer

Eğer bu kontrolü kendimiz yazmak isteseydik büyük ihtimalle şöyle bir çözüm ihtiyacımızı karşılardı.

İlgili nuget paketini yükledikten sonra Startup.cs içerisindeki ConfigureServices kısmını aşağıdaki gibi güncellememiz gerekli. (Commented line’da custom sqlCheck yapısı implementasyon örneği mevcut)

/hc” endpoint’i default olarak overall bir health check sonucu dönüyor. Eğer component’lerden birinin bile health check sonucu “Unhealthy” ise overall sonuç “Unhealthy” oluyor. Bu sonucu override edebilirsiniz ama component integrity’nin tutarlı olması gerektiğinden pek önerilmiyor.(Component Integrity’yi kısaca açıklamak gerekirse, bütünü oluşturan veya ona bağımlı tüm bileşenlerin bir bütünlük içerisinde tasarlanması diyebiliriz) Sql bağlantımız için de health check kontrolümüzü ekledikten sonra “/hc” adresinde overall sonuç yerine tüm health check sonuçlarını görüntülemek istiyorsak aşağıdaki gibi ufak bir düzenleme yapmamız gerekiyor.

Bu düzenleme sonrası “/hc” adresimizdeki görüntü aşağıdaki gibi olmalıdır.

Monitoring sürecini daha efektif hale getirmek için oluşturacağımız dashboard için ise aşağıdaki Nuget paketini yüklemek gerekiyor.

Install-Package AspNetCore.HealthChecks.UI

Ardından Startup.cs içerisinde ve appsettings.json dosyasında yapacağımız birkaç ayar ile dashboard’umuz kullanıma hazır hale gelmiş olacaktır.

Konfigürasyonlara ait bazı açıklamaları yapmakta yarar var:

EvaluationTimeOnSeconds : Health check kontrolleri arasındaki geçen sürenin saniye cinsinden değeri
MinimumSecondsBetweenFailureNotifications : Health check kontrollerinin failure statüsünde olması durumunda gönderilecek olan notification’lar arasında geçen sürenin saniye cinsinden değeri
Name: Health Check Api ‘yi implemente eden servisin adı.
Uri : Health check verilerini sağlayan endpoint
HealthChecks : Değerlendirilecek olan Health Check Uri’lerini kapsayan liste

Dashboard & Webhooks

Yaptığımız düzenlemeler sonrası UseHealthChecksUI içerisinde belirttiğimiz dashboard adresini tarayıcımızda açtığımızda aşağıdaki gibi bir ekran bizi karşılayacaktır.

Health Check Dashboard

HealthChecksUI yapısı default olarak verileri SQLite veritabanında saklıyor. Bunun için de uygulamanızın ana dizininde “healthchecksdb” adında SQLite veritabanı açarak data’yı bu veritabanı üzerinde persist ediyor. Eğer health check verilerinizi bu şekilde saklamak istemiyorsanız kendi kullanacağınız veritabanınıza ait connection string’i appsettings.json içerisindeki HealthChecksUI section’ında aşağıdaki gibi belirtmeniz yeterli olacaktır.

HealthChecksUI yapısı storage için aşağıdaki pek çok sayıdaki veritabanı çözümünü destekliyor ve her birinin kendine ait nuget paketleri mevcut.

AspNetCore.HealthChecks.UI.InMemory.Storage

AspNetCore.HealthChecks.UI.SqlServer.Storage

AspNetCore.HealthChecks.UI.SQLite.Storage

AspNetCore.HealthChecks.UI.PostgreSQL.Storage

AspNetCore.HealthChecks.UI.MySql.Storage

Ek olarak yazacağınız custom bir CSS dosyası ile dashboard’unuzu dilediğiniz gibi özelleştirebilirsiniz.Aşağıdaki kod satırı ile de hazırladığınız CSS dosyasını HealthChecksUI yapısına import edebilirsiniz.

Notifications

Dashboard’umuzu da oluşturduktan sonra sıra geldi notification kısmına. WebHook’lar aracılığıyla dilediğiniz tool ile entegrasyon yapabilme imkanınız var. Biz ise bu kısımda Slack’i kullanacağız.(Microsoft Teams ve Azure Functions entegrasyon örneği mevcut) Yapacağımız örnekler Slack konfigürasyonu ile alakalı olacak.

Öncelikle “incoming-webhook” uygulamasını Slack içerisine yüklemeniz gerekiyor. Ardından yeni bir configuration oluşturarak hazırlayacağımız JSON payload’larını ileteceğimiz WebHook Url’ini kopyalıyoruz. Bu kısımda notification kısmında gözükecek isim ve ikonu da belirleyebilirsiniz.

Uygulama tarafındaki WebHook ayarlarınızı isterseniz Startup.cs içerisinde, isterseniz de appsettings.json üzerinde yapabilirsiniz. Startup.cs için aşağıdaki gibi bir düzenleme ile Slack üzerinde oluşturduğumuz WebHook’u HealthChecksUI içerisine tanımlayabiliriz.

Eğer appsettings.json üzerinden tanımlama yapmak isteseydik çözümümüz şu şekilde olacaktı.

WebHook yapılandırmasını da tamamladıktan sonra, HealthChecksUI otomatik olarak yeni notification gönderimine başlayacak, Payload ve RestoredPayload property’lerindeki değerler ile de ilettiği notification’ın içeriğini oluşturacaktır. Payload alanları içerisinde yer alan LIVENESS, FAILURE, DESCRIPTIONS bookmark’ları ile de health check kontrolünün fail olduğu durumlarda bunun nedenleri ile ilgili açıklamalar yer alıyor. Burada LIVENESS bookmark’ı, appsettings içerisindeki HealthChecks kısmında Name parametresi ile belirtilen kısmı temsil ediyor. FAILURE ve DESCRIPTIONS ise health check kontrolünün fail olduğu durumun açıklamalarını ve nedenlerini temsil ediyor.

Özetlemek Gerekirse

Health Check mekanizmaları doğru konfigüre edildiğinde gerçekten bizler için rahatlatıcı çözümler üretebiliyor. İsterseniz Microsoft’un resmi desteğine sahip Microsoft.Extensions.Diagnostics.HealthChecks’i tercih edin, isterseniz de zaten bu kütüphane üzerine temellendirilmiş ve gönüllü çalışmalarla epey bir yol katetmiş olan AspNetCore.Diagnostics.HealthChecks’i. Sonuç olarak günümüzde birbirine bağlı servisler/uygulamalar ve bu servislerin/uygulamaların bağımlı olduğu bileşenlerin çalışabilirlik durumlarını takip edebilmek büyük önem arz ediyor. Biz ekip olarak hızlı UI & Dashboard çözümü, webhook entegrasyonları, customizable styling, hızlı component adaptasyonu gibi özellikleri nedeniyle AspNetCore.Diagnostics.HealthChecks ‘i terch ettik.

Kendi sistemimiz içerisinde yaptığımız bu ufak ama önemli dokunuşlar üzerinden çok vakit geçmeden bizlere meyvelerini başlamaya başladı.Production ortamından staging ortamına database restore işlemi gerçekleştiren scheduled job’ların, AWS’deki staging cluster’ında koşan task’ların health check durumlarını failure olarak etkilediğini (database restore sırasında staging database’i yanıt veremez durumda olduğundan dolayı) slack notification’ları ve dashboard ekranındaki details kısmından hızlıca tespit ettik.Ek olarak farklı environment’larda gerçekleşen redis timeout’larını ,url bağımlılıklarımızdaki sorunları eskiye oranla çok daha az eforla ve zaman maliyetiyle çözebilme yeteneğine kavuştuk.

Cloud tabanlı mimarilerde, mikroservis yapılarda veya monolitik uygulamalarda kritik önem taşıyan health check mekanizmaları ile ilgili ekip olarak tecrübelerimizi aktarmaya çalıştık. Bu tür konular ile ilgili destek almak veya bizlerle görüşmek isterseniz dev@hesapkurdu.com adresinden bizimle iletişime geçebilirsiniz. Github üzerindeki örnek uygulamaya ise buradan ulaşabilirsiniz.

Yeniden görüşmek üzere.

Saygılarımla.

--

--

Semih Şenvardar
hesapkurdu-development

just some stuff about software development, sharing is caring i guess.