Asp.Net Mvc’de MicroServis Mantığında RabbitMQ ve Dapper ile Error Log Tutma

Selamlar,

Bu makalede, herhangi bir uygulamanın log bilgisinin var olan sistemden bağımsız bir Microservis ile nasıl tutulacağını hep beraber  inceleyeceğiz. Burada amaç çalışan yoğun sistemleri yormadan, farklı işlemler için küçük MicroServislerin asenkron olarak çalıştırılmasıdır.

Öncelikle ben Microservis olarak içinde RabbitMQ kullanan, bir queue ‘dan data çeken basit bir Windows servis oluşturacağım. RabbitMQ ile ilgili detaylı bilgiyi, önceki makalelerimden edinebilirsiniz. Makinanızda Erlang ve RabbitMQ’nun kurulu olması gerekmektedir.

Kaydedilecek data bir error log dosyası olacaktır. Öncelikle ilgili MSSql Error Database’ini ve ErrorLog tablosunu aşağıdaki gibi oluşturalım.

ErrorLog Tablosu:

ErrorLog Class:

Visual Studio 2015 ortamında bir ErrorService adında bir Windows Service projesi aşağıdaki gibi yaratılır.

Nugetten aşağıdaki paketler indirilir:

Program.cs: Aşağıda görüldüğü gibi ilgili windows service, debug modda çalıştırılıp test edilebilmesi için “#if DEBUG”  tanımlaması ile “ErrorListener” sınıfının “DoWork()” methodu çalıştırılır. Bu şeklide gerektiğinde ilgili servisin satır satır test edilmesi sağlanmıştır.

ErrorService.cs: Release Modda aşağıda görülen ErrorService sınıfı çalıştırılmaktadır.

Windows Servisin çalışması için run prompt’da “services.msc” yazılıp yukarıdaki “RabbitMQ” servisinin “Runnig” yani çalışır modda olduğuna bakılmalıdır. İlgili servisin çalışması durumunda, browser penceresine “http://localhost:15672” yazılması ile ilgli RabbitMQ Queue’leri, aşağıdaki gibi görülebilmektedir.

ErrorListener: Sıra geldi esas işin yapıldığı ErrorListener sınıfının yazılmasına. Burada amaç, RabbitMQ’da sırada bekleyen ErrorLog paketlerinin alınması ve herbirinin Dapper ile yukarıda yaratılan MsSql DB’ye kaydedilmesidir. Kaydedilme işleminden sonra ilgili paketin Queue’dan temizlenir.

