
Vo svojej práci sa často stretávam s novými technickými riešeniami\/softvérovými produktmi, o ktorých je v slovenskom internete veľmi málo informácií. Touto článkom sa pokúsim zaplniť jednu takúto medzeru príkladom z mojej nedávnej praxe, keď bolo potrebné nastaviť odosielanie CDC udalostí z dvoch populárnych SDB (PostgreSQL a MongoDB) do klastera Kafka pomocou Debezium. Dúfam, že tento prehľadový článok, vzniknutý na základe vykonanej práce, bude užitočný aj ostatným.
Čo je Debezium a vôbec CDC?
— zástupca kategórie softvérového CDC (), a presnejšie povedané, je to súbor konektorov pre rôzne SDB, kompatibilných s frameworkom Apache Kafka Connect.
Toto ktorý využíva licenciu Apache License v2.0 a je sponzorovaný spoločnosťou Red Hat. Vývoj prebieha od roku 2016 a v súčasnosti podporuje nasledujúce SDB: MySQL, PostgreSQL, MongoDB, SQL Server. Existujú aj konektory pre Cassandra a Oracle, ale momentálne sú v štádiu "skorého prístupu", pričom nové vydania nezaručujú spätnú kompatibilitu.
Ak porovnáme CDC s tradičným prístupom (keď aplikácia číta údaje priamo zo SDB), jeho hlavné výhody zahŕňajú realizáciu streamovania zmien údajov na úrovni riadkov s nízkou latenciou, vysokou spoľahlivosťou a dostupnosťou. Posledné dva body sa dosahujú vďaka použitiu klastera Kafka ako úložiska CDC udalostí.
Medzi výhody patrí aj fakt, že na uchovávanie udalostí sa používa jednotný model, a preto sa konečná aplikácia nemusí obávať nuáns prevádzky rôznych SDB.
Nakoniec, vďaka použitiu správy správ sa otvára priestor na horizontálne škálovanie aplikácií, ktoré sledovať zmeny v údajoch. Pri tom sa vplyv na zdroj údajov minimalizuje, keďže získavanie údajov prebieha nie priamo zo SDB, ale z klastera Kafka.
O architektúre Debezium
Používanie Debezium sa zjednodušuje na takúto jednoduchú schému:
SDB (ako zdroj údajov) → konektor v Kafka Connect → Apache Kafka → konzument
Ako ilustráciu uvádzam schému zo stránky projektu:

Avšak táto schéma sa mi veľmi nepáči, pretože vytvára dojem, že je možné len použitie sink konektora.
V skutočnosti však situácia vyzerá inak: naplnenie vášho Data Lake (posledná časť na schéme vyššie) — to nie je jediný spôsob využitia Debezia. Udalosti odoslané do Apache Kafka môžu byť využívané vašimi aplikáciami na riešenie rôznych situácií. Napríklad:
- odstránenie neaktuálnych dát z cache;
- odosielanie upozornení;
- aktualizácie vyhľadávacích indexov;
- akýsi typ auditných logov;
- …
V prípade, že máte aplikáciu na Jave a nie je potrebné/možné používať klaster Kafka, existuje aj možnosť práce cez . Zrejmou výhodou je, že sa môžete vzdať dodatočnej infraštruktúry (vo forme konektora a Kafky). Avšak toto riešenie je považované za zastarané (deprecated) od verzie 1.1 a už sa neodporúča používať (v budúcich vydaniach môže byť jeho podpora odstránená).
V tomto článku sa bude diskutovať o odporúčanej architektúre od vývojárov, ktorá zabezpečuje odolnosť voči chybám a možnosť škálovania.
Konfigurácia konektora
Aby sme mohli sledovať zmeny najdôležitejšej hodnoty — dát — budeme potrebovať:
- zdroj dát, ktorým môže byť MySQL od verzie 5.7, PostgreSQL 9.6+, MongoDB 3.2+ ();
- klaster Apache Kafka;
- inštancia Kafka Connect (verzie 1.x, 2.x);
- konfigurovaný konektor Debezium.
Práca na prvých dvoch bodoch, t.j. proces inštalácie DBMS a Apache Kafka, presahuje rámec článku. Avšak pre tých, ktorí chcú všetko rozbehnúť v pieskovisku, v oficiálnom repozitári s príkladmi je pripravený .
Zastavíme sa podrobnejšie na dvoch posledných bodoch.
0. Kafka Connect
Tu a ďalej v článku sú všetky príklady konfigurácie zvažované v kontexte Docker obrazu, ktorý poskytujú vývojári Debezium. Obsahuje všetky potrebné súbory pluginov (konektorov) a predpokladá konfiguráciu Kafka Connect pomocou premenných prostredia.
V prípade, že sa predpokladá použitie Kafka Connect od Confluent, bude potrebné samostatne pridať pluginy potrebných konektorov do adresára, ktorý je určený v plugin.path alebo stanovený prostredníctvom premennej prostredia CLASSPATH. Nastavenia pracovníka Kafka Connect a konektorov sú definované prostredníctvom konfiguračných súborov, ktoré sú predávané ako argumenty príkazu na spustenie pracovníka. Viac informácií nájdete v .
Celý proces nastavenia Debezium s konektorom sa vykonáva v dvoch krokoch. Pozrime sa na každý z nich:
1. Nastavenie rámca Kafka Connect
Pre streamovanie údajov do klastru Apache Kafka v rámci Kafka Connect sa nastavujú špecifické parametre, ako sú:
- parametre pripojenia ku klastru,
- názvy tém, v ktorých bude uchovávaná samotná konfigurácia konektora,
- meno skupiny, v ktorej je konektor spustený (v prípade použitia distribuovaného režimu).
Oficiálny Docker obraz projektu podporuje konfiguráciu pomocou premenných prostredia – a to využijeme. Takže, sťahujeme obraz:
docker pull debezium/connectMinimálny súbor premenných prostredia, potrebný na spustenie konektora, vyzerá nasledovne:
-
BOOTSTRAP_SERVERS=kafka-1:9092,kafka-2:9092,kafka-3:9092– počiatočný zoznam serverov klastru Kafka na získanie kompletného zoznamu členov klastru; -
OFFSET_STORAGE_TOPIC=connector-offsets– téma pre uchovávanie pozícií, na ktorých sa v súčasnosti konektor nachádza; -
CONNECT_STATUS_STORAGE_TOPIC=connector-status– téma pre uchovávanie stavu konektora a jeho úloh; -
CONFIG_STORAGE_TOPIC=connector-config– téma pre uchovávanie údajov konfigurácie konektora a jeho úloh; -
GROUP_ID=1– identifikátor skupiny pracovníkov, na ktorých môže byť úloha konektora vykonávaná; nutnou podmienkou pri použití distribuovaného (distributed) režimu.
Spúšťame kontajner s týmito premennými:
docker run
-e BOOTSTRAP_SERVERS='kafka-1:9092,kafka-2:9092,kafka-3:9092'
-e GROUP_ID=1
-e CONFIG_STORAGE_TOPIC=my_connect_configs
-e OFFSET_STORAGE_TOPIC=my_connect_offsets
-e STATUS_STORAGE_TOPIC=my_connect_statuses debezium/connect:1.2Poznámka o Avro
Predvolene Debezium zapisuje údaje vo formáte JSON, čo je prijateľné pre pieskoviská a malé objemy údajov, ale môže sa to stať problémom vo vysoko zaťažených databázach. Alternatívou k JSON prevodníku je serializácia správ pomocou do binárneho formátu, čo umožňuje znížiť záťaž na subsystém I/O v Apache Kafka.
Na použitie Avro je potrebné rozvinúť samostatný (pre uchovávanie schém). Premenné pre prevodník budú vyzerať nasledovne:
name: CONNECT_VALUE_CONVERTER_SCHEMA_REGISTRY_URL
value: http://kafka-registry-01:8081/
name: CONNECT_KEY_CONVERTER_SCHEMA_REGISTRY_URL
value: http://kafka-registry-01:8081/
name: VALUE_CONVERTER
value: io.confluent.connect.avro.AvroConverterPodrobnosti o použití Avro a nastavení registry presahujú rámec článku – na ďalšie ilustrácie budeme používať JSON.
2. Nastavenie samotného konektora
Teraz môžeme prejsť priamo na konfiguráciu samotného konektora, ktorý bude čítať údaje zo zdroja.
Pozrime sa na príklad konektorov pre dve DBMS: PostgreSQL a MongoDB, — pri ktorých mám skúsenosti a existujú medzi nimi rozdiely (nech sú aj malé, ale v niektorých prípadoch — podstatné!).
Konfigurácia je popísaná v notácii JSON a načítava sa do Kafka Connect pomocou POST požiadavky.
2.1. PostgreSQL
Príklad konfigurácie konektora pre PostgreSQL:
{
"name": "pg-connector",
"config": {
"connector.class": "io.debezium.connector.postgresql.PostgresConnector",
"plugin.name": "pgoutput",
"database.hostname": "127.0.0.1",
"database.port": "5432",
"database.user": "debezium",
"database.password": "definitelynotpassword",
"database.dbname" : "dbname",
"database.server.name": "pg-dev",
"table.include.list": "public.(.*)",
"heartbeat.interval.ms": "5000",
"slot.name": "dbname_debezium",
"publication.name": "dbname_publication",
"transforms": "AddPrefix",
"transforms.AddPrefix.type": "org.apache.kafka.connect.transforms.RegexRouter",
"transforms.AddPrefix.regex": "pg-dev.public.(.*)",
"transforms.AddPrefix.replacement": "data.cdc.dbname"
}
}Princíp fungovania konektora po takejto konfigurácii je dosť jednoduchý:
- Pri prvom spustení sa pripojí k databáze uvedenej v konfigurácii a spustí sa v režime initial snapshot, odosielajúc do Kafka počiatočný súbor údajov získaných pomocou podmienečného
SELECT * FROM table_name. - Akonáhle je inicializácia dokončená, konektor prechádza do režimu čítania zmien z WAL súborov PostgreSQL.
O použitých možnostiach:
-
name— názov konektora, pre ktorý sa používa konfigurácia opísaná nižšie; nielenže sa toto meno používa na prácu s konektorom (t.j. kontrolu stavu/reštartovanie/aktualizáciu konfigurácie) prostredníctvom REST API Kafka Connect; -
connector.class— trieda konektora DBMS, ktorá sa bude používať konfigurovaným konektorom; -
plugin.name— názov pluginu na logické dekódovanie údajov z WAL súborov. Na výber sú dostupnéwal2json,decoderbuffsapgoutput. Prvé dve vyžadujú inštaláciu zodpovedajúcich rozšírení v DBMS, zatiaľ čopgoutputpre PostgreSQL verzie 10 a vyššie nevyžaduje ďalšie manipulácie; -
database.*— možnosti pripojenia k DB, kdedatabase.server.name— názov inštancie PostgreSQL, použitý na formovanie názvu témy v klastri Kafka; -
table.include.list— zoznam tabuliek, v ktorých chceme sledovať zmeny; zadané vo formáteschema.table_name; nemožno používať spolu stable.exclude.list; -
heartbeat.interval.ms— interval (v milisekundách), s ktorým konektor posiela heartbeat správy do špeciálnej témy; -
heartbeat.action.query— dopyt, ktorý sa vykoná pri odosielaní každej heartbeat správy (možnosť bola pridaná od verzie 1.1); -
slot.name— názov replikovacieho slotu, ktorý bude používať konektor; publication.name— názov v PostgreSQL, ktorý používa konektor. V prípade, že neexistuje, pokúsi sa jej vytvoriť. Ak nemá používateľ, pod ktorým sa pripája, dostatočné práva na tento úkon, konektor skončí s chybou;-
transformácieurčuje, ako presne sa má zmeniť názov cieľovej témy:-
transforms.AddPrefix.typeuvádza, že budeme používať regulárne výrazy; -
transforms.AddPrefix.regex— maska, podľa ktorej sa prepisuje názov cieľovej témy; -
transforms.AddPrefix.replacement— priamo to, na čo sa prepisujeme.
-
Viac informácií o heartbeat a transforms
Predvolene konektor odosiela údaje do Kafka pri každej potvrdenej transakcii a jej LSN (Log Sequence Number) zapíše do systémovej témy offset. Ale čo sa stane, ak je konektor nastavený na čítanie nie celej databázy, ale iba časti jej tabuliek (v ktorých sa aktualizácia údajov nedeje často)?
- Konektor bude čítať WAL súbory a nebude v nich zisťovať potvrdenia transakcií v tých tabuľkách, ktoré sleduje.
- Preto nebude aktualizovať svoju aktuálnu pozíciu ani v téme, ani v replikatornom slote.
- To zas povedie k "uchovávaniu" WAL súborov na disku a pravdepodobnému vyčerpaniu celého diskového priestoru.
A tu prichádzajú na pomoc možnosti heartbeat.interval.ms a heartbeat.action.query. Použitie týchto možností v páre umožňuje zakaždým pri odosielaní heartbeat správy vykonávať dopyt na zmenu údajov v samostatnej tabuľke. Odtiaľ sa neustále aktualizuje LSN, na ktorom sa teraz nachádza konektor (v replikatornom slote). To umožňuje DBMS odstrániť WAL súbory, ktoré už nie sú potrebné. Ďalšie informácie o fungovaní možností nájdete v .
Ďalšia možnosť, zasluhujúca si väčšiu pozornosť, je transformácie. Aj keď ide skôr o pohodlie a estetiku...
Predvolene Debezium vytvára témy v súlade s nasledujúcou politikou pomenovávania: serverName.schemaName.tableName. To nemusí byť vždy pohodlné. Možnosti transformácie pomocou regulárnych výrazov môžete určiť zoznam tabuliek, ktorých udalosti sa majú smerovať do témy s konkrétnym názvom.
V našej konfigurácii vďaka Na záver popisu konfigurácie konektora pre PostgreSQL je potrebné spomenúť nasledujúce vlastnosti/obmedzenia jeho fungovania: Tak sme načítali našu konfiguráciu do konektora: Kontrolujeme, či načítanie prebehlo úspešne a konektor sa spustil: Výborne: je nastavený a pripravený na použitie. Teraz sa predstavíme ako konzument a pripojíme sa k Kafka, po čom pridáme a zmeníme záznam v tabuľke: V našej téme to bude vyzerať nasledovne: Veľmi dlhý JSON s našimi zmenami V oboch prípadoch záznamy pozostávajú z kľúča (PK) záznamu, ktorý bol zmenený, a samotnej podstaty zmien: aký bol záznam predtým a aký sa stal po. Tento konektor používa štandardný mechanizmus replikácie MongoDB, čítajúci informácie z oplog-u primárneho uzla DBMS. Podobne ako už popísaný konektor pre PgSQL, aj tu pri prvom spustení skenuje primárny snímok údajov, po čom sa konektor prepne do režimu čítania oplog-u. Príklad konfigurácie: Ako si môžete všimnúť, tu nie sú nové možnosti v porovnaní s minulým príkladom, ale znížil sa len počet možností, ktoré zodpovedajú za pripojenie k DB a ich prefixy. Nastavenia Otázka odolnosti a vysokej dostupnosti je v súčasnosti dôležitejšia ako kedykoľvek predtým – najmä keď hovoríme o údajoch a transakciách, a sledovanie zmien údajov v tomto poradi nie je výnimkou. Poďme sa pozrieť, čo všetko sa môže pokaziť a čo sa bude diať s Debezium v každom prípade. Existujú tri varianty zlyhania: Existujú však výnimky. Ak konektor bol dlhodobo v odpojenom stave (alebo nemohol dosiahnuť inštanciu MongoDB), a oplog za tento čas prešiel rotáciou, potom pri obnovení pripojenia konektor bez vzrušenia začne čítať dáta z prvej dostupnej pozície, čo môže spôsobiť, že niektoré dáta v Kafka nie sa dostanú. Debezium — moja prvá skúsenosť s CDC systémami a celkovo veľmi pozitívna. Projekt zaujal podporou hlavných DBMS, jednoduchosťou konfigurácie, podporou klastrovania a aktívnou komunitou. Odporúčam tým, ktorí majú záujem o prax, aby si prečítali príručky pre a . V porovnaní s JDBC konektorom pre Kafka Connect je hlavnou výhodou Debezium to, že zmeny sa čítajú z denníkov DBMS, čo umožňuje získať dáta s minimálnym oneskorením. JDBC Connector (z dodávky Kafka Connect) robí dopyty na sledovanej tabuľke s pevnými intervalmi a (z rovnakého dôvodu) nevytvára správy pri odstraňovaní dát (ako by ste mohli dopytovať dáta, ktoré neexistujú?). Na riešenie podobných úloh sa môžete zamerať na nasledujúce riešenia (okrem Debezium): Prečítajte si tiež na našom blogu: Zdroj: habr.comtransformácie sa deje nasledujúce: všetky CDC-udalosti z monitorovanej databázy sa dostanú do témy s názvom data.cdc.dbname. V opačnom prípade (bez týchto nastavení) by Debezium predvolene vytváral tému pre každú tabuľku vo forme: pg-dev.public..
Obmedzenia konektora
Aplikácia konfigurácie
curl -i -X POST -H "Accept:application/json"
-H "Content-Type:application/json" http://localhost:8083/connectors/
-d @pg-con.json$ curl -i http://localhost:8083/connectors/pg-connector/status
HTTP/1.1 200 OK
Date: Thu, 17 Sep 2020 20:19:40 GMT
Content-Type: application/json
Content-Length: 175
Server: Jetty(9.4.20.v20190813)
{"name":"pg-connector","connector":{"state":"RUNNING","worker_id":"172.24.0.5:8083"},"tasks":[{"id":0,"state":"RUNNING","worker_id":"172.24.0.5:8083"}],"type":"source"}$ kafka/bin/kafka-console-consumer.sh
--bootstrap-server kafka:9092
--from-beginning
--property print.key=true
--topic data.cdc.dbname
postgres=# insert into customers (id, first_name, last_name, email) values (1005, 'foo', 'bar', 'foo@bar.com');
INSERT 0 1
postgres=# update customers set first_name = 'egg' where id = 1005;
UPDATE 1{
"schema":{
"type":"struct",
"fields":[
{
"type":"int32",
"optional":false,
"field":"id"
}
],
"optional":false,
"name":"data.cdc.dbname.Key"
},
"payload":{
"id":1005
}
}{
"schema":{
"type":"struct",
"fields":[
{
"type":"struct",
"fields":[
{
"type":"int32",
"optional":false,
"field":"id"
},
{
"type":"string",
"optional":false,
"field":"first_name"
},
{
"type":"string",
"optional":false,
"field":"last_name"
},
{
"type":"string",
"optional":false,
"field":"email"
}
],
"optional":true,
"name":"data.cdc.dbname.Value",
"field":"before"
},
{
"type":"struct",
"fields":[
{
"type":"int32",
"optional":false,
"field":"id"
},
{
"type":"string",
"optional":false,
"field":"first_name"
},
{
"type":"string",
"optional":false,
"field":"last_name"
},
{
"type":"string",
"optional":false,
"field":"email"
}
],
"optional":true,
"name":"data.cdc.dbname.Value",
"field":"after"
},
{
"type":"struct",
"fields":[
{
"type":"string",
"optional":false,
"field":"version"
},
{
"type":"string",
"optional":false,
"field":"connector"
},
{
"type":"string",
"optional":false,
"field":"name"
},
{
"type":"int64",
"optional":false,
"field":"ts_ms"
},
{
"type":"string",
"optional":true,
"name":"io.debezium.data.Enum",
"version":1,
"parameters":{
"allowed":"true,last,false"
},
"default":"false",
"field":"snapshot"
},
{
"type":"string",
"optional":false,
"field":"db"
},
{
"type":"string",
"optional":false,
"field":"schema"
},
{
"type":"string",
"optional":false,
"field":"table"
},
{
"type":"int64",
"optional":true,
"field":"txId"
},
{
"type":"int64",
"optional":true,
"field":"lsn"
},
{
"type":"int64",
"optional":true,
"field":"xmin"
}
],
"optional":false,
"name":"io.debezium.connector.postgresql.Source",
"field":"source"
},
{
"type":"string",
"optional":false,
"field":"op"
},
{
"type":"int64",
"optional":true,
"field":"ts_ms"
},
{
"type":"struct",
"fields":[
{
"type":"string",
"optional":false,
"field":"id"
},
{
"type":"int64",
"optional":false,
"field":"total_order"
},
{
"type":"int64",
"optional":false,
"field":"data_collection_order"
}
],
"optional":true,
"field":"transaction"
}
],
"optional":false,
"name":"data.cdc.dbname.Envelope"
},
"payload":{
"before":null,
"after":{
"id":1005,
"first_name":"foo",
"last_name":"bar",
"email":"foo@bar.com"
},
"source":{
"version":"1.2.3.Final",
"connector":"postgresql",
"name":"dbserver1",
"ts_ms":1600374991648,
"snapshot":"false",
"db":"postgres",
"schema":"public",
"table":"customers",
"txId":602,
"lsn":34088472,
"xmin":null
},
"op":"c",
"ts_ms":1600374991762,
"transaction":null
}
}{
"schema":{
"type":"struct",
"fields":[
{
"type":"int32",
"optional":false,
"field":"id"
}
],
"optional":false,
"name":"data.cdc.dbname.Key"
},
"payload":{
"id":1005
}
}{
"schema":{
"type":"struct",
"fields":[
{
"type":"struct",
"fields":[
{
"type":"int32",
"optional":false,
"field":"id"
},
{
"type":"string",
"optional":false,
"field":"first_name"
},
{
"type":"string",
"optional":false,
"field":"last_name"
},
{
"type":"string",
"optional":false,
"field":"email"
}
],
"optional":true,
"name":"data.cdc.dbname.Value",
"field":"before"
},
{
"type":"struct",
"fields":[
{
"type":"int32",
"optional":false,
"field":"id"
},
{
"type":"string",
"optional":false,
"field":"first_name"
},
{
"type":"string",
"optional":false,
"field":"last_name"
},
{
"type":"string",
"optional":false,
"field":"email"
}
],
"optional":true,
"name":"data.cdc.dbname.Value",
"field":"after"
},
{
"type":"struct",
"fields":[
{
"type":"string",
"optional":false,
"field":"version"
},
{
"type":"string",
"optional":false,
"field":"connector"
},
{
"type":"string",
"optional":false,
"field":"name"
},
{
"type":"int64",
"optional":false,
"field":"ts_ms"
},
{
"type":"string",
"optional":true,
"name":"io.debezium.data.Enum",
"version":1,
"parameters":{
"allowed":"true,last,false"
},
"default":"false",
"field":"snapshot"
},
{
"type":"string",
"optional":false,
"field":"db"
},
{
"type":"string",
"optional":false,
"field":"schema"
},
{
"type":"string",
"optional":false,
"field":"table"
},
{
"type":"int64",
"optional":true,
"field":"txId"
},
{
"type":"int64",
"optional":true,
"field":"lsn"
},
{
"type":"int64",
"optional":true,
"field":"xmin"
}
],
"optional":false,
"name":"io.debezium.connector.postgresql.Source",
"field":"source"
},
{
"type":"string",
"optional":false,
"field":"op"
},
{
"type":"int64",
"optional":true,
"field":"ts_ms"
},
{
"type":"struct",
"fields":[
{
"type":"string",
"optional":false,
"field":"id"
},
{
"type":"int64",
"optional":false,
"field":"total_order"
},
{
"type":"int64",
"optional":false,
"field":"data_collection_order"
}
],
"optional":true,
"field":"transaction"
}
],
"optional":false,
"name":"data.cdc.dbname.Envelope"
},
"payload":{
"before":{
"id":1005,
"first_name":"foo",
"last_name":"bar",
"email":"foo@bar.com"
},
"after":{
"id":1005,
"first_name":"egg",
"last_name":"bar",
"email":"foo@bar.com"
},
"source":{
"version":"1.2.3.Final",
"connector":"postgresql",
"name":"dbserver1",
"ts_ms":1600375609365,
"snapshot":"false",
"db":"postgres",
"schema":"public",
"table":"customers",
"txId":603,
"lsn":34089688,
"xmin":null
},
"op":"u",
"ts_ms":1600375609778,
"transaction":null
}
}
INSERT: hodnotenie pred (pred) je rovné null, a po - reťazec, ktorý bol vložený. UPDATE: do payload.before zobrazuje predchádzajúci stav riadka, a v payload.after — nový s podstatou zmien.2.2 MongoDB
{
"name": "mp-k8s-mongo-connector",
"config": {
"connector.class": "io.debezium.connector.mongodb.MongoDbConnector",
"tasks.max": "1",
"mongodb.hosts": "MainRepSet/mongo:27017",
"mongodb.name": "mongo",
"mongodb.user": "debezium",
"mongodb.password": "dbname",
"database.whitelist": "db_1,db_2",
"transforms": "AddPrefix",
"transforms.AddPrefix.type": "org.apache.kafka.connect.transforms.RegexRouter",
"transforms.AddPrefix.regex": "mongo.([a-zA-Z_0-9]*).([a-zA-Z_0-9]*)",
"transforms.AddPrefix.replacement": "data.cdc.mongo_$1"
}
}transformácie tentoraz robia nasledujúce: premieňajú názov cieľového topiku zo schémy .. v data.cdc.mongo_.Odolnosť voči zlyhaniam
Záver
P.S.
