Kafka Terminolojisi ve Mimarisi

Apache Kafka son yıllarda başta microservice olmak üzere yeni nesil mimarilerin ve büyük oranda veri ve/veya olay akışlarıyla çalışan uygulamaların temel bileşenlerinden biri haline gelmiş bir yapıdır.Bu yazı serisinde ilk önce Kafka’nın terminolojisi, mimarisi ve nasıl çalıştığından bahsedip, bir sonraki yazılarımda sırayla kurulum ve bazı iyi uygulama örneklerine değineceğim.

Kafka dağıtık, kolay ölçeklenebilir, hataya dayanıklı ve sürdürülebilirliği yüksek bir veri/olay akış aracıdır. Çok büyük miktarda veriyi eş zamanlı karşılamasının yanında veriyi üreten kaynaktan okuyup arkada tüketecek sisteme 10ms’nin altında aktarabilecek bir kapasiteye sahiptir. Peki, Kafka ne gibi senaryolarda kullanılmaktadır;

  • Büyük ölçekte IoT metriklerinin veya uygulama loğlarının toplanacağı, yüzlerce hatta yüz binlerce kaynaktan eş zamanlı gelen verilerin yazılması, saklanması ve ilgili uygulamaların kullanabilmesi için verilerin sunulabilmesi.
  •  Farklı sistemlerin bir birleriyle konuşabilmesi için ortak ara yüz sunması; bir uygulama eğer birden fazla uygulamayla iletişime geçmesi gerekiyorsa her biriyle olan iletişimi için tek tek entegrasyon yazılması gerekmektedir. Bu hem iş yükü olarak hem de mimari olarak çok tercih edilmediği gibi, değişiklikler veya sorunlar esnasında ciddi darboğaza sebep olmaktadır. Bunun yerine uygulamalar mesajlarını Kafka’ya yazıp, bu mesajı tüketecek uygulamaların da direk Kafka’dan bu mesajları okuması, hem karmaşıklığı oradan kaldıracak hem asenkron bağlantı sayesinde uygulamaların genel performansı olumlu olarak artacak hem de geliştirilecek entegrasyon sayısı ciddi anlamda azalacaktır.
  • Canlı veri akışının toplanması ve analiz edilmesi; mesela bir web sitesinde kullanıcıların gezinti verilerinin toplanıp anlık önerilerin yaratılması için tüm gezinti metriklerinin kafka’da toplanıp kafka üstünde analiz edilmesi.

Kafka’nın ne olduğu ve amacını anlattığımıza göre terminolojisinden ve mimarisinden bahsetmeye başlayabiliriz. En başta biraz karışık gelse de Kafka oldukça basit bir yapıya sahiptir, özellikle daha önceden bir MQ veya benzer bir Event-streaming servisiyle çalıştıysanız ilişki kurmanız kısa zaman alacaktır.

Broker: Kafka sistemlerinin en temel bileşenidir, Kafka kümesinde çalışan her bir sunucu/servise broker denir. Broker’lar fiziksel olarak kurulu oldukları sunucuya bağlıdırlar ama bir broker kendi üstünde olmasa bile kümede ki tüm topic ve partition’lardan haberdardır. Broker’lar hem producer hem de consumer’lar için bağlantı noktası olarak görev alırlar. Broker’ların her biri eşsiz bir sayı ile temsil edilir(Örnek: 101,102,103 gibi).

Broker discovery/bootstrap server: Consumer veya Producer’lar sadece bir broker üzerindeki bootstrap servisine bağlanarak tüm kümede bulunan diğer broker’lar, topic’ler ve partition’ların durumunu ve bağlantı noktalarını öğrenebilirlerler. Bu bilgileri bootstrap server metadata olarak istemcilere sunmaktadır.

Topic: Verilerin yazıldığı, yaratıldığı anda tüm brokerlar tarafından erişilebilir olan, kafka’nın veri tabanları veya MQ’larda bulunan kuyruklara benzeyen yapısıdır. Topic’ler istendiği kadar yaratılabilir ve mantıksak bir kavramdır. Topic isimleri harf, rakam ve bazı özel karakterlerden oluşabilir.

Partition: Verilerin yazıldı, her broker’ın kendisine özel olan ve bir topic’e bağlı fiziksel disk üzerindeki alanı temsil eder. Bir topic’e ait birden fazla partition olabilir, her partition’nın 20Mb/s’lık okuma ve yazma limiti bulunmaktadır ve partition bağlı olduğu topic’e özel 0,1,2,3… gibi rakamlar şeklinde temsil edilir.

Veri Partition’a bir kere yazılır ve belli bir süre boyunca saklanır, Partition’a yazılan veri silinemez. Topic’ler yaratılırken kaç adet partition ile yaratılacağını belirleyebiliriz. Kafka broker sayısına göre partition’ları küme içerisinde dağıtır. Bu konuda ki iyi uygulamalardan biri broker sayısı veya onun katları kadar partition yaratılması yönündedir.

Replication: Yukarda da bahsettiğim üzere Partition’lar tüm küme tarafından erişilebilseler bile (Broker Discovery/bootsrap server maddesine bakınız.)üzerlerinde bulundukları fiziksel diske bağımlıdırlar eğer broker bir sebepten dolayı devre dışı kalırsa üzerinde bulunan partition’lara erişilemez. Bu da veri kaybına sebep olabilir. Bunu önlemek için Kafka, replication mekanizmasını kullanır. Bir topic yaratılırken her partition’nın kaç adet kopyası olacağını belirleyebiliriz.

Mesela 3 partition ve 2 replication factore sahip bir topic yapısı aşağıdaki gibi gözükmektedir.

Replication of Kafka

Son önemli bir noktaysa partition’ların kopyalarını yarattığımız zaman sadece bir tanesi producer’lar tarafından yazılabilir, t anında yazılabilir olan partition’a leader diğerlerine ISR(in-sync-replication) denmektedir.

Bir partition’nın birden fazla replication’ı olabilir ama sadece bir adet aktif leader’ı vardır.

Offset: Partition ve topic konularını kapatmadan önce önemli bir kavramdan daha bahsetmek gerekli, offset’ler partition özelinde olup, veriler her partition’a yazılırken bir identity number atanır, bu sayede veriler hem partition’a yazıldığı sırayla okunabilir hem de consumer’lar bir partition’da okuma yaparken hangi mesajda kaldıklarını hatırlayabilirler.

Offset sayısı 0’dan başlar ver sonsuza dek devam edebilir, her mesaj yazıldığında yeni mesaja bir sonraki numara atanır.

Offset’ler partition özelinde olduğundan dolayı bir topic’e sahip tüm partition’ların offset sayıları farkılır sadece bir partition’nın leader ve onun replica’ları aynı offset’e sahiptir.

Topic Offsets

Producer: Kafka terminolojisine göre mesaj(log) yaratan ve ilgili topic’e yazan uygulama/sistemlere verilen isimdir. Producer’lar bootstrap server sayesinde tüm broker, topic ve partition’ların listesine erişebilirler bu sayede mesajı nereye yazacağını ve nasıl yükü dağıtacağını kendisi karar verebilir.

Producer’lar her mesajı yazarken yazılım işleminden sonra onay(ACK) talep edebilirler. Kafka şu anda 3 tip ACK desteklemektedir, bunlar;

  • ACK = 0; yani mesajı yazdıktan sonra cevap beklememesi, bunun handikabı veriyi producer’ı broker’a bıraktıktan sonra bir aksilik olur ve yazamazsa producer bundan haberdar olmayacak ve veri kaybına sebep olabilir.
  • ACK = 1; Producer leader partition’a mesaj yazıldığında ACK cevabını alır. Veri kaybı riski görece olarak düşük olsa da leader’in ISR partitionlara kopyalaması bitmeden ACK verildiği için eğer tam bu esnada leader partition bulunduğu broker devre dışı kalırsa veri kaybı olabilir.
  • ACK = all; Producer hem leader hem de tüm ISR’e yazma işlemi bitmeden ACK cevabını almaz bu sebepten dolayı veri kaybı riski en düşük olan model ama Producer tarafı için cevabı beklemesi gerektiğinden performansı en düşük olan seçenektir.

Uygulamanızın kritikliği, mesaj zincirinin bozulması durumundaki etkisi gibi konuları göz önüne alınarak karar verilmesi gerekmektedir.

Message Key: Uygulamaların(Producer) Kafka’ya yazdığı mesajlar 3 parçadan oluşmaktadır; zaman damgası, mesajın içeriği ve message key. Message key her mesaj için ayrı oluşturur ve aynı key’e sahip mesajlar aynı partition’lara yazılırlar. Bunu Producer eğer belirtmezse, kafka kendisi her mesaj için yaratıp kendisi bir partition’a atayabilir veya alternatif olarak belli tip bir mesajın aynı partition’a yazılmasını istiyorsak özelliklede okuma sırasının her zaman doğru olmasını bekliyorsak message key’i elle de atayabiliriz.

Consumer: Kafka’dan verileri okuyan sistemlere verilen isimdir, aynı producer’lar gibi bootstrap serverüzerinden tüm Kafka kümesine erişebilir ve kendi load balance’ını yapma yetisine sahiptir. Consumer’lar partitionlardan verileri sırayla okur, burada dikkat edilmesi gereken nokta Kafka’ya mesajlar yazılırken birden fazla partition’a yazıldığından dolayı Consumer’lar aynı sırayla partitionlara erişmediklerinden dolayı Kafka’ya yazılma sırasından farklı olarak okunabilir. Mesajlar sadece partition’lar içerisinde sıralıdır, partition’lar bir birinden farklı sırada okunabilir.

Consumer Group: Aynı Topic’i okuyan birden fazla consumer’ın olması durumunda aynı mesajın tekrar tekrar okunmasının önüne geçmek için Consumer Group kullanılır. Consumer group içerisinde bulunan tüm consumer’lar en az bir partition’a atılır ve aynı grup içerisindeki diğer consumer aynı partitiona atanmaz. Böylelikle tekrarlı okumaların önüne geçilir.

Consumer Group içerisinde hangi consumer’ın hangi partition’la eşleştiğini, gruba yeni consumer geldiğinde veya çıktığında partition’ların tekrar dağıtılması işlemini Consumer coordinatör denilen, Kafka’nın broker’larından birini bu rol için leader seçtiği bir node üzerinde olur.

Consumer Group kullanımıyla ilgili iyi uygulamalardan biri de Consumer sayısının asla Partition sayısını geçmemesidir. Consumer group her bir partition’ı sadece bir consumer’a atayacağından dolayı fazla consumerlar boşta kalacaktır.

Consumer Group

Consumer group konusunu bitirirken __consumer_offset isimli topic’den bahsetmem gerekir. Bu topic kafka tarafından yaratılan ve yönetilen bir topictir ve consumer’lar bir partition’dan her okuma yaptıklarında hangi offset’te kaldıklarını burada tutuluyor. Consumer group’a yeni bir üye katıldığında veya bir consumer kesinti yaşayıp tekrar kafka’ya bağlandığında buradan nerede kaldığını hatırlayarak devam ediyor. Kafka kümesini ilk kurduğunuzda __consumer_offset’in mutlaka minimum 3 node’a replice edilmesini ayarlamanız gerekmektedir, aksi durumda __consumer_offset’in leader partition’larını tutan broker’ı kaybetmeniz durumunda servisiniz duracaktır.

Consumer delivery semantics: Consumer’ın ne zaman offset’i commit ettiğini belirler.

  • At most once: Offset consumer tarafından okunur okunmaz commit edilir, eğer consumer tarafında mesaj okunduktan sonra işlemlerde sorun oluşursa veri kaybı oluşabilir
  • At least once: Offset’in commit edilmesi consumer okuduğu mesajı işledikten sonra yapılır, veri kaybı riski az olmasına rağmen mesaj birden fazla kere okunabilir.
  • Exactly once: Daha çok Kafka’dan kafka’ya mirrormaker gibi süreçlerde kullanılır.

Kafka terminolojisinden bahsederken fark etmiş olduğunuz üzere kafka ciddi bir metadata yönetimi yapmakta, tüm bileşenlerinin bilgilerini ve yetkileri bir yerde saklamalı aynı zamanda küme içerisinde ki leader/follower yapısını bir şekilde takip edip devre dışı kalan veya yeni eklenen broker’lara göre kümeyi dinamik olarak ayarlayabilmelidir. Kafka mevcut versiyonu itibariyle bu rolleri Zookeeper ile yapmakta ama yakın gelecekte planlanan versiyonlarında Zookeeper yerine kendi iç metadata veri tabanını kullanması planlanmaktadır.

Zookeeper; özellikle büyük veri projeleri başta olmak üzere birçok açık kaynak projesinde kullanılan, dağıtık, key-value veri saklama yeteneğine sahip açık kaynaklı bir servistir. Zookeeper kafka için aşağıdaki rolleri üstlenir;

  • Kafka kümesinin takibi; Zookeeper kümede bulunan tüm broker’ları heartbeat servisleriyle izler ve bir tanesine erişilememe durumunda broker listesinden çıkartır. Böylelikle bootstrap servisi üzerinden producer ve consumer’lar bu broker’ı göremezler. Aynı şekilde yeni bir broker’ın eklmesi durumunda tüm kümeye bildirimini yapar.
  • Controller seçimi: Kafka broker’larından biri kümedeki tüm partitionların leader/follower ilişkini controller yönetir. Bir broker devre dışı kaldığında onun üzerindeki leader partitionlara sahip hangi replicaların leader olacağını seçer. Bu role sahip broker’ın cevap verememe durumunda Zookeeper yeni bir controller seçer
  • Topic konfigürasyonlarının ve ACLs’lerin tutulması: Kümede hangi topic’ler, kaç adet partitiona sahip, partition durumları, replicationların durumu ve yerlerinin bulunduğu metadataları tutar ve yönetir. Aynı zamanda kullanıcıların broker’lar ve topic’ler üzerindeki yetkileride burada tutulmaktadır.
  • Kotalar: Topic’ler ve partitionlar ile kullanıcıların yazma/okuma kota bilgilerini burada tutar.

Zookeeper Kafka’dan ayrı bir servistir ve ayrı olarak konumlandırılması ve planlanması gerekmektedir. Zookeeper leader follower mekanizmasıyla çalışmaktadır, yani zookeeper kümesindeki bir sistem tüm işlemleri, değişiklikleri ve koordinasyonu üstleniyor diğer nodelarsa onu takip ediyorlar. Kümede lider seçimi çoğunluk oyuna göre yapılmaktadır, bu sebepten dolayı Zookeeper kümesinin node sayısının 1,3,5,7… gibi tek sayılardan oluşması gerekmektedir.

Yukarda konuştuklarımızı özetlerse Kafka yapısı aşağı yukarı aşağıdaki gibidir.

Genel yapı

Bu blog yazısı Emre Bozlak tarafından paylaşılmıştır. Referans vererek istediğiniz gibi kullanabilirsiniz. Eğer bir sorunuz olursa eposta veya sosyal medya hesaplarım üzerinden bana ulaşabilirsiniz. Yazılarımı Twitter'dan @emrebozlak veya RSS üzerinden takip edebilirsiniz.

One Trackback

  1. […] bahsedeceğim eğer Kafka nedir ve Kafka’nın terminolojisini öğrenmek istiyorsanız bir önceki yazımı […]

Leave a comment