Mikroservis Bir Hedef Değildir

Bir yazılım projesi büyümeye başladığında mimari konuşmalarının mikroservislere gelmesi neredeyse kaçınılmaz. Servislerin bağımsız deploy edilmesi, ayrı ayrı ölçeklenebilmesi ve ekiplerin birbirinden bağımsız hareket edebilmesi oldukça cazip.

Sorun şu: mikroservislerin avantajlarını almak için önce dağıtık sistemlerin maliyetini kabul etmek gerekir.

Aynı process içindeki bir metod çağrısını başka bir servise taşıdığınız anda artık network timeout’ları, retry stratejileri, distributed tracing, servis keşfi, veri tutarlılığı ve deployment koordinasyonu gibi problemleriniz vardır.

Martin Fowler’ın mikroservis çalışmalarında da altını çizdiği noktalardan biri tam olarak budur: bağımsız deployment ve güçlü modül sınırları önemli avantajlardır; buna karşılık dağıtık sistem olmanın ciddi bir operasyonel maliyeti vardır.

Asıl problem monolit değil, kötü sınırlar

Monolit dendiğinde çoğu kişinin aklına binlerce sınıftan oluşan, her şeyin her şeyi çağırdığı eski uygulamalar geliyor.

Bu aslında monolit olmanın değil, modüler olmamanın sonucudur.

İyi tasarlanmış bir modüler monolitte örneğin Payment, Order, Customer ve Notification birbirinden açık sınırlarla ayrılabilir. Modüller aynı application artifact içinde deploy edilir ama birbirlerinin tablolarına veya internal sınıflarına kontrolsüz biçimde erişmez.

Bu yapı önemli bir avantaj sağlar: domain sınırlarını öğrenmeden distributed system vergisini ödemezsiniz.

Mikroservis sınırlarını yanlış belirlemek, yanlış sınıf sınırından çok daha pahalıdır. Bir sınıfı yeniden organize etmek kolaydır. Üretimde bağımsız deploy edilen iki servisin verisini, API sözleşmesini ve event akışını yeniden birleştirmek ise değildir.

Ne zaman mikroservis anlamlı hale gelir?

Benim bakacağım ilk sinyal trafik olmazdı.

Bir uygulama monolitken de load balancer arkasında onlarca instance ile yatay ölçeklenebilir. Fowler’ın mikroservis açıklamasında da monolitlerin horizontal olarak çoğaltılabileceği açıkça belirtiliyor.

Daha anlamlı sinyaller şunlardır: belirli bir domain’in diğerlerinden farklı ölçeklenmesi, ekiplerin deployment sırasında sürekli birbirini beklemesi, bazı modüllerin farklı availability gereksinimine sahip olması veya domain sahipliğinin organizasyon içinde net biçimde ayrılması.

Örneğin ödeme sistemi saniyede yüz işlem yaparken bildirim sistemi yüz binlerce event işliyorsa iki modülün aynı ölçekleme stratejisinde kalması anlamsız hale gelebilir.

Ama üç kişilik bir ekipte altı mikroservis varsa, çoğu zaman mimari işinizi kolaylaştırmıyor; sadece dağıtılmış bir monolit üretmiş oluyorsunuz.

Ben hangi yolu tercih ederim?

Yeni bir projede domain henüz tam bilinmiyorsa iyi sınırlandırılmış bir modüler monolit güçlü bir başlangıç noktasıdır.

Modüller arasında API benzeri kontratlar oluşturun. Database ownership sınırlarını koruyun. Cross-module erişimi kontrol altına alın. Integration event’leri gerektiği yerde kullanın.

Sonra gerçek bir operasyonel gerekçe ortaya çıktığında ilgili modülü ayırın.

Bu yaklaşım mikroservislerden vazgeçmek değildir. Tam tersine, mikroservise neden geçtiğinizi bilerek geçmek demektir.

Mimarinin kalitesini servis sayısı belirlemez. Doğru sınırların doğru yerde olması belirler.