Orchestration-Based Saga Pattern Nedir?

Mert Özler
7 min readSep 5, 2022

--

Bu yazıda geçen aylarda projemde kullandığım ve öğrenirken çok keyif aldığım bir patterni size aktarmak istiyorum. Öncelikle orchestration-based saga pattern’i daha iyi anlayabilmek için bazı kavramları açmamız gerekiyor. Bu kavramlara aşikar olmayan yazılımcılar için patternin daha iyi anlaşılması adına yüzeysel bir tanımlama yapıp, gerekli kaynakları verip ardından orchestration based saga pattern’i anlatacağım.

Transaction Nedir?

Transaction veritabanı işlemlerini bir bütün olarak görür ve başarıyı ya da hatayı garanti eder. Böylelikle veri tutarlılığını sağlamamız mümkün olur. Tek bir transaction içerisinde birden fazla insertion, update veya delete işlemi olabilir. Bu işlemlerden herhangi birinin başarısız olması bile rollback (geriye alma) işleminin yapılması için yeterlidir. Böylelikle veritabanı üzerindeki verilerimizin tutarlı, doğru ve tam olması sağlanır. Transaction hedef olarak ACID özelliklerini karşılamaktadır.

ACID Nedir?

Bir transaction’un başarılı sayılabilmesi için ACID prensiplerini karşılaması gerekmektedir. ACID; Atomicity, Consistent, Isolated ve Durable özelliklerini barındırır. Kısaca bu özellikleri açıklarsam;

  • Atomicity: tüm transasctionlar ya başarılı olmalı ya da başarısız olmalılar.
  • Consistency: transaction sonucunda bütün veriler tutarlı olmalı, tutarsızlığın önüne geçmeli
  • Isolation: bir transaction diğer bir transaction tarafından engellenmemeli, etkilenmemeli.
  • Durability: bir transaction sırasında bir hata alınması durumunda veriler bir önceki duruma getirilmeli, yani rollback yapılmalı.

Microservice Nedir?

Microserviceler monolith uygulamalardan farklı olarak yalnızca sistemin küçük bir bölümünden sorumlu, kendi iç mantığını oturtmuş ve ayrı bir parça olarak deploy edilebilen bir servistir. Microservice mimaride birden fazla microservice birbiri ile haberleşebilir ve bu haberleşme ile bir bütün sistemi oluşturarak, sistemin sağlamayı amaçladığı business requirements’i karşılamayı amaçlar. Bağımsızca ölçeklenebilirler fakat microserviceler arası iletişim monolith uygulamaya göre daha karmaşık olabilir ve olası network problemlerinden doğan consistency, erişilebilirlik durumları söz konusu olabilir. Bu gibi durumların önüne geçmek için çeşitli mimari yapılar, design patternler mevcuttur. Daha derin bir okuma için buradaki kaynağı öneririm.

Event-Driven Architecture Nedir?

Eventler geçmiş zamanda gerçekleşmiş iş parçacıklarıdır. Bu mimari yapı distributed systemler arası asenkron ve ölçeklenebilir uygulama geliştirmek için oldukça sık kullanılır. Bir microservice’de bir event tamamlanıp bir başka microservice’ye iletildiğinde bu eventin yaptığı iş bitmiş ve diğer microservice’de başka bir işin tetiklenmesi amaçlanır. Bu sayede eventler üzerinden microserviceler arası iletişim sağlanır ve iş bütünlüğü korunur. Event-Driven Architecture’nin en büyük dezavantajlarından biri consistency’i sağlamaktır. Event-Driven Architecture çok detaylı ve derin bir konu olduğu için detaylı bilgi için buradaki kaynağı okumanızı öneririm.

Local ve Global Transactionlar Nedir?

Saga patterni daha iyi anlayabilmek için local ve global transaction ayrımını göz önünde bulundurmamız gerekmektedir. Event based architecture bir yapıda microserviceler eventler aracılığı ile birbirleriyle konuşurlar. Eventler geçmiş zamanda gerçekleşmiş iş parçacıkları olarak yorumlanabilir ve başka işleri tetiklerler.

Local transaction bir microservicenin kendi içerisindeki veritabanı işlemlerini tamamladığı ve buradaki transactionun tamamlandığı durumlarda kullandığımız isimlendirmedir. Örneğin; Order service kendi iç mantığında order yaratıp, ORDER_CREATED eventini fırlattığı ve bu durumu veritabanında kaydettiğinde bir local transaction tamamlanmış olur.

Global transaction’da ise event-based architecture yapıda birbiri ardına tetiklenen local transactionların takip edilmesi ve olası hata durumlarında rollback senaryolarının oluşturulmasını hedeflemektedir.

Örneğin; ORDER_CREATED eventini dinleyen microservice bu eventin hangi işlemi tetiklemesi gerektiğini bilir ve proje özelinde değişen mantıklara göre bu işlemleri işler.

Saga patternin ortaya çıkış nedeni ve çözmeye çabaladığı sorun tam olarak budur.

Saga Pattern Nedir?

Saga Pattern’e göre distributed system içerisinde gelen istek ile bir sonraki adım, bir önceki adımın başarılı bir şekilde tamamlanması sonrasında gerçekleşir. Olası bir hata durumunda işlemi geri alma, rollback senaryolarının güvenilirliğini , consistencyi sağlamayı amaçlayan ve buna göre aksiyon almayı hedefleyen pattern’dir. Birden fazla microservice’ye yayılan local transactionları yönetmeyi amaçlar. Böylelikle distributed system içerisinde ACID prensiplerini karşılamayı hedefler.

İki çeşit SAGA pattern vardır. Bunlardan birisi merkezi (orchestration-based saga) diğeri ise merkezi olmayan ve direkt olarak local transaction tamamlandıktan sonra diğer microservice’ye event bırakan (choreography-based saga) patternlerdir.

Bu yazıda Choreography kapsam dışı bırakılmıştır, yalnızca merkezi olan saga patterni yani orchestration-based saga patterni inceleyeceğiz.

Orchestration-Based Saga Pattern Nedir?

Orchestration-Based Saga Pattern’in teknik derinliğini anlatmadan önce bir analoji ile anlaşılırlığı kolaylaştırmak istiyorum. Bu patterni bir senfoni orkestrasına benzetebiliriz. Bu durumda senfoni bizim distributed systemimiz olacaktır. Orkestra şefi ise bizim orchestrator’ümüz olacaktır.

Bir orkestrada kemancı, obuacı veya çellocu çok başarılı müzisyenler olabilirler. Kendi önlerinde duran notaları doğru ve tutkulu bir şekilde çalabilirler fakat burada bir senfoniyi icra ettikleri için ortaya çıkan eserin uyumlu olması gerekir. Yani; kemancı, çellocu ve obuacı birbirleri ile uyumlu, eş zamanlı ve tutarlı olarak senfoniyi icra etmelidirler. Tam da bu noktada orkestra şefi bütün senfoninin doğru icra edilmesi ve dinleyicinin tatmin olabilmesi için kemancı, obuacı ve çellocuyu yönetmektedir.

Buradaki çalgıcıları microservislere benzetirsek doğru bir analoji kurabiliriz. Her microservice kendi içerisinde local transactionlarını başarılı bir şekilde yönetiyor olabilir fakat distributed system içerisinde birbirleri ile tutarlı, doğru bir şekilde iş yapamazlarsa ortaya çıkacak senfoni dinleyici asla tatmin etmeyecektir ve parasının boşa gittiğini düşünecektir. Bizim senaryomuza ise bu müşteri kaybına yol açacaktır.

Teknik olarak orchestration-based saga pattern’de geliştirdiğimiz microservice mimarisinde Database per Service pattern’i kullanmayı tercih ettik. Bu durumda kullandığımız her microservice’nin ayrı veritabanı olacaktır. Bu microserviceler yalnızca kendi iş mantığını etkileyen local transactionlar barındırabilir fakat çoğu sistem için microservicelerin haberleşmesi ve global transactionların yönetilmesi gerekecektir. Bu yaklaşıma göre orchestrator subscrible olan tüm consumer’lara ne zaman hangi işi yapacağını ileten bir consumer’dır.

Örnek Senaryo

Bir e-ticaret sitesinde müşterilerin sepetine ürün eklediğini ve sipariş vermek istediklerini düşünelim. Bu durumda sistemimizde order-service, customer-service gibi iki ayrı microservice’nin bulunduğunu varsayalım.

Çoğu durumda microservice mimarisi çok daha karmaşıktır. Örneğin; adress-service, payment-service gibi bir çok servisin bulunmaktadır fakat örneğin anlaşılması için basitleştirmek daha doğru olacaktır.

Order-service ve Customer-service kendi ayrı veritabanlarını kullandığından ve bu iki servis bir bütün olarak sistemi oluşturduğundan dolayı yalnızca kendi local transactionlarında ACID’i sağlamaları yeterli olmayacaktır. Olası hata durumlarında bu iki servis arasındaki veri tutarlılığının sağlanması gerekecektir. Çünkü bir müşteri olarak kredi limitimin yetersiz olması durumunda sipariş verebiliyorsam bu müşteri olarak beni mutlu edebilir :) fakat bussiness olarak ciddi sorunlara yol açaktır.

Problem

Birden fazla microservice arası transaction gerektiren işlemler nasıl sağlanır?

Çözüm

Bu sorunu çözmek için SAGA patterni kullanmalıyız. SAGA bir dizi local transaction bütünüdür. Her local transaction kendi servisinin içerisinde veritabanını günceller ve ACID’i sağlayan local transacation’unu tamamlar. Bununlar birlikte bir event fırlatır ve hedeflenen microservice’deki bir sonraki local transaction’u tetikler. Eğer bir local transaction herhangi bir hatadan olayı hata olursa SAGA pattern bu işlem özelinde daha önce gerçekleşmiş işlemleri geriye alan bir rollback senaryosunu işlemeye başlar. Yani, 3 ayrı microservice’nin bulunduğu bir distributed systemde birbiri ardına tetiklenen local transactionlar içerisinde biri bile hatalı olursa global transaction kendisini rollback eder ve böylelikle distributed system içerisinde consistency sağlanır.

SAGA Pattern implementasyonunda örnek senaryo

SAGA’yı yönetebilmek için iki farklı yöntemimiz mevcuttur.

  • Choreography: Her local transaction bir event fırlatır ve bir diğer microservicedeki local transaction’u tetikler.
  • Orchestration: bir orchestrator merkezi bir şekilde eventleri yönetir. Örneğin; a servisi bir eventi orchestrator’e fırlatır ve orchestrator merkezi bir sistem olarak bu eventten sonra hangi servise hangi eventi fırlatacağını bilir ve birbiri ardına local transactionları tetikler.

Bu yazıda daha önce de bahsettiğim gibi Choreography SAGA pattern kapsam dışı bırakılmıştır, bir sonraki yazıda detaylı bir şekilde üstüne düşeceğim.

Örnek Implementasyon

Yukarıda kısaca bahsettiğim e-ticaret sitesindeki SAGA işlemi için kurulan distributed systemin şeması.

Bu mimari yapıyı kullanan bir e-ticaret uygulaması aşağıdaki adımları izleyen orchestrator temelli SAGA patterni kullanacak ve order-create işlemini tamamlayacaktır.

Message Broker olarak Kafka, RabbitMQ veya diğer message brokerler tercih edilebilir.

  1. Order Service /orders endpointine bir POST isteği alır ve Create Order saga orchestrator düzenleyicisi oluşturur. Yani order service local transaction başlatırken, orchestrator SAGA pattern global bir transaction başlatır.
  2. Order-service kendi local transactionunu tamamlar ve Order’i database’e Pending statusunda kaydeder.
  3. Ardından Reserve Credit eventini Customer Service’ye fırlatır.
  4. Customer Service reserve credit işlemini yapmaya çalışır.
  5. Customer Service kendi iç süreçlerine göre, yani başarılı ya da başarısız olma durumuna göre bir event fırlatır. (Burada hata durumunda rollback senaryosu oluşturulur ve order’in statusu hatalı ya da başarılı olarak değiştirilir.)
  6. Saga Orchestrator Order’in başarılı ya da başarısız olma durumunu Customer Service’den gelen event’e göre belirler ve Order-Service’ye yeni bir event fırlatır.
  7. Global transaction tamamlanır.

Her durum için, local ve global transactionları takip etmek, distributed system içerisinde veri consistency’i sağlamak için state tutmak yönetilen durumları takip etmeyi kolaylaştırır.

Yukarıda bahsedilen adımlardan birine herhangi bir hata olursa global transaction kendi rollbackini yapmak için event fırlatır. Örneğin Reserve Credit işlemi fail olduğunda Orchestrator’a gelen RESERVE_CREDIT_FAILED eventi, orchestrator’un kendi içerisindeki mantığa göre Order Service’ye ORDER_FAILED gibisinden bir event fırlatarak order’in statusunu failed’e çekmeyi amaçlayacaktır.

Global transactionlar ve consistency’i takip etmek için stateler kullanmayı tercih ederiz. Örneğin; CREATED, PENDING, SUCCESS, FAILED, CANCELED gibi stateler verinin sistem içerisindeki o anki durumunu temsil eder. Eventler ile rollback senaryoları yaparken bu stateleri takip etmek hem yazılımcının işini kolaylaştıracaktır hem de distributed system içerisindeki hataların önüne geçmek kolaylaşacaktır.

Avantajları ve Dezavantajları

  • Distributed transaction yönetimini merkezileştirir.
  • Implement etmek ve test etmek kolaydır.
  • Strategy pattern ile projenin geliştirilmesinde yazılımcıya kolaylık sağlar.
  • Rollback senaryolarını yönetmek kolaydır.
  • Yeni senaryolara ve yeni bussiness logic’ler geldikçe Choreography yaklaşımına göre daha az karmaşıklaşır.
  • Altyapı karmaşıklığını arttırır.

Bu yazıda basitçe Orchestration-Based Saga Pattern’i aktarmaya çalıştım. Bir sonraki yazımda Choreography-Based Saga Pattern’i aktarmak ve bu iki patternin implementasyonları ile ilgili bir tutorial videosu çekmeyi hedefliyorum.

--

--