Nats Streaming Genel Bakış

Tugay Ersoy
8 min readDec 22, 2020

--

Pub/Sub mimari desenini kullanmak için service broker’lardan biri olan Nats’ı bu yazımda ele aldım, umarım faydalı olur.

Nats ve Nats Streaming

NATS pub/sub senaryolarında kullanılan bir service broker ürünüdür. Birçok use case içerisinde kullanılır diğer service broker ürünlerine göre yüksek bir performansa sahiptir.

Disturbed messaging system’ler de 3 farklı semantic mevcuttur. Bunlar At Most Once, At Least Once ve Excualty Once.

  • At Most Once (En Fazla Bir) = Mesaj publisher tarafından gönderilir. Gönderilen mesaj ya da event’in subscriber tarafına kesin ulaşıcağını garanti etmez. Mesaj ulaştıktan sonra consume edilirken bir hata alırsa, tekrar mesajın handle edilmesi mümkün değildir. Bu sebeple en performanslı semantic At Most Once’dır. Nats Core(Nats Server) bu semantic ile çalışır.
  • At Least Once (En Az Bir) = Mesaj publisher tarafından gönderilir. Mesajın subscriber’a ulaşması garanti edilir. Network kesintisi veyahut farklı bir durumdan dolayı mesaj consumer’a tekrar iletilebilir. Nats Streaming At Least Once ile çalışmaktadır.
  • Excualty Once (Tam Olarak Bir) = Mesaj publisher’a bir kere ve kesin ulaşır. En performansız semantic’dir. State bir yerde tutulur ve mesaj iletimlerinde kontrol edilir. Kafka buna örnek bir service broker’dır.

Nats Streaming

Nats Streaming’in Mimarisi

Nats Streaming, içerisinde Nats Server’ı kullanan ve Nats Server’ın üzerine konumlandırılmış bir sistemdir. Nats Server’ın eksik kaldığı ve gerçeklenmesi istenen ek özellikleri içerisinde barındırır.

  • Message/event persistence = Nats Streaming ayarlanabilir bir mesaj persistence sunar. Mesajlar memory’e, file’a veya bir database’e kayıt edilebilir. Bu sayede sunucunun restart yada erişememe gibi bir durumda channellara gönderilen eventlerin kaybedilmesinin önüne geçilir.
  • At-least-once-delivery = Nats Streaming publisher ve subscriber arasında bir onaylama mekanizması sunar. Acknowledgements dediğimiz bu yapıyı Ack mesajları ile sağlar. Gerekli durumlarda event kaybolmadığı için mesajı subscriber’a tekrar iletir.
  • Rate matching/limiting per subscriber = Subscription aşamasında MaxInFlight parametresi verilebilir. Bu sayede bir consumer’a iletilebilecek max Unack(onaylanmamış) mesaj sayısı sınırlandırılır.
  • Durable Subscriptions = Subcription aşamasında durable name consumer için bir durable name verilir. Bu sayede consumer restart durumunda kaldığı yerden mesajı işlemeye devam eder.

Not: Nats Streaming kurulu bir sunucuda, at most once semantic ile de nats server’ı kullanabiliriz.

Client Bağlantısı

Client’lar doğrudan streaming server’a bağlı değillerdir.(streaming server module). Bir bağlantı isteği gönderirler. Bu istek içerisinde client Id parametresi bulunur. ClientId parametresi uniqueliği sağlamak ve subscriptionları sınırlandırmak için kullanılır. Aynı anda iki aynı ClientId streaming server’a bağlanamaz.

Durable subscriptionlar ClientId ve DurableName kombinasyonu ile state’in saklanması için kullanılır.

Nats Streaming kütüphanesi içerisinde bulunan Nats kütüphanesini kullanarak Nats Server’a bağlanır ve dolaylı yoldan Nats Streaming server ile iletişimini sağlar.

Client’ın Nats Streaming’in ayakata olmadığını anlayıp bağlantıyı kesme süresi default 15 sec’dir. Nats Streaming’in client’ın bağlı olmadığını tolere etme süresi default 7dk’dır.

Ayrıntılı Kaynak

Channels

Channel yapısı Nats Streaming Server’ın ana bileşenidir. Channel’lar Clientlar’ın event publish ve consume ettikleri yerlerdir. Channel üzerindeki mesajlar FIFO Queue yapısındadır. Channel’lara isim verilerek Channel Name üzerinden farklı ayarlamalar yapılabilir. Channeler içerisinde yer alan mesajlara belirli limitler verilebilir.

Nat Streaming Server üzerindeki Channel miktarı sınırlandırılabilir.

Default Channel sayısı MAX 100 channel’dır. Ayarlanabilir.

Subscriptions

Client’lar belirli bir channellar ile subscription oluştururlar. Subscription sonlandırılana kadar Server bu subscription için bir state’i saklar. Client’ın subscription kurduğu channel’da bir log var ise bu log o client’a gönderilir. Client tarafında subscription kurulurken client alabileceği max unack haldeki mesaj sayısı verilebilir. MaxInFlight dediğimiz bu sayı client’ın bir t anında alabileceği max onaylanmamış(Ack mesajı gönderilmemiş, işlenmemiş, geriye işlendiğine dair ack mesajı dönülmemiş) mesaj sayısını belirtir. Her bir mesaj için geriye dönülcek Ack mesajının timeout süresini AckWait parametresi verir. Bu parametre sayesinde timeout alındığında mesaj tekrar gerekli consumer’a iletilir. (O event işlensede, işlenmesede)

Dört farklı subcription şekli bulunmaktadır.

  • Regular
  • Regular Durable
  • Queue
  • Queue Durable

Regular

Reguler çalışma mantığı

Bu tip bir subscription’da connection kapatılırsa state korunmaz. Birden fazla uygulama bu tip bir subscription ile abonelik sağladığında her consumer’a(clientId’si farklı olan) bütün mesajlar iletilir.

  • Case 1 = Reguler tip bir subscription gerçekleştirdim. Nats Streaming’in bir consumer için bağlatısını kapatmadan crash olduktan sonra bağlı olmadığımı anlaması için geçen süre olan 7dk(default)’dan daha geç bir sürede aynı clientId ile bağlansam dahi state korunmaz. Çünkü bu tip subscription’da offline ve connection close edildiğinde state korunmaz.
  • Case 2 = Regular tip bir subscription gerçekleştirdim. Nats Streaming anlık bir fail durumu ile karşılaştı. Persistance mod’da eventler saklanırsa(kurumlum bu şekilde yapıldı) consumer bu durumdan etkilenmeden işine devam eder.
  • Case 3 = Regular tip bir subscription gerçekleştirdim. Uygulama bağlantısını kapatmadan crash oldu.7 dk içerisinde tekrar aynı clientId ile ayağa kalktığında kaldığı yerden devam eder.
  • Case 4 = Regular tip bir subscription gerçekleştirdim. Event consumer’a gönderildi. Consumer event’i işlerken bir hata aldı. Geriye 2xx status kodu dışında farklı bir status kod(404 hariç) ile response dönerse bu mesaj tekrar iletilir.(dapr-sidecar ile bu durum gerçekleşiyor, bir sonraki yazımda dapr’den bahsedicem. Nats’ın kendi sdk’sı ile de bu durum kontrol edilebilir.)
  • Case 5 = Regular tip bir subscription gerçekleştirdim. Event bir consumer’a gönderildi. Geriye AckWait süresi zarfınca bir response dönülmezse event nats streaming tarafından aynı consumer’a tekrar gönderilir.

Regular Durable

Regular subscription’dan farkı state’in connection close edilse dahi korunmasıdır. Bunu durablename+clientId unique’liğinden sağlar. Bir uygulama aynı clientId ve durableName ile geldiğinde connection’ı kapansa dahi(Nats Streaming tarafında) tekrar bağlandığında kaldığı yerden mesajları almaya devam eder.

Regular Durable Subscriptionların silinmesi için uygulama tarafında unsubscribe olunması gerekmektedir aksi taktirde bu subscription ghost bir subscription olarak varlığını sürdürür ama offline status’de olduğu için herhangi bir mesaj iletmeyi sunucu denemez.

  • Case 1= Regular durable tip bir subscription gerçekleştirdim. Uygulama crash oldu ve aynı clientId+durableName ile geri connect oldu. Sunucu teslimatı kaldığı yerden devam eder.

Durable subscriptionlarda consumer tekrar connect olduğunda başlangıç noktası göz ardı edilir. Sebebi ise durable subscription’da state’in korunmasıdır. Bu nedenle uygulama geri connect olduğunda kaldığı yerden almaya devam eder.(son gönderilen mesaj sırasının tutulması)

  • Case 2 = Regular durable tip bir subscription gerçekleştirdim. Uygulama crash oldu. Sunucuda 7 dakika boyunca uygulamanın geri dönüşünü bekledi. Uygulama bu süre zarfında geri dönmedi. Sunucu tarafında state korunur ve gelen eventler channel’da bekler. Ta ki bu consumer tekrar gelene kadar. Geldiğinde kaldığı yerden devam eder.
  • Case 3 = Regular durable tip bir subscription gerçekleştirdim. Subscription aktif iken aynı clientId+durableName’de bir consumer daha ayağa kaldırdım. Bu consumer nats’a bağlanmayı dener. Nats hali hazırdaki aktif olan consumer’ın aktif olup olmaduğı teyit eder. Aktif ise bu bağlantıya izin vermez. Aktif değilse aynı clientId+durableName ile yeni gelen consumer’a diğerinin kaldığı yerden event’leri göndermeye devam eder.(diğerinin yerine alır)

Queue Group

Queue Group çalışma mantığı

Farklı clientId’e sahip consumerlar aynı channel üzerinden aynı queue name ile bir subscription gerçekleştirdiğinde bir queue group oluştururlar. Channel üzerindeki bir mesaj queue group içerisindeki sadece bir consumer’a iletilir. Bu süre zarfında queue group’a consumerlar girip çıkabilir ve state tutulduğundan eventlerin işlenmesi kalınan yerden devam eder.

Gelen consumer’ın başlangıç noktası ignore edilir. Sebebi ise queue group içerisinde bir state tutulur ve event teslimatı bunun üzerinden devam eder, consumer’ın başlangıç noktası baz almaz. Queue group içerisinde hiçbir connected consumer kalmaz ise Queue group sonlandırılır. Tekrar başladığında state kaybolduğu için en başta eventleri işlemeye devam eder. Queue Group’un doğası gereği her zaman ordered bir yapı mevcut değildir. Yani redelivery durumlarında yeni mesajların arasına ack dönülmeyen eski mesajlarda girebilir. Order önemli ise regular subscription gerçekleştirilmeli ve MaxInFlight(1) olarak ayarlanmalıdır. Kubernates ortamında birden fazla pod olması ve ölçeklendirme için Queue Group Subscription kullanılabilir. Queue Group subscription oluştururken clientId kullanılmaz fakat nats streaming’e bağlanılması için clientId’nin unique şartı halen geçerlidir.

  • Case 1 = Queue Group name vererek bir subscription gerçekleştirdim. Queue Group içerisine yeni bir member girdi. Mesajlar load balance edilerek random olarak queue’nun memberları arasında paylaştırılır.
  • Case 2 = Queue Group name vererek bir subscription gerçekleştirdim. Queue Group’a bir member daha dahil oldu. Member’lardan biri crash oldu. Bu member’a gönderilen mesaj AckWait’i aşıcağından queue group’un farklı bir member’na iletilir. Ta ki 7dk(default) geçince geri gelmezse crash olan member, subscription’ı sonlandırılır.
  • Case 3 = Queue Group Name verilerek bir subscription gerçekleştirdim. Bir süre sonra consumer crash oldu. 7 dk içerisinde geri gelmedi ve bu süre zarfında da queue group’a farklı bir consumer(farklı clientId’li) dahil olmadı. Bu queue group sonlandırılır ve group’un state’i tutulmaz. Tekrar join olduğunda yeni bir queue group oluşur ve event’ler en baştan işlenmeye devam eder.

Queue Group Durable

Queue Group ve durableName’i aynı olan consumer’lar birleşerek bir Durable Queue Group oluştururlar. Queue Group’dan farkı connectionlar sonlandırılsa dahi Queue’nun state’i korunur. Ta ki unsubscription işlemi gerçekleşene dek.

Durable Queue Group bir subscription oluşturulurken QueueName+durableName şeklinde bir ayrım mevcuttur. Queue’a girmek için aynı QueueName+durableName girilmesi gerekmektedir.

  • Case 1 = Durable Queue Group bir subscription gerçekleştirdim. Queue Group’a bir member daha katıldı. Bir süre sonra iki member’da crash oldu ve 7 dakika içerisinde aynı clientId’li consumer tekrar bir bağlantı gerçekleştirmedi. Böyle bir durumda ilk gelen consumer’ın subscription ve bağlantısı sonlandırılır. Son gelenin bağlantısı sonlandırılır ama subscription’ı sonlandırılmaz offline bir şekilde kalır. Böylelikle state kaybolmadan tutulmaya devam eder. Yeni bir consumer queue’a dahil olduğunda son kalan offline’da sonlandırılır ve tek bir consumer ile kalınan yerden event’ler işlenmeye devam eder.

Cluster Mode

Nats Streaming server’ı Cluster Mode ile kurabiliyoruz. Bu sayede fail over senaryolarında high avability sağlamaktadır. Nats node’lar arasındaki data replication’ı Raft algoritması ile sağlamaktadır. Her bir event node’lar arasında eşitlenmektedir. Aktif olarak t anında stream işlemini sadece bir node yapmaktadır yani scaling sağlanmamakta bu mode ile high avability sağlanmaktadır. Bu sebeple node sayısının fazla olması uygulamanın performansını arttırmaz. 3 veya 5 node clustering mode için yeterlidir. Performansı Fault Tolarance Mode’a göre daha küçüktür.

Fault Tolarance Mode

Single point of failure’ın önüne geçmek için Fault Tolarance mode’da Nats Streaming’i çalıştırabiliriz. Bu mode’da da aynı clustering mode’da olduğu gibi aktif olarak stream yapan bir sunucu mevcuttur. Standby olarak duran server diğerini sürekli düzgün çalışıp çalışmadığını, sağlıklı olup olmadığını kontrol eder. Bir sıkıntı olduğunda shared alandaki kaynakları locklarak Active Server olarak çalışmaya başlar diğer server sağlıklı hale geldiğinde standby olarak görevini sürdürür ve aktif olanın sağlığını sürekli kontrol eder.

Aktif olarak hem ft hem cluster mode’da sunucuları çalıştıramayız. Clustering mode ile partitioning beraber gerçekleştirilemez. Clustering ve partitioning aktif olarak başlatıldığında start up’da service fail alır.

Partitioning

Partitioning sayesinde aynı anda aktif olarak birden fazla Nats ActiveServer’ı ayakta tutabiliriz fakat herbirine belli channelları handle edecek şekilde ayarlamak gerekmektedir.Nats Streaming’i ft mode ve partition ile başlatarak yedekte bir sunucu stanby kalacak şekilde aktif olarak ft grouplar ile channelları ölçeklendirebiliriz.

Channel’lar kesinlikle aynı ft grouplar üzerinde tanımlanmamalıdır. Bu durum duplication’a neden olmaktadır. Ayrıntılı Açıklama

Store Interface

FT mode’da aynı anda aktif olarak sadece bir sunucu stream işlemi gerçekleştirir. İki sunucunun’da ortak eriştiği bir noktada state ve sunucu ile alakalı dosyalar,event’ler yer alır. Bir sunucu aktif çalışıyor iken diğer sunucu buraya erişemez. Aktif olan sunucu burayı lock’lar. Config ile değişiklik yaparak event’leri dosya’ya yada db’ye yazabiliyoruz. Bu sayede restart fail senaryolarında event’ler ve subscription’lar da bir kayıp olmadan stream işlemi devam edebiliyor.

Shared bir alanda yer alan ortak storage alanı hızı ve network’ü güvenli bir yerde yer almalıdır.

Config file içerisinde tanımlanan bütün parametrelerin default değerleri Link içerisinde yer almaktadır.

Bir sonraki yazımda Nats’ın monitoring endpointini inceliyor olacağım.

--

--