Napjainkban az esemény alapú (event-driven) architektúra kialakítása nagyon divatosan cseng elosztott rendszerek tervezése során. Az Apache által fejlesztett Kafka ehhez ad egy nyílt forráskódú szoftvert, eseményfolyam (streaming) alapú szolgáltatásával üzenetek továbbítására/publikálására. Technikailag a Kafka egy olyan eszközt biztosít, ami az adatok folyamatos áramlását teszi lehetővé. Széles körben használják, rengeteg nagyvállalat tette már mellette le a voksát. Egy-két kiemelkedő tulajdonság a teljesség igénye nélkül:
Rövid bemutató: https://kafka.apache.org/intro
Kafka úgynevezett topic-okat használ az üzenetek áramlásához. Minden topic-nak van egy vagy több író/publikáló oldala (őket hívjuk producer-eknek) és van egy vagy több olvasó/feldolgozó oldala (őket hívjuk consumer-eknek). A publikáló fél egyszerűen felrakja az üzenetét a topic-ra, majd az olvasó ezt leolvassa és visszaigazolja (commitol) a topicon, hogy ő ezt az üzenetet már feldolgozta az eseményfolyamról.
Minden topic egy logikai egységet alkot, amit a Kafka több partícióra (legkisebb tároló egység) oszt fel a brókerek (clusterben elérhető szerver) között. Ennek több előnye is van:
A consumerek csoportszinten dolgozzák fel az üzeneteket. Minden consumer csoport egy egyedi azonosítóval iratkozik fel a topic-ra, ezt nevezzük consumer group id-nak (ezzel publikálja magáról, hogy melyik feldolgozói csoporthoz tartozik). Egy csoport több consumeret is indíthat egyidejűleg (egyszerűen felskálázható pl. megnövekedett üzenetek esetén, de fordítva is igaz, könnyedén leskálázható, ha visszaáll a normál működés), amelyek ugyanazt a célt szolgálják, leolvassák az üzenetet és feldolgozzák. Ha több példány is indult a csoport azonosítójával akkor a feldolgozás szempontjából nem releváns, hogy melyik feldolgozó kapta fel az üzenetet. Abban az esetben ha több consumer csoport is feliratkozott a topicra, akkor már fontos lesz az azonosító szerepe, mert addig amíg az összes consumer csoport nem igazolja vissza, hogy feldolgozta az adott üzenetet, meg kell azt tartani (retention time: meghatározza az üzenetek megtartási idejét, ezt az értéket meg lehet adni globálisan a Kafka szerver konfigurációval, de akár topiconként is lehet definiálni). Figyelni kell rá, hogy a consumer group-ok ne használják egymás azonosítóit, mert előállhat egy olyan állapot, hogy elkapkodják egymás elöl az üzeneteket.
A lenti példa két író és egy olvasó csoportot (2 példányban indítva) reprezentál.
Azokat a rutin feladatokat, amelyeket rendszeresen el kell tudni végezni, érdemes automatizálni. Ez több szempontból is előnyös:
Egy nagyvállalati környezetben általában az átfutás több körös jóváhagyást jelent, majd ezt követően tud elkezdődni a végrehajtás. Ha ezért a két folyamatért nem ugyanaz a csapat a felelős akkor ez időben még tovább tarthat. Egy automatizált folyamatban ezek a lépések sokkal gyorsabban végrehajthatóak, hiszen a végrehajtás jobb esetben már csak egy gomb megnyomását jelenti.
Kafka topic létrehozása vagy a topicon való jogosultsági beállítások elvégzése rutin feladatoknak számítanak. Nincs különbség „A” vagy „B” topicon való végrehajtás során, jól leírható, egymás utáni deklaratív parancsok kiadásával elvégezhető, egyszóval „scriptelhető”. Mit jelent a gyakorlatban? Egy vagy több végrehajtó job-ot, ami könnyedén beilleszthető egy projekt CI/CD pipeline-ba.
Kézenfekvő megoldás lenne egy Ansible playbook írása, ami pont deklaratív feladatok elvégzését segíti elő. Fontos, hogy ne készítsünk el olyat, ami már létezik és van hozzá támogatás. Ansible scriptekkel nem lehet operatív devops-os feladatokat végrehajtani Kafka környezetben. Ellenben egy Kafka cluster felépítésére nagyon jó támogatást ad.
Az Apache kiadott egy eszközkészletet (sh scriptek formájában), amivel elvégezhetőek az operatív devopsos folyamatok. Ezeknek a parancsoknak a felhasználásával készült el a minta projektben szereplő job, ami képes topicot létrehozni és azon jogosultságot beállítani.
A készlet itt elérhető: https://kafka.apache.org/quickstart
Automatizált folyamat kialakításánál konvenciókat kell meghatározni, amelyekre egyértelműen lehet építeni a folyamatokban, ilyen pl. a topic nevének meghatározása vagy az adminisztrációs fájlok elnevezése.
A Bitbucket mint verziókezelő alkalmas az adminisztráció elvégzésére. A minta projektben minden Kafka topic saját repository-val rendelkezik. Egy új topic megjelenése esetén létre kell hozni egy új repository-t, aminek az első lépése, hogy milyen névvel hozzuk létre. Ehhez az alábbi konvenciót határozzuk meg: topic-name (kötöjelekkel elválasztva ha több szótagból áll).
Minden repository a futtatandó környezeteknek megfelelő számú leírót fogja tartalmazni. Erre azért van szükség, mert általánosságban kijelenthető, hogy eltérő konfigurációval jönnek létre és különböző felhasználók fogják írni/olvasni a topic-okat a különböző környezetekben. A példában DEV, UAT és PROD környezetnek megfelelő számú leírót hozunk létre. A környezet azonosítója alapján (topic_neve + “_környezet„) postfixel az alábbi fájlok lettek létrehozva a „notifications” topic-hoz:
Környezet | Példa fájl neve |
DEV | notifications_dev.yaml |
UAT | notifications_uat.yaml |
PROD | notifications_prod.yaml |
Minden topic egy egységes formátumban közli magáról az elérni kívánt állapotot. A fájlok az adott a környezetre utaló mindenkori aktuális állapotát írják le. Változáskezeléssel könnyedén visszakövethető, hogy a topic milyen beállításokat/jogosultságokat tartalmazott egy adott verzióban. A séma definiálja, hogy milyen adatok megléte szükséges ahhoz, hogy a megfelelő Kafka scripteket érvényre lehessen juttatni. A name, replication, partition rész tartalmazza a topic létrehozásához szükséges információkat, az acl (access control lists
) rész hordozza a jogosultsági beállításokat.
name: notifications_dev
replication: ‘2’
partition: ‘4’
acl:
– principal: _proj_microservice_dev
consumerGroup: dsp_microservice_read_dev
role: consumer
– principal: _proj_microservice-2_dev
role: producer
– principal: _proj_microservice-3_dev
consumerGroup: dsp_microservice-3_read_dev
role: consumer
– principal: _proj_microservice-4_dev
role: producer
Itt lehet további megszorításokat meghatározni a principal-ok elnevezésében, illetve consumer-ek esetén a consumerGroup azonosítókban (a fenti példa a _proj prefixet használja). Ez azért fontos mert a script vagy már a review folyamat is el tudja buktatni a nem konvenció szerint létrehozott azonosítókat.
Abban a szerencsés helyzetben, ha csak a környezet azonosítójában térnek el az azonosítók akkor paramétereket is lehet alkalmazni. Ebben az esetben nincs szükség 3 fájlra, egyszerűen leírható így is:
name: notifications_${ENV_NAME}
replication: ‘2’
partition: ‘4’
acl:
– principal: _proj_microservice_${ENV_NAME}
consumerGroup: dsp_microservice_read_${ENV_NAME}
role: consumer
– principal: _proj_microservice-2_${ENV_NAME}
role: producer
– principal: _proj_microservice-3_${ENV_NAME}
consumerGroup: dsp_microservice-3_read_${ENV_NAME}
role: consumer
– principal: _proj_microservice-4_${ENV_NAME}
role: producer
(A paramétert a végrehajtó job induláskor megkapja.)
Az alkalmazott branching stratégia az összes repository-ra érvényes.
branch | leírás | komment |
master | A mindenkori aktuális állapotot írja le. | Védett branch, csak Pull request-en keresztül lehet kódot eljuttatni. Erről a branch-ről lehet release-t kiadni, illetve a merge során automatikusan kap egy release tag-et. |
feature/task-id | A feature branchek tartalmazzák a folyamatban lévő fejlesztésekhez tartozó változtatásokat. Életciklusa szerint addig él, amíg a fejlesztő csapat elvégzi a szükséges változtatásokat és feladja egy új igényként(Pull request) a master branch-re. | Erről a branch-ről lehet kipróbálni (akár egy dry-run job-val) az elkészült változtatásokat. Fejlesztési időben kiderül, ha hiba van (pl. nem megfelelő a topic neve vagy hiányzik consumer esetén a consumerGroup azonosító). |
(Release branch-re nincs szükség, a master állapotából lehet release-t kiadni, illetve bugfix-elni tag alapján is lehet.)
Ahhoz, hogy egy változtatás eljusson a „production” állapotig, megfelelő minőségbiztosításra van szükség. Ezt jóváhagyói csoport(ok) és szabályok kialakításával lehet biztosítani Bitbucketes környezetben, amit az adminok tudnak beállítani.
A megfelelő tagok bevonásával az alábbi csoportokat hoztuk létre:
Bitbucket jóváhagyói csoport | kafka-merge | Jóváhagyói jogosultság. Ebbe a körbe csak olyan tagok vannak, akik felelősök a Kafka üzemeltetésért a projekten. |
Bitbucket szerkesztői csoport | kafka-editor | Fejlesztői csoport, írási jogosultság (kivéve master branch). |
Bitbucket olvasási csoport | kafka-read | Olvasói jogosultság (nem tud kódot push-olni a branch-en). |
(Elképzelhető olyan felállás, hogy több csoportnak is rendelkeznie kell egy új igénylés elfogadása felett és legalább egy-egy jóváhagyás szükséges csoportonként.)
A telepítéshez a Kafka leíró fájlokat ki lehet releaselni egy artifaktként pl. Nexusba vagy használható a master branch megfelelő tag alapján. A folyamat lépései időrendi sorrendben:
Pull request | Röviden “PR” feladásával történik meg a környezet változtatási (topic létrehozása is) igény létrehozása. A PR biztosítja a kontrollt, hogy csak is olyan módosítás kerüljön be a master branch-re, ami jóváhagyási folyamaton átesett. |
Merge | A PR-t a default reviewerek (kafka-merge csoport tagok) jóváhagyták. |
Release | Release artifakt elkészítése a master branchről (opcionális ha elfogadható a tag). |
Telepítés | Job lefuttatja a scriptet a megfelelő környezeten (DEV, UAT, PROD). |
A fejlesztő csapat PR keretein belül feladja a módosítási (ebbe értendő a topic létrehozás is) kérelmet a master branchre, amiről a default reviewerek (kafka-merge csoport tagok) automatikusan értesítést kapnak.
A Bitbucketben nyilvántartott fájlok aktuális Kafka állapotokat írnak le jogosultságokkal, környezeti paraméterekkel, stb. A fájlok mint bement használható egy automatizált folyamatban, ami a megfelelő Kafka command line toolok felhasználásával létrehozza (topicot is) és/vagy beállítja a megfelelő jogosultságokat az adott környezeten.
Előfeltételek:
Az alábbi folyamatábra reprezentálja a végrehajtási (szinkron) lépéseket:
A folyamat első lépéseként le kell tudni kérdezni, hogy az adott Kafka topic létezik-e vagy sem a megfelelő környezetben. Ehhez az alábbi command line tool használható, aminek egyetlen paraméter a zookeper host (olyan változó, ami ritkán vagy egyáltalán nem változik meg, ezért statikus változóként a kódban lett definiálva):
kafka-topics.sh –zookeeper zk01.example.com:2181 –list |
Kafka topic létrehozásához az alábbi command line tool futtatása szükséges. A paraméterek a környezethez definiált yaml fájlban, a metadata alatti kulcsokkal összeegyeztethetőek.
kafka-topics.sh –create –zookeeper {$zookeeper}
–topic {$topic} –partitions {$num_of_partitions} –replication-factor {$num_of_replication_factor} |
paraméter | leírás | forrás |
zookeeper | Zookeper host címe. | Előre definiált statikus változóból. |
topic | Létrehozandó topic neve. | Yaml-ben definit name property. |
num_of_partitions | Partíciószám, hány darab fizikai partícióra legyen felosztva a topic. Fontos, hogy később csak felfelé módosítható adatvesztés nélkül.
Tervezési fázisban kalkulációt igényelhet a megfelelő throughput elérése: https://dattell.com/data-architecture-blog/kafka-optimization-how-many-partitions-are-needed/ |
Yaml-ben definit partitation property. |
num_of_replication_factor | Replikációk számát határozza meg, hány darab Kafka brókeren legyen replikálva az adat. | Yaml-ben definit replication property. |
Adott topicról lekérdezhetőek a jelenlegi jogosultság beállítások az alábbi command line tool futtatásával:
kafka-acls.sh –authorizer-properties zookeeper.connect={$zookeeper} –list |
Az eredmény feldolgozását követően a Jenkins job képes eldönteni, hogy szükséges-e további beállítás a topicon.
Kafka topicon jogosultság beállításhoz az alábbi command line toolok biztosítanak lehetőséget. 2 típusú jogosultságot lehet beállítani:
jogosultság | típus | cli |
consumer | Olvasási jogosultság. | kafka-acls.sh –authorizer-properties zookeeper.connect={$zookeeper} –add –consumer –allow-principal User:{$user} –topic {$topic} –group {$group_id} |
producer | Írási jogosultság. | kafka-acls.sh –authorizer-properties zookeeper.connect={$zookeeper} –add –producer –allow-principal User:{$user} –topic {$topic} |
paraméter | leírás | forrás |
zookeeper | Zookeper host url. | Előre definiált statikus változóból. |
user | A consumer/producer neve. | Yaml-ben definit principal property. |
group_id | Consumer esetén kötelező consumer group id-t megadni a feldolgozói csoport azonosításához. | Yaml-ben definit consumerGroup property. |
Mikroszerviz architektúrában központi szerepet kaphat egy Kafka cluster az infrastruktúrában. Ennek hatásaként rendszeres feladatot jelent az új vagy meglévő Kafka topic-ok adminisztrációja. A release-ek élesítése során sok környezeti igénylési probléma elkerülhető, ha egy hasonló megoldás részét képezi a CI/CD pipeline-nak, ezzel is biztosítva az alkalmazásunk stabil működését.
Minden problémára professzionális megoldást kínálunk. Keress minket bizalommal!
Nézd meg nyitott pozícióinkat, és ha felkeltettük érdeklődésed, keress minket bizalommal!