Aşağıda ilk dikkat edilecek husus sistemden bağımsız bir “new Thread(()=>“‘in çalıştırılmasıdır.

  • Bağlanılacak RabbitMQ sunucusu “localhost“‘dur.
  • Connection ve channel” using ile oluşturulur.
  • channel.QueueDeclare” ile dinlenecek sıranın ErrorLog olduğu, “queue: ErrorLog” ile tanımlanır.
  • channel.BasicConsume” ile ilgili mesaj çekme işlemine başlanır.
  • “while(true)” burada ilgili dinleme işleminin sonlanmayıp, ilgili queue lerin sürekli olarak dinlenmesi sağlanmıştır.
  • consumer.Queue.Dequeue()” methodu ile ilgili queue’den sıradaki “ErrorLog” alınmıştır.
  • İlgili paket içeriği “message“‘a atanmış ve Newtonsoft.Json kullanılarak ilgili message “<ErrorLog>” tipine Deserialize edilmiştir.
  • İlgili “Error” DB’sine ait SqlConnection açılır.
  • Queue’den gelen pakete göre yeni bir “ErrorLog” kaydı oluşturulur. “ErrorLog log = new ErrorLog() { ErrorText= _errorLog.ErrorText, Platform = _errorLog.Platform, ErrorCode = _errorLog.ErrorCode, CreatedDate = DateTime.Now };
  • Dapper sayesinde yanda görülen, tabloya kaydedilecek insert cümlesi oluşturulur. “Insert into [dbo].[ErrorLog]([ErrorText],[Platform],[ErrorCode],[CreatedDate]) VALUES (@ErrorText,@Platform,@ErrorCode,@CreatedDate)
  • Son olarak ilgili query, yandaki gibi execute edilir. “sqlConnection.Execute(sqlQuery, log);

App.config(connectionStrings):

ErrorListener.cs:

İlgili Windows Service’nin yani ErrorService’in Install  edilmesi:

  1. Öncelikle .NetFrameWork’ün kurulu olduğu folder’a command prompt’dan yandaki gibi “Admin” yetkisi ile açılıp gelinir. Sizdeki vesiyonu farklı olabilir. “C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\
  2. InstallUtil.exe “C:\Users\Bora KASMER\Documents\Visual Studio 2015\Projects\Error\ErrorService\bin\Release\ErrorService.exe” komutu çalıştırılır.
  3. Önemli bir nokta”services.msc” komutu ile ilgili “ErrorService”‘e gidilip sağ tıklanıp “Log On” sekmesindeki “This account” SqlServer’ınızdaki User ile aynı olmalıdır. Yoksa ilgili servis DB’ye yazma sırasında hata vermektedir.

İlgili ErrorService’in User’ı aşağıdaki gibi değiştirilir:

SqlDB’ye hangi user ile bağlanıldığı, property penceresinden aşağıdaki gibi görülmektedir:

Error Windows Servis için ProjectInstaller Oluşturma:

ErrorService sağ tıklanıp “Add Installer” seçilir. Projeye “ProjectInstaller” adında bir dosya eklenir. “serviceProcessInstaller1” ve “ErrorService“‘in property ekranları aşağıdak gibidir.

“ErrorService”‘in, install işleminden sonra Servisler kısmında aşağıdaki gibi gözükmesi gerekmektedir. Servise ait “Yetkili User”‘ı değiştirmeyi ve ve tabi ki start etmeyi unutmayın:)

Şimdi sıra geldi ilgili servisi hata durumunda çağırmaya:

ErrorLogTest” şeklinde boş bir Mvc Web Application açıyoruz. 2 sayıyı birbirine böldüreceğiz ve sonucu ekrana yazacağız:

Index.cshtml: Post işlemi ile “Calc” action’ına gidilmektedir.

HomeController.cs: Aşağıda görüldüğü gibi 2 sayının bölümü ve sonucu tekrardan geri dönülmüştür. Örnek basit ama amaç tamamen oluşabilecek hatalara göre MicroServisler kullanılarak asenkron logların tutulmasıdır.

Öncelikle gelin hep beraber ilgili “RabbitMQ“‘ya bağlanılıp nasıl Queue’ya yeni bir “ErrorLog” paketi atılıyor onu inceleyelim.

  • Yukarıda tanımlanan “ErrorLog” modeli, bu projede de yine Model klasörü altına tanımlanır.

Publisher.cs: Burada “localhost“‘da çalışan ve credential istemeyen bir RabbitMQ servisine bağlanılmaktadır. Parametre olarak alınan “ErrorLog” sınıfı byte’a çevrilip “BasicPublish()” methodu ile gönderilmektedir.

Platform(Enum):

Home/Calc() Update: Aşağıda görüldüğü gibi hata olması durumunda “Publisher” static sınıfına ait “SendMessage()” methodu, oluşan hataya göre yeni bir “ErrorLog()” sınıfı oluşturulup parametre olarak gönderilir.

Ayrıca Global Hataların Yakalanması İçin Global.asax’a “Application_Error()” methodun’da aşağıdaki gibi static “Publisher” sınıfına ait “SendMessage()” methodu çağrılmış ve ilgili hata RabbitMQ’ya gönderilmiştir.

Global.asax:

Böylece bu makalede özellikle yoğun tarafik alan bir portalın, var olan sistemi yormadan yapması gereken işleri kendisinin değilde, asenkron olarak MicroServicelere nasıl yaptırdığını hep beraber inceledik.

