Mikroservis Geçişlerinde Databaselerin Ayrıştırılması
Microservis mimarisinin temel kurallarından biri de her servisin kendine ait bir databasei olması gerektiğidir. 5 Mikroservisiniz var ise 5 ayrı databaseiniz, 10 mikroservisiniz varsa 10 ayrı databaseiniz olması gerekir yani servisleri ayrıştırdığımız gibi databaseleri de ayrıştırmamız gerekir. Bunun arkasında yatan sebepler ve faydalarına değinmek gerekirse, ben kafamda genelde bu faydaları bir işin ana özü, anlamı bir de teknik sebepleri olarak ayırıyorum. Bu şekilde akılda tutmak daha çok hoşuma gidiyor.
İlk olarak databaseleri ayırmanın arkasında yatan anlam üzerine düşünelim. Her mikroservis sadece kendi işini yapmak için özelleşmiş, küçük, domain sınırları belli olan bir servistir ve kendi datasını kendisi yönetir. Sizin bir domainin datasına erişebilmek için o domaninin, domain kuralları üzerinden geçmeniz gerekir. Object oriented dünyanın yaşadığımız dünyayı modellemek olduğu gerçeği üzerinden, mikroservis örneğini günlük hayattan bir benzetmeyle somutlaştıralım. Bir şirketin finans departmanında çalıştığınız düşünün. Şirketin finans dışında muhasebe departmanı, satın alma departmanı vs gibi departmanları olsun. Finans departmanı olarak yapacağınız herhangi bir iş için satın alma departmanının elindeki verilere ihtiyaç duyduğunuzda gidip, departmandan birinin çekmecesinden çat diye belgeleri alabilir misiniz? Ya da daha dijital düşünelim, finans departmanında birisi satın alma departmanının database tablolarına direkt ulaşabilir mi? Eğer ki başka bir departmanın elindeki bilgiye ihtiyaç duyuyorsanız uygun bir şekilde talebinizi iletirsiniz ve o talep ilgili birimin yöneticisine ya da sorumlusuna gider. Sorumlu da size ihtiyaç duydugunuz bilgileri verir. Burada her bir departmanı mikroservislerimiz, departman bilgilerini de mikroservislerin databaseleri olarak düşünebilirsiniz. Ayrıca mikroservis veriyi sadece ilgili diğer servise vermekle kalmaz o veriyi verirken kendi genel business rulelarından geçirerek verir. Aynı sizin satın alma departmanından bir evrak veya belge talep ettiğinizde sınırsızca tüm bilgileri alamamanız, ekibin kendi içerisinde ve şirket kültürü gereği sahip olduğu kurallar çerçevesinde sınırlandırılmış bilgileri alabiliyor olmanız gibi.
Teknik olarak ise, mikroservis mimarisinde, her servisin diğer tüm servislerden bağımsız bir lifecylei olmasını isteriz. Eğer tüm servisler aynı DB’ye bağlı olursa ve bu DB down olursa tüm servisler down olacaktır ve aslında biz mikroservislerin en önemli faydalarından biri olan decouplingi kaybetmiş olacağız. Ayrıca her servisin domaini için farklı database teknolojileri daha uygun olabilir. Örneğin bir servis için RDBMS daha uygun iken diğer servis için NoSQL çözümleri ya da graph based bir DB çok daha uygun olabilir. Ayrıca dağıtık sistemlerin en önemli kazanımlarından biri olan single point of failuredan kurtulmus olacağız.
Bu genel bilgiden sonra mikroservis mimarisine geçiş sırasında databaseleri ayrıştırırken karşılaşabileceğimiz sorunlar ve çözümler üzerine bir şeyler karalamaya başlayabilirim sanırım.
1. Foreign Key İlişkisi Olan Tabloların Ayrıştırılması
Mikroservis mimarisinde tabloları ve databaseleri ayrıştırırken en sık karşılaşılan ve üzerine düşünülen konulardan biri foreign key ilişkisi olan tabloların dblerinin nasıl ayrıştıralacağıdır. Bu başlığı bir örnek üzerinden ilerletelim. Bir catalog bir de finance domainimiz olsun. Finance domaninin tablosu Catalog domaininin tablolarını kullanıyor olsun. Mikroservis mimarisine geçiş yaptığımızda catalog ayrı bir mikroservis, finance da ayrı bir mikroservis olacaktır. Dolayısıyla bu servislerin databaseleri de ayrı olacaktır. Peki ya foreign key ilişkisi?
Bunun için iki yerde değişiklik yapmaya ihtiyaç duyabiliriz. Birincisi artık finance servisi direkt olarak catalog tablolarına erişmemeli. Bu db catalog servisinin sorumluluğunda olmalı ve finance servisinin de catalog dbsine erişip kendi kurallarına göre database verilerini işletmesini istemiyoruz. İstediğimiz şey katalog verilerinin her daim catalog servisinin sorumluluğunda olması. Buradaki çözüm finance servisin artık verilere direkt olarak erişmek yerine catalog servis üzerinden alacak olmasıdır. Tabi burada ayrı bir durum ortaya çıkıyor. finans servisin dataları direkt almasıyla catalog servis üzerinden alması arasında ne fark var? HIZ/ZAMAN, aynı şey mikroservisler için de geçerli. Burada da tradeoff devreye girer.
2. Statik Data Tablolarının Servisler Tarafından Paylaşılması
Database ayrıştırmadaki bir başka konu da statik data tablolarının paylaşılmasıdır. Örneğin, ülke isimleri, diller, para birimleri vs gibi tablolarınız olduğunu varsayın. Bu ortak datalar herhangi bir servise ait datalar değil. Bu durumda nasıl ilerlemeliyiz? Bunun ile ilgili bir kaç yaklaşımdan bahsedebiliriz.
Birinci yaklaşım, hepimizin ilk aklına gelen tabloları her bir servis databasei için çoklamak ancak bu potansiyel consistency sorunlarını da beraberinde getirir. Bir database’deki statik veri tablosunu update ettim. Peki ya diğerleri? Diğer tüm mikroservislerin databaseleri? Ortak bir update triggerı yazsak bu sorun çözülür mü yoksa mikroservislerin doğasına aykırı bir hareket mi yapmış oluruz?
Bir diğer yaklaşım da dataları kodun içeriside statik olarak tutmaktır. Tüm statik dataları enum şeklinde kodda tutabiliriz. Tabi ki bu da değişkenlerdeki herhangi bir değişikliğin deploy ihtiyacı doğurması anlamına gelir. Bunun yanında bu çözüm de aslında data consistency problemini ortadan kaldıran bir çözüm değil.
Üçüncü yaklaşım ise datalar için ortak bir look up servis yazıp bu servisi kullanmaktır.
3. Ortak Paylaşılan Dataların Ayrıştırılması (Modellenmemiş Domain Problemi)
Biraz daha kompleks ve yaygın bir sorunla devam edelim. Ortak kullanılan datalar. Finans ve muhasebe örneğinden devam edelim. Iki domain de ortak olarak müşteri datalarını dolayısıyla müşteri tablosunu kullanıyor olsun. Hatta aynı tabloya hem yazıyor hem de tablodan okuyor olsunlar. Böyle bir durumda nasıl ilerleyebiliriz?
Aslında burada ana sorun farklıdır. Sorun sistemde databasede modellenip kodda modellenmeyen bir domain olmasıdır. Demek istediğim, olması gereken Customer domaininin mikroservis mimarisinde modellenmemesidirr. Burada çözüm Customer domainini de microservis mimarisine dahil ederek, bu domaini oluşturup bu domain üzerinden call yapmalıyız.
4. Tablonun Kullanılan Ayrı Kolonlarının Servisler için Ayrıştırılması (Normalizasyon Problemi)
Bir diğer farklı sorun da ortak kullanılan tablo kolonlarıdır. Yine aynı benzer senaryolar üzerinden ilerleyelim. Finans ve Muhasebe domainleriniz bir şekilde aynı monolitik uygulamada yer alıyor ve ortak bir tabloyu kullanıyor olsun. Finans domaininiz tablonun belli kolonlarını, Muhasebe domaininiz de belli kolonlarını kullanıyor olsun ve Mikroservis mimarisine geçmeye karar verdiğiniz. Burada da bir sorun ortaya çıkıyor. Aslında buradaki sorun mikroservis mimarisinin dışında eskiden kalan teknik borcunuz olabilir. DB normalizasyonu… Object tablolar yaratmak, buna kafa yormak yerine tabloları sürekli yana doğru genişletmenin getirdiği teknik borç mikroservis mimarisine geçiş yaparken ortaya çıkmıştır. Buradaki çözüm database tablosunu ilgili domainlere göre normalize edip ayrıştırmak olacaktır.