Nedir bu “ Transactional Messaging”

emre tiryaki
hepsiburadatech
Published in
4 min readJan 29, 2020

Event driven mimarisi ile geliştirme yapıyorsanız karşınıza çıkması muhtemel problemlerden birisi de transactional bir ortamda yani transaction.commit() ile beraber transaction devam ederken oluşan domain event’leri kaybetmeden nasıl yayınlayabiliriz (publish) olmuştur. Yazının içeriği “Transactional Messaging”ın neden ortaya çıktığı, hangi sorunu çözdüğü, günümüzdeki implemantasyonları ve kullanımında sıklıkla yaşanılan hatalar hakkında olacaktır.

Eventleri kaybetmeden nasıl yayınlayabiliriz?

MSDTC

Yöntemlerden birisi DTC idi. Her ne kadar bu konsept daha geniş bir konu olsa bile “Microsoft Distributed Transaction Coordinator”’u amacınız için kullanabilirsiniz. Fakat microservice , linux, rabbitmq, kafka , nosql db kelimelerini duyunca muhtemelen MSDTC’den vazgeçeceksiniz. MDTC gibi araçlar yüksek yük aldığınız zamanlarda performansınızda çok ciddi problemlere yol açacaktır.

Transactional Outbox

Yukardaki örnekte bir müşterinin kayıt olmaya geldiğini düşünelim. Uygulamanız kullanıcıyı kayıt ettikten sonra eventlerini yayınlanmaya başlar. Message Broker’a -ki burada rabbbitmq tercih ettik- publish ederken herhangi bir sebepten ötürü hata aldığımızda (timeout / network failure) muhtemelen eventler message broker’a bu sebeple diğer sistemlere iletilmemiştir ve en korktuğumuz senaryo “data inconsistency” oluşacaktır. Müşteri uygulamanızda kayıt edilmiştir fakat uygulamanızdan beslenen eventleri dinleyip notification gönderen diğer uygulamanız ise event publish edilmediği için “hoş geldin” maili atılmayacaktır. Bu en şirin senaryo, üzerinde muhasebe daha doğrusu para akışı olan sistemlerinizde böyle bir problem söz konusu olması hepimizin korkulu rüyasıdır. Mutsuz müşteri yada mutsuz satıcı e-ticaret firmalarında ciddi problemlerdir.

Chris Richardson’ında belirttiği “Transactional outbox” pattern’i burada uygulayabiliriz. Bu yöntemin amacı transaction içinde (mongo’da 2PC) hem kendi datalarınızı güncellersiniz hemde eventleri aynı transaction içerisinde OUTBOX adı verilen bir tabloya eklersiniz. Aşağıdaki örnekte:

  1. OrderService kendi dökümanlarında CRUD işlemleri uygular. OutBox tablosuna ürettiği eventleri yazar.
  2. Başka bir uygulama üretilen bu eventleri okur ve broker’a publish eder.
Transactional Outbox

NOT: Peki iletilen bu eventler ne olacak? Dikkat edilmesi gereken ve yapılan en büyük yanlışta budur. Bu tablonun geçici olması gerekmektedir. Outbox’ı mailbox gibi düşünebilirsiniz, FIFO gibi çalışır. Bu tabloda publish edilen event mutlaka silinmelidir. Çünkü bu Event Store değildir. Event Sourcing‘de eventler store edilir ve oluşan bu eventleri konseptin getirdiği başka bir çözüm ile yani snapshot ile küçültülebilir. Örnek vermek gerekirse OMS domaini aylık 87 milyon civarı event publish ettiği bir yerde outboxda event store etmek çok mantıklı bir tercih değildir.

Transaction Outbox’ı uyguladığınız zaman karşınıza çıkacak problem ise bu eventleri nasıl bir yolla publish etmeliyim? Bunun uygulandığı 2 yöntem bulunmaktadır. (Pulling Publisher ,Transaction log tailing)

  1. Pulling Publisher
    Adından anlaşılacağı üzere belirli bir zaman aralığında outbox tablosundan eventlerin çekilip publish edilmesi , ardından publish edilen bu eventlerin silinmesi üzerine bina edilmiş bir yapıdır. Yukarıdaki resim bu sistemi anlatan bir temsili gösterimidir. Belirli zaman aralığını düşürdükçe db’ye sorgu çekmek yüksek ölçekli sistemler için performans kaybı oluşturacağını unutmamak gerekmektedir. Bu yapının en büyük dezavantajı budur. Bununla beraber publisher uygulamasını scale ettiğiniz zaman aynı eventi farklı instance’ların işlememesine dikkat etmeniz gerekmektedir. Bunun için mssql’de uplock (prevent multiple read) , nosql db’lerde ise findandmodify kullanabilirsiniz. Böylece publisher uygulamasını slace edebilirsiniz. Avantajı ise implemantasyonu ve kullanılması basittir.
  2. Transaction log tailing
    Bu yöntem ise aslında kullandığınız database’in transaction loglarını okuyarak değişiklikleri publish etmektir. Bu yöntem EventStore’da da kullanılan yöntemdir.

Transaction loglarını okuyarak publish etmek daha sofistike bir işlemdir. Bunu sizin için yapan bazı open source projeler bulunmaktadır. Bu yöntemin dezavantajı ise eğer log miner yazacaksanız low-level seviyede domain kodlarınız bulunabilir.

Bu bilgiler ve yaptığımız POC’lerle, Outbox ve Pulling Publisher yöntemini tercih ettik. Bizim için zorluk, outbox tablosundan okuyup eventi publish eden uygulamanın scale edilebilmesiydi. Çünkü dakikada 2K event’in publish edildiği bir uygulamanın scale edilme yeteneği olmazsa artan hacimde ve kampanya günlerinde artan yükle beraber burada bir bottleneck oluşacaktı. Yukarıda da belirttiğim üzere Mongo’nun FindAndModify fonksiyonu ile genişletilebilir hale getirebildik. Transaction log tailing yapısı elbette kullanılabilirdi, fakat gereksinimden daha fazlasını uygulamak over-enginering (wikipedia tabiriyle bir ürünün uygulanması için gerekenden daha sağlam veya karmaşık olması) olacağını düşündüğümüz için şu anda pulling publisher yöntemini kulandık. Fakat biliyoruz ki birgün daha da artan hacimle beraber bir streaming yapısı olan log tailing yapısına geçememiz şart olacaktır.

--

--