Bu makalede DB’ye hata loglarını atan bir yapıyı kurgularken, mesajlaşma sisteminde chat kayıtlarını tutan ya da bir portalda güncellenen kayıtların cache’lerini düşüren yapılar da kurguluyabilirdik. Hatta binlerce gelen başvuru formlarını bile bu mikroserviceslere, kolaylıkla asenkron olarak yaptırabilirdik. Birçok farklı Quee sistem bulunmaktadır. MsMq, Kafka, RabbitMQ gibi… Hepsinin kendine göre artıları ve eksileri bulunmaktadır. Bazen hıza önem verilip, güvenliğe çok önem verilmediği durumlarda Quee yerine “Redis Pub/Sub” gibi direk haberleşen yapılara da kullanılabilmektedir. Kısaca bir işin yapılabileceği birçok yöntem vardır. Yeter ki amaca, bütçeye ve ihtiyaca göre en makul teknolojinin, kullanılmasıdır. Bu da hiçbir zaman bitmeyen bir yolculuktur.

Geldik bir makelenin daha sonuna :) Yeni bir makalede görüşmek üzere hoşçakalın.

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

5 Cevaplar

  1. serdar dedi ki:

    Merhabalar;

    Öncelikle bu güzel yazı için teşekkürler. Bir konuda yorumunuzu rica edeceğim:
    Loglama işlemini, sistemden ayrı tutmasaydık eski usül ile aynı uygulama veritabanında bir ErrorLog tablosu oluşturacaktık ve excetion’u yakaladığımız yerde, hatayı bu tabloya direk yazacaktık.

    Yani şu kod yerine:
    Publisher.SendMessage(new ErrorLog() { ErrorText = ex.Message, ErrorCode = _errorCode, Platform = Platform.Web.ToString(), CreatedDate = DateTime.Now, });

    Şöyle bir kodumuz olacaktı:
    ErrorLog.SaveError(ex.Message, errorCode, platform, Datetime.Now);

    Şimdi soru şu: DB’ye kaydetmek ile RabbitMQ servisini çağırmak arasında nasıl bir performans farkı var?

    Teşekkürler

  2. Emre dedi ki:

    Hocam asp.net mvc projelerinizde , mvc nin kendi Authentication ‘unu mu kullanıyorsunuz yoksa kendiniz mi yazıyorsunuz. Profesyönel hayatta nasıl oluyor merak ediyorum
    Teşekkür ederim eğitimleriniz için.

    • borsoft dedi ki:

      Authentication kurumsal firmalarda genelde custom yapılır. Social Login’de(Facebook,Google,Twitter gibi..) vardır. Ama yazılan uygulamanın önem ve güvenlik derecesine göre değişiklik gösterir. Genelde firmaya özel yazılır.

      İyi çalışmalar.

  3. mehmet baran dedi ki:

    Hocam ellerinize saglık. Çok faydalı bir yazı olmuş. Biz de şirket olarak kendi altyapımızda bu sorunu bir thread havuzu olusturarak çözdük. Thread havuzu da benzer sekilde 1producerNconsumer şeklinde loglamaları yapıyor. Threadleri kodlarken tabiki IRegisteredObject kullandık. Aklımıza bunun msmq’lu cozumu de geldi. Fakat kurulumu zorlastırmamak adına tek uygulamada çözmeye çalıştık problemi. Şu an için sorun yok. Fakat bizim öngöremediğimiz bir sorun çıkabilir mi sizce? Yorumlarınızı merak ettim açıkçası.

    • borsoft dedi ki:

      Selam Mehmet,
      Öncelikle teşekkürler.

      Sizin yapıda Loglama İşlemi o an yapılamaz ise kalır. Farklı, yani dağıtık uygulamalar ile çalışmanın faydası, işlem yapılacak microservis patlasa dahi, joblar Queue’de toplanacak ve Microservis ayağa kalkınca sıradaki log işlemleri tekrardan işlenme amaçlı devreye alınacaktır. İşte Queue’nin ve dağıtık mimarinin en büyük faydası budur :)

      İyi çalışmalar.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir