Bir Sql Server’ı MicroServisler Yardımı ile Yedekleme

Selamlar,

Bu makalede, esas amaç var olan bir DB’nin BackUp’ının alınmasıdır. Ayrıca, DB katmanındaki çözüm yolları haricinde, servisler ve yazılım ile bu sorun nasıl çözülür ona deyinilecektir. Bunun için, gecelik tüm DB’nin bir yedeğinin alınması yerine, mümkün olduğunca performanslı bir şekilde, ilgili DB’nin ilk sefere mahsus eşleniğinin alınmasından sonra sadece işlem yapılan kayıtların, aktarılması ile yapılması daha doğrudur. Bu gibi yapılarda, gecelik BackUp alma yönteminin birçok handikapı mevcuttur. Gün içinde yapılan değişikliklerin kaybolma ihtimali ve 50tb gibi DB’lerin kopyalanmasının çok fazla zaman ve sistem gereksinimi istemesi, bunun nedenlerden sadece birkaçıdır. Bu ihtiyaca çözüm olabilecek birçok yol bulunmaktadır. İlk önceliğimiz, Sql üzerine mümkün olduğunca yükün gelmemesini sağlamak ve var olan kodda minimum değişikliğe gitmektir. Anlık en az 50bin kayıdın yazılıp güncellendiği sistemlerde, performans olmazsa olmazlardan biridir.

  • Yedeklenecek DB üzerinde işlem yapılırken bir flag atılarak, Örneğin:(isInsert, isUpdate, isDelete) gibi ilgili data işaretlenebilir. Daha sonra değişen data, başka bir servis aracılı ile monitor edilip diğer bir DB’ye yedeklenebilir. Ama bu hem hali hazırda çalışan sisteme sorgu atılması sureti ile yük getirecek, hem de 50tb veri içinde büyük bir zaman kaybı sağlanacaktır. Aynı zamanda gerçekten silinen dataların da yakalanması imkansız hale gelecektir.
  • Tüm datanın belli bir zaman dilimi içerisinde yedeklenmesi konusuna zaten yukarıda bahsedilen performans karşıtı sebeplerden dolayı hiç değinilmemiştir.

En gerçekçi çözümlerden biri olarak, var olan sistemin haricinde bir Queue mekanizmasının oluşturulması, işlem yapılan dataların Custom Action Filterlar ile bu listeye atanması ve son olarak harici microservicesler ile ilgili queueden her bir datanın çekilerek backup’nın alınmasıdır.

Alttaki komut ile Mvc .Net Core “SqlBackUp” projesi yaratılır.

Uygulama, benim makinamda default ayarları ile çalışmadığı için Program.cs üzerinde aşağıdaki gibi custom “1923” port’u ayarlanmıştır.

Program.cs:

Öncelikle CRUD işlemleri yapılacak “Vehicle” ve Yedeği olucak “VehicleBackUp” modeli aşağıdaki gibi tanımlanır. Var olan DB’deki kolonlardan farklı olarak “OperationType” property’si bulunmaktadır. Bu kolon datada işlem yapılan tipi belirtmektedir.(Insert, Update, Delete) Bu bilginin gerçek DB’de bir karşılığı olmadığı için [NotMapped] şeklinde işaretlenmiştir. Proje içinde, yapılan işlem tipine göre BackUp aksiyonu alınacaktır.

Models/Vehicle:

Models/VehicleBackUp:

Bu projede EntityFramework kullanılmıştır. Bu örnek için yedek alınan tablo gene aynı DB’deki farklı bir tablodur.

DAL/VehicleDataContext:  Projede kullanılan Data Access Layer katmanı aşağıdaki gibidir. Bir BackUp’ı alınacak “Vehicle” tablosu ve bir de yedek almak için kullanılan “VehicleBackUp” tablosu bulunmaktadır.

Şimdi Business yani operasyonel işlerin yapılacağı katmanı yazalım.

Business/IContext: Aşağıda Crud işlemlerin yapılacağı tüm methodlar, ilgili Interface altında tanımlanmıştır. Business altında tanımlanacak “DataContext” bu “IContext” interface’inden türetilmiştir. Kısaca yapılacak işler baştan tanımlanmıştır.

Business/DataContext: Proje içerisinde araçların tüm listesinin alındığı “GetVehicleData()”,  özellikle bir aracın detayınını çekildiği “GetVehicleDataByID()”, yeni bir aracın kaydedildiği “InsertVehicle()” ve var olan bir aracın güncellendiği “UpdateVehicle()” methodları “DBContext” kullanılarak yazılmıştır. Silme işlemi ise bu örnekte yapılmamıştır.

Not: İlgili DBContext’in “using(){}” tagleri arasında kullanılabilmesi için “IDisposable” interface’inden türetilmesi gerekmektedir.

HomeController: Ana sayfaya giden ve ürünleri listeleten “Index()” action’ı, bir ürünün detayının incelendiği detay sayfasına yönlendiren “Detail()” action’ı ve son olarak güncelleme ya da yeni bir kayıt işleminin yapıldığı “Update()” action’ı aşağıdaki gibi tanımlanmıştır. Burada dikkat edilmesi gereken 3 husus vardır.

  1. [ServiceFilter(typeof(BackUpFilter))]: Üstüne tanımlandığı Action sonlandırılırken, “BackUpFilter” sınıfında tanımlı ilgili methodlar çalıştırılır. Böylece işlem yapılan data RabbitMQ’ya atılır.
  2. Tüm data işlemleri “DataContext” sınıfı üzerinden yapılmakta ve var olan projeden bağımsız bir hale getirilmektedir.
  3. Update() methodunda, “OperationTypes” enum tipine göre farklı aksiyonlar alınmaktadır. Ya backup alınacak data güncellenir ya da yeni bir kayıt olarak eklenir.

Models/EnumOperation: Detay sayfasında yapılabilecek tüm işlem tipleri Enum olarak “OperationTypes” tipinde aşağıdaki gibi tanımlanmaktadır.

Business/BackUpFilter: Action Filterlar, .Net Core’da en sevdiğim yapılardan biridir. Makalenin başında da bahsedildiği gibi esas amaç, var olan koda backup işlemi için minimum müdahale etmektir. Bu neden ile aşağıda yazılan Action Filter, DB üzerinde işlem yapan Actionların başına konulmuştur. “IActionFilter” interface’inden 2 method implemente edilmiştir.

1-) OnActionExecuting: Methoda parametre olarak gönderilen “Vehcile” modelinin yakalandığı yerdir. Aslında DB’de backup işlemi, method sonlandığı zaman kısaca işlem başarılı olduğu zaman yapılmaktadır. Ama gelen parametrik model “OnActionExecuted“‘da yakalanamamaktadır. İşte bu nedenle “OnActionExecuting()”‘da ilgili model alınıp, “HttpContext” ile “__vehcile__” değişkenine atanmaktadır.

Burada önemli nokta : ActionFilterlar’da aşağıda yorumlandığı gibi asla 2 Method arasında, değişken gönderilmemelidir. Farklı session state durumları için, ilgili değişken doğru değeri aktarmaya bilir. Bu neden ile  methodlar arasında değişken aktarmanın en sağlıklı yolu, “context.HttpContext.Items“‘dır.

2-) OnActionExecuted : Başarı ile DB üzerinde işlem yapılan “Vehcile” modeli backup amaçlı serialize edilip, RabbitMQ’de “Vehicle” adındaki bir kuyruğa atılır. Makinanızda RabbitMQ kurulu ise, console’da “rabbitmq-server” komutu ile ayağa kaldırılması unutulmamalıdır. RabbitMQ hakkında daha detaylı bilgiye bu makaleden erişebilirsiniz.

Startup.cs: .Net Core’da yazılan custom bir Action Filter’ın kullanılabilmesi için örneğin bu makalede “BackUpFilter”, “ConfigureServices”‘de aşağıdaki gibi tanımlanması gerekmektedir.

Index.cshtml: Index yani Ana sayfasında css olarak Bootstrap kullanılmıştır. Model olarak List of Vehicle almaktadır. İlgili liste gezilerek bir tablo içinde ekrana basılmaktadır. Bu ekran üzerinden ya yeni kayıt girmek için ya da var olan kaydın düzenlenmesi için “Detail” sayfasına gidilmektedir.

Detail.cshtml: Hem yeni kayıt girişinin yapıldığı, hem de var olan kaydın güncellendiği ekrandır.

Son olarak sıra geldi, bir microservis yardımı ile RabbitMQ’daki her bir kaydın sıra ile alınıp “VehicleBackUp” tablosuna atılmasına.

Bu işlem için “dotnet new console -o SqlBackUpService” komutu ile ilgili console application yaratılır.

SqlBackUpService/Program.cs: Bu Microservices de amaç, var olan sistemden bağımsız olarak , Sql DB’de yeni bir işlem yapıldığı zaman sadece işlem yapılan kaydın, RabbitMQ gibi bir kuyruk mekanizmasından alınarak, belirlenen başka bir SqlDB’ye güncellenmesi ya da kaydedilmesidir.

  • “channel.QueueDeclare(queue: “Vehicle”,” : RabbitMQ’da “Vehicle” kanalı tanımlanır. RabbitMQ bu örnekte “localhost”‘da bulunmaktadır.
  • “consumer.Received += (model, ea) =>” : İlgili kanal dinlenmeye başlanır.
  • “VehicleBackUp vehicleBackUp = JsonConvert.DeserializeObject<VehicleBackUp>(data);” : Önemli Vehicle tipinde bir data ilgili RabbitMQ’dan gelmiş olsa da Deserialize işleminde, diğer tabloya kaydedilecek “VehicleBackUp” tipine dönüşütürülmüştür. Zaten 2 tablo da birbirinin eşleniği olduğu için herhangi bir sorun çıkmamıştır.
  • “switch ((OperationTypes)vehicleBackUp.OperationType)” : Gelen modeldeki OperationType’a göre “VehicleDataContext” kullanılarak Insert ya da Update işlemi yapılır. Delete işlemi bu örnekte yapılmamıştır.

SqlBackUpService console application içerisinde aynı Mvc projede olduğu gibi Vehicle ve VehicleBackUp modelleri, EnumOperation ve DAL/VehicleDataContext sınıfları tanımlanmalıdır.

Bu makalede anlık 10bin veya üzeri işlemin olduğu bir DB’de, var olan sistemden bağımsız (RabbitMQ) ve (Microservices) ile sadece işlem yapılan datalar en az maliyetle yedeklenmişdir. Minimum kod ile maximum iş prensibinden yola çıkılarak, “BackUpFilter” adında Custom Action bir Filter yazılmış ve işlem yapılan datalar, RabbitMQ’da bir kuyruğa atılmıştır. Daha sonra sistemden bağımsız başka bir servis ile ilgili kuyruk dinlenerek, kendisine gelen data model(Vehicle), VehicleBackUp tablosuna modeldeki OperationType’a göre ınsert ya da Update edilmiştir. Her şeyden önemlisi yoğun bir yük altında olan SqlDB ve .Net Core Web application, bu yedekleme işleminden bağımsız olarak çalışmasına devam etmiştir. Büyük yük altında olan yapılarda, böyle suya sabuna dokunmadan yapılan harici işler, ya da birbaşka değişle dağıtık mimarı yapısı, yanında ekstra monitor ve bakım maliyeti de getirmektedir.

Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Sorce Code : https://github.com/borakasmer/SqlBackUp

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

4 Cevaplar

  1. Mustafa Kemal dedi ki:

    Hocam, öncelikle elinize sağlık. Ancak SQL Server backup işlemi için neden bir MVC projesi açtığınızı anlayamadım. Günlük oluşan veri farkları için flag’ler oluşturmuşsunuz vs. Bu işlemler DB Admin’lerin sorumluluğunda olmakla birlikte bu arkadaşların çok daha verimli ve stabil tool’ları mevcut; SQL Server Differential Backup Job’ları oluşturuyorlar. Ayda/haftada bir full ve günlük differential backup alma senaryoları mevcut

    • borsoft dedi ki:

      Selamlar Mustafa,

      Öncelikle teşekkürler. Şimdi video’da ve makalede bu soruna detaylıca cevap verdim. Rica ediyorum bir okuyun ya da video’yu 1.5x hızda falan izleyin:) 1.olarak MVC bir proje oluşturmadım. Var olan bir MVC proje üzerine sadece Action Filter ekledim. Neden çalışan bir sistemde, işlem yapılan dataların BackUp’ını almak için. 2.olarak Flagleri hiç kullanmadım. Aksine flag kullanımının yanlışlığını anlattım. Amaç DB’ye hiç yük bindirmemek. Anlık BackUp alma durumunda ve Backup alıncak data 20TB ise ne yapılmalı? Anlık 30bin kayıt işleminin olduğu bir DB’de gecelik Backup alınıyor diyelim. 2 saatlik bir data kaybında bile milyonlarca kayıt gidebilir. Bunun haricinde diyelim ki BackUp durumunda bir bussines var. Yani çalışan bir takım rulelar mevcut. İşte bu gibi durumlarda belki işinize yarar dedim. Yoksa videoda da zaten DB Admin çözümlerinden ve Toolarından bahsettim. Benimkisi fikir verme. Önceden kullandım mı? Kullandım. İşe yaradı mı? Yaradı. Daha iyisi var mı her zaman var. DB Adminin işini DB Admine mi bırakmak lazım. KESİNLİKLE. Peki yoksa bu yönetem denenebilirim. Ne kaybedersiniz :)
      Not: Unutmayın bu işi bir DB Admin yapacak ise hangi toolu kullanırsa kullansın çalışan DB’ye az da olsa bir yük getirecektir. Bu sistemde var olan DB’ye yük “0”.

      İyi çalışmalar.
      Hoşçakalın.

  2. Mustafa dedi ki:

    Makale için Teşekkür ederim. Süper olmuş kendi db’ imde hemen testlerini yapacağım.

Bir cevap yazın

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