{"id":2007,"date":"2021-02-16T09:49:13","date_gmt":"2021-02-16T09:49:13","guid":{"rendered":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?p=2007"},"modified":"2021-02-16T09:49:13","modified_gmt":"2021-02-16T09:49:13","slug":"datenbankaenderungen-teil-2","status":"publish","type":"post","link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/","title":{"rendered":"Datenbank\u00e4nderungen erkennen und streamen mit Debezium und Apache Kafka (Teil 2) \u2013 Ein Beispiel"},"content":{"rendered":"\n<p>Im ersten Teil des Blogposts wurde vorgestellt, welche technischen M\u00f6glichkeiten man zum Erkennen von Datenbank\u00e4nderungen hat und wie das Tool Debezium zusammen mit der Plattform Apache Kafka genutzt werden kann, um solche Change-Events zu streamen und anderen Anwendungen zur Verf\u00fcgung zu stellen.<\/p>\n\n\n\n<p>Jetzt soll dazu St\u00fcck f\u00fcr St\u00fcck ein kleiner Prototyp erarbeitet werden, welcher die Funktionsweise von Debezium demonstriert. Die Architektur dazu ist folgenderma\u00dfen aufgebaut: Auf einer lokalen Instanz eines SQL Servers befindet sich eine Datenbank mit einer einzigen Tabelle, die den Namen CdcDemo tr\u00e4gt. Diese enth\u00e4lt ein paar wenige Datens\u00e4tze. Dazu wird jeweils eine Instanz von Apache Kafka und Kafka Connect aufgesetzt. In der Kafka-Instanz wird sp\u00e4ter ein Topic f\u00fcr Change-Events erstellt, w\u00e4hrend Kafka Connect den SQL-Server-Konnektor von Debezium beinhaltet. Letztendlich werden die \u00c4nderungsdaten aus dem Topic von zwei Anwendungen ausgelesen und vereinfacht auf der Konsole dargestellt. Die beiden Consumer sollen zeigen, dass sich die Nachrichten von Debezium auch parallelisiert verarbeiten lassen.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-1024x242.jpg\" alt=\"Architektur des Prototypen\" class=\"wp-image-2186\" width=\"768\" height=\"182\" srcset=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-1024x242.jpg 1024w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-600x142.jpg 600w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-768x182.jpg 768w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-1536x363.jpg 1536w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-640x151.jpg 640w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-1200x284.jpg 1200w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1-1920x454.jpg 1920w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1.jpg 2000w\" sizes=\"auto, (max-width: 639px) 98vw, (max-width: 1199px) 64vw, 768px\" \/><figcaption><em>Abbildung 1: Architektur des Prototypen<\/em><\/figcaption><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Vorbereitungen im SQL Server<\/h2>\n\n\n\n<p>Zuallererst muss die Grundlage daf\u00fcr gelegt werden, das Change Data Capture demonstrieren zu k\u00f6nnen, d. h. es muss eine kleine Datenbasis erstellt werden. Dazu wird in einer Datenbank einer lokalen SQL-Server-Instanz eine Tabelle mit dem folgenden Befehl angelegt:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">CREATE TABLE CdcDemo (\n\tId INT PRIMARY KEY,\n\tSurname VARCHAR(50) NULL,\n\tForename VARCHAR(50) NULL\n)<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Nun k\u00f6nnen beliebige Datens\u00e4tze in die Tabelle eingef\u00fcgt werden. In diesem Beispiel handelt es sich um die Namen von ber\u00fchmten Autorinnen und Autoren.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Id<\/td><td>Surname<\/td><td>Forename<\/td><\/tr><tr><td>101<\/td><td>Lindgren<\/td><td>Astrid<\/td><\/tr><tr><td>102<\/td><td>King<\/td><td>Stephen<\/td><\/tr><tr><td>103<\/td><td>K\u00e4stner<\/td><td>Erich<\/td><\/tr><tr><td>&#8230;<\/td><td>&#8230;<\/td><td>&#8230;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Im Anschluss sind die f\u00fcr den Debezium-Konnektor spezifischen Vorkehrungen zu treffen. Das bedeutet im Falle des SQL Servers, dass sowohl die Datenbank als auch die Tabelle f\u00fcr das Change Data Capture aktiviert werden m\u00fcssen. Das geschieht \u00fcber die Ausf\u00fchrung der beiden folgenden Systemprozeduren:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">EXEC sys.sp_cdc_enable_db\n\nEXEC sys.sp_cdc_enable_table\n\t@source_schema = N\u2019dbo\u2019,\n\t@source_name = N\u2019CdcDemo\u2019,\n\t@role_name = N\u2019CdcRole\u2019<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>In diesem Beispiel ist dbo das Schema der Tabelle, die <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">CdcDemo <\/code>hei\u00dft. Der Zugriff auf die \u00c4nderungsdaten erfolgt \u00fcber die Rolle <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">CdcRole<\/code>.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Kafka und Debezium einrichten<\/h2>\n\n\n\n<p>Wenn die Vorbereitungen im SQL Server erfolgreich getroffen wurden, kann nun die f\u00fcr Debezium ben\u00f6tigte Infrastruktur eingerichtet werden. Zuvor sollte aber noch sichergestellt werden, dass eine aktuelle Version der Java-Runtime installiert ist.<\/p>\n\n\n\n<p>Jetzt kann die Apache-Kafka-Software von der offiziellen Downloadseite heruntergeladen und in einen beliebigen Ordner entpackt werden. Eine Installation ist nicht erforderlich. Danach muss der SQL-Server-Konnektor von Debezium heruntergeladen und ebenfalls in einen Ordner entpackt werden.<\/p>\n\n\n\n<p>Nach dem erfolgreichen Download von Apache Kafka und Debezium kann nun eine neue Konfiguration f\u00fcr den Konnektor mittels einer Java-Properties-Datei erstellt werden:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">name=srcsys1-connector\nconnector.class=io.debezium.connector.sqlserver.SqlServerConnector\ndatabase.hostname=123.123.123.123\ndatabase.port=1433\ndatabase.user=cdc-demo-user\ndatabase.password=cdc-demo-password\ndatabase.dbname=cdc-demo-db\ndatabase.server.name=srcsys1\ntable.whitelist=dbo.CdcDemo\ndatabase.history.kafka.bootstrap.servers=localhost:9092\ndatabase.history.kafka.topic=dbhistory.srcsys1<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Besonders wichtig ist die Einstellung <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">connector.class<\/code>. Diese gibt Kafka Connect an, welcher der zuvor heruntergeladenen, ausf\u00fchrbaren Konnektoren genutzt werden soll. Die Klassennamen der Debezium-Konnektoren finden sich in der jeweiligen Dokumentation. Weiterhin bestimmt <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">database.server.name<\/code> den logischen Namen, den Debezium f\u00fcr die Datenbank verwendet. Dieser ist wichtig f\u00fcr die sp\u00e4tere Benennung des Topics in Kafka. Mithilfe der Konfiguration <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">table.whitelist<\/code> k\u00f6nnen alle Tabellen angegeben werden, die der Debezium-Konnektor \u00fcberwachen soll. Eine Erkl\u00e4rung zu allen weiteren Parametern ist in der Dokumentation von Debezium zu finden.<\/p>\n\n\n\n<p>Als n\u00e4chstes muss die Konfigurationsdatei von Kafka Connect angepasst werden, welche sich im Ordner <em>config<\/em> der Kafka-Installation befindet. Da f\u00fcr dieses Beispiel nur eine Instanz gebraucht wird, ist die Datei <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">connect-standalone.properties<\/code> zu verwenden. An sich k\u00f6nnen hier die Voreinstellungen beibehalten werden. Nur f\u00fcr die Eigenschaft <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">plugin.path<\/code> muss der Pfad zum heruntergeladenen Debezium-Konnektor angegeben werden. Wichtig: Damit ist nicht der Pfad zu den JAR-Dateien gemeint, sondern zu dem Ordner in der Hierarchie dar\u00fcber, da Kafka Connect auch mehrere Konnektoren gleichzeitig ausf\u00fchren kann, die sich in diesem Ordner befinden.<\/p>\n\n\n\n<p>F\u00fcr Apache Kafka an sich ist noch eine kleine \u00c4nderung in der Konfigurationsdatei <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">server.properties<\/code> sinnvoll. Da letztendlich zwei Konsumenten die Debezium-Nachricht verarbeiten sollen, macht es auch Sinn, die Anzahl der Partitionen f\u00fcr ein Topic auf zwei zu erh\u00f6hen. Damit werden die Change-Events entweder in die erste oder in die zweite Partition geschrieben. Die Partitionen werden dann jeweils einem Consumer zugeordnet, sodass die Nachrichten parallel, aber nicht doppelt verarbeitet werden. Zur Umsetzung davon ist beim Parameter <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">num.partitions<\/code> die Zahl 2 einzutragen.<\/p>\n\n\n\n<p>Nachdem nun die beteiligten Komponenten konfiguriert wurden, k\u00f6nnen die Instanzen gestartet werden. Dabei ist die Beachtung der Reihenfolge wichtig.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ .\/bin\/zookeeper-server-start.sh config\/zookeeper.properties\n$ .\/bin\/kafka-server-start.sh config\/server.properties\n$ .\/bin\/connect-standalone.sh config\/connect-standalone.\n\tproperties &lt;path_to_debezium_config&gt;<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Zuerst wird der ZooKeeper gestartet, der f\u00fcr die Verwaltung der Kafka-Instanzen verantwortlich ist. Danach wird ein Kafka-Server ausgef\u00fchrt, der sich beim ZooKeeper anmeldet. Zum Schluss wird Kafka Connect zusammen mit dem Debezium-Konnektor gestartet.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Einen Consumer implementieren<\/h2>\n\n\n\n<p>Mittlerweile steht die Infrastruktur f\u00fcr Debezium vollst\u00e4ndig und es fehlt nur noch ein Consumer, der die Nachrichten aus Kafka verarbeiten kann. Daf\u00fcr wird beispielhaft unter Verwendung der Bibliothek Confluent.Kafka eine .NET-Core-Konsolenanwendung programmiert, die sich am Einf\u00fchrungsbeispiel der Bibliothek auf GitHub orientiert. Zus\u00e4tzlich dazu gibt es noch eine weitere Methode, die die gelesenen JSON-Nachrichten aus Kafka kurz und knapp auf der Konsole darstellt.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using Confluent.Kafka;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Threading;\n\nnamespace StreamKafka\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            var config = new ConsumerConfig\n            {\n                GroupId = \"streamer-group\",\n                BootstrapServers = \"localhost:9092\",\n                AutoOffsetReset = AutoOffsetReset.Earliest,\n            };\n\n            using (var consumer = new ConsumerBuilder&lt;Ignore, string&gt;(config).Build())\n            {\n                consumer.Subscribe(\"srcsys1.dbo.CdcDemo\");\n\n                CancellationTokenSource cts = new CancellationTokenSource();\n                Console.CancelKeyPress += (_, e) =&gt;\n                {\n                    e.Cancel = true;\n                    cts.Cancel();\n                };\n\n                try\n                {\n                    while (true)\n                    {\n                        try\n                        {\n                            var consumeResult = consumer.Consume(cts.Token);\n\n                            if (consumeResult.Message.Value != null)\n                                Console.WriteLine($\"[{consumeResult.TopicPartitionOffset}]  \" + ProcessMessage(consumeResult.Message.Value));\n                        }\n                        catch (ConsumeException e)\n                        {\n                            Console.WriteLine($\"Error occured: {e.Error.Reason}\");\n                        }\n                    }\n                }\n                catch (OperationCanceledException)\n                {\n                    consumer.Close();\n                }\n            }\n\n\n        }\n\n        static string ProcessMessage(string jsonString)\n        {\n            var jsonObject = JObject.Parse(jsonString);\n            var payload = jsonObject[\"payload\"];\n\n            string returnString = \"\";\n\n            char operation = payload[\"op\"].ToString()[0];\n\n            switch (operation)\n            {\n                case 'c':\n                    returnString += \"INSERT: \";\n                    returnString += $\"{payload[\"after\"][\"Id\"]} | {payload[\"after\"][\"Nachname\"]} | {payload[\"after\"][\"Vorname\"]}\";\n                    break;\n\n                case 'd':\n                    returnString += \"DELETE: \";\n                    returnString += $\"{payload[\"before\"][\"Id\"]} | {payload[\"before\"][\"Nachname\"]} | {payload[\"before\"][\"Vorname\"]}\";\n                    break;\n\n                case 'u':\n                    returnString += \"UPDATE: \";\n                    returnString += $\"{payload[\"before\"][\"Id\"]} | {payload[\"before\"][\"Nachname\"]} | {payload[\"before\"][\"Vorname\"]} --&gt; \" +\n                        $\"{payload[\"after\"][\"Id\"]} | {payload[\"after\"][\"Nachname\"]} | {payload[\"after\"][\"Vorname\"]}\";\n                    break;\n\n                default:\n                    returnString += $\"{payload[\"after\"][\"Id\"]} | {payload[\"after\"][\"Nachname\"]} | {payload[\"after\"][\"Vorname\"]}\";\n                    break;\n            }\n\n            return returnString;\n        }\n    }\n}<\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Im Quelltext gibt es einige interessante Stellen: Zun\u00e4chst wird f\u00fcr den Consumer eine Konfiguration erstellt. Diese beinhaltet eine <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">GroupId<\/code>, die durch eine Zeichenkette repr\u00e4sentiert wird. Die Gruppe dient dazu, die Arbeit unter den Konsumenten aufzuteilen, da Applikationen derselben Gruppe keine Nachrichten doppelt verarbeiten. Im Nachfolgenden abonniert der Consumer das Topic <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">srcsys1.dbo.CdcDemo<\/code>, das zuvor von Debezium automatisch in Kafka eingerichtet wurde. Der Name des Topics ergibt sich dabei aus den in der Debezium-Konfiguration angegebenen Parametern f\u00fcr den Server und die Tabelle. Im Anschluss geht der Consumer in eine Endlosschleife \u00fcber, in der Nachrichten gelesen, verarbeitet und ausgegeben werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Den Prototypen testen<\/h2>\n\n\n\n<p>Jetzt sind f\u00fcr diesen Prototyp alle erforderlichen Komponenten installiert, konfiguriert und implementiert. Es wird Zeit, den Prototypen auch einmal auszuprobieren. Daf\u00fcr ist es ratsam, zun\u00e4chst zwei Instanzen des implementierten Consumers zu starten und erst im Anschluss Kafka bzw. Debezium wie oben beschrieben auszuf\u00fchren.<\/p>\n\n\n\n<p>Sind alle Komponenten hochgefahren, f\u00fchrt der Debezium-Konnektor einen Snapshot der Datenbanktabelle durch und schreibt diese Nachrichten an Kafka. Dort warten schon die beiden Consumer. Sie sollten eine Ausgabe produzieren, die der folgenden Abbildung \u00e4hnlichsieht.<\/p>\n\n\n\n<figure class=\"wp-block-image size-medium\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"422\" src=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_2-600x422.png\" alt=\"\" class=\"wp-image-2031\" srcset=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_2-600x422.png 600w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_2.png 605w\" sizes=\"auto, (max-width: 639px) 98vw, (max-width: 1199px) 64vw, 600px\" \/><figcaption><em>Abbildung 2: Die Consumer geben den Snapshot der Datenbanktabelle aus<\/em><\/figcaption><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Kurz zur Bedeutung der Ausgabe: Die Informationen in den eckigen Klammern vor dem eigentlichen Datensatz geben Auskunft \u00fcber das Topic, die Partitionsnummer und die Lognummer der jeweiligen Nachricht. Es wird ersichtlich, dass sich ein Consumer nur um die Nachrichten einer Partition k\u00fcmmert. Debezium entscheidet durch Hashing und Modulo-Rechnung des Prim\u00e4rschl\u00fcssels, welcher Partition ein Datensatz zugeordnet wird.<\/p>\n\n\n\n<p>Nun kann man testen, wie Debezium auf \u00c4nderungen an der Tabelle reagiert. Mittels des SQL Server Management Studios lassen sich INSERT-, UPDATE-, und DELETE-Befehle auf der Datenbank ausf\u00fchren. Nur kurze Zeit, nachdem ein Statement abgesetzt wurde, sollten die Consumer darauf reagieren und eine entsprechende Ausgabe produzieren. Nachdem ein paar DML-Kommandos ausgef\u00fchrt wurden, k\u00f6nnte die Ausgabe wie folgt aussehen:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_3.png\" alt=\"\" class=\"wp-image-2029\" width=\"693\" height=\"333\" srcset=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_3.png 924w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_3-600x288.png 600w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_3-768x369.png 768w, https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_Datenbankaenderungen_Teil2_3-640x308.png 640w\" sizes=\"auto, (max-width: 639px) 98vw, (max-width: 1199px) 64vw, 693px\" \/><figcaption><em>Abbildung 3: Konsolenausgabe der Consumer nach einigen \u00c4nderungen auf der Tabelle<\/em><\/figcaption><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Eine Frage sollte zum Schluss noch gekl\u00e4rt werden: Ist es durch die Partitionierung der Nachrichten m\u00f6glich, dass Race Conditions auftreten? K\u00f6nnten sich also \u00c4nderungen am selben Datensatz \u00fcber die beiden Partitionen gegenseitig \u201e\u00fcberholen\u201c und somit in der falschen Reihenfolge verarbeitet werden? Die Antwort ist nein. Daran hat Debezium zum Gl\u00fcck schon gedacht. Da die Change-Events anhand ihres Prim\u00e4rschl\u00fcssels wie oben beschrieben den jeweiligen Partitionen zugeordnet werden, landen \u00c4nderungsdaten bez\u00fcglich desselben Datensatzes auch immer hintereinander in derselben Partition und werden dort nur von einem Consumer in der richtigen Reihenfolge verarbeitet.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n\n\n<p>Das Beispiel hat gezeigt, dass die Nutzung von Debezium zusammen mit Apache Kafka zum Streamen von Datenbank\u00e4nderungen recht einfach umzusetzen ist. Einf\u00fcge-, \u00c4nderungs- und L\u00f6sch-Befehle k\u00f6nnen damit in ann\u00e4hernder Echtzeit bearbeitet werden. Zus\u00e4tzlich zu den in diesem Prototyp gezeigten Beispielen gibt es auch die M\u00f6glichkeit, \u00c4nderungen am Datenschema zu streamen. Daf\u00fcr erstellt Debezium ein separates Topic in Kafka.<\/p>\n\n\n\n<p>Wichtig ist es zu beachten, dass der vorgestellte Prototyp nur ein Minimalbeispiel darstellt. F\u00fcr den produktiven Einsatz von Debezium ist es erforderlich, die entsprechenden Komponenten so zu skalieren, dass ein gewisses Ma\u00df an Fehlertoleranz und Ausfallsicherheit gew\u00e4hrleistet ist.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dieser Beitrag zeigt anhand eines Beispiels, wie relationale Datenbanken mit Debezium und Apache Kafka besser verwaltet werden k\u00f6nnen.<\/p>\n","protected":false},"author":107,"featured_media":2188,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","footnotes":""},"categories":[15,16],"tags":[542,544,545,546,547,548,549,550,551,553],"topics":[552],"class_list":["post-2007","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","category-dot-net","tag-datenbanken","tag-debezium","tag-streaming-plattform","tag-apache-kafka","tag-kafka","tag-change-events","tag-datenaenderungen","tag-datenbankaenderungen","tag-change-data-capture","tag-rela","topics-datenbankaenderungen-mit-debezium-und-apache-kafka"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.0 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Datenbank\u00e4nderungen erkennen und ... - ZEISS Digital Innovation Blog<\/title>\n<meta name=\"description\" content=\"Dieser Beitrag zeigt anhand eines Beispiels, wie relationale Datenbanken mit Debezium und Apache Kafka besser verwaltet werden k\u00f6nnen.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Datenbank\u00e4nderungen erkennen und ... - ZEISS Digital Innovation Blog\" \/>\n<meta property=\"og:description\" content=\"Dieser Beitrag zeigt anhand eines Beispiels, wie relationale Datenbanken mit Debezium und Apache Kafka besser verwaltet werden k\u00f6nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/\" \/>\n<meta property=\"og:site_name\" content=\"Digital Innovation Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-02-16T09:49:13+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1125\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Richard Mogwitz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:site\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Richard Mogwitz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"8\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/\",\"name\":\"Datenbank\u00e4nderungen erkennen und ... - ZEISS Digital Innovation Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg\",\"datePublished\":\"2021-02-16T09:49:13+00:00\",\"dateModified\":\"2021-02-16T09:49:13+00:00\",\"author\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/3465908d8147bde7af2b97ae3f00354e\"},\"description\":\"Dieser Beitrag zeigt anhand eines Beispiels, wie relationale Datenbanken mit Debezium und Apache Kafka besser verwaltet werden k\u00f6nnen.\",\"breadcrumb\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#primaryimage\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg\",\"width\":2000,\"height\":1125,\"caption\":\"Architektur des Prototypen\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Datenbank\u00e4nderungen erkennen und streamen mit Debezium und Apache Kafka (Teil 2) \u2013 Ein Beispiel\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\",\"name\":\"Digital Innovation Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/3465908d8147bde7af2b97ae3f00354e\",\"name\":\"Richard Mogwitz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/mogwitz_richard-e1608623929823-150x150.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/mogwitz_richard-e1608623929823-150x150.jpg\",\"caption\":\"Richard Mogwitz\"},\"description\":\"Richard Mogwitz studiert Angewandte Informatik an der HTW Dresden und ist seit 2019 bei der ZEISS Digital Innovation als Werkstudent t\u00e4tig. Dabei besch\u00e4ftigt er sich haupts\u00e4chlich mit der Entwicklung von .NET-Anwendungen, aber auch mit der Programmierung von Web-Applikationen mit Blazor und Angular.\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/richardmogwitz\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Datenbank\u00e4nderungen erkennen und ... - ZEISS Digital Innovation Blog","description":"Dieser Beitrag zeigt anhand eines Beispiels, wie relationale Datenbanken mit Debezium und Apache Kafka besser verwaltet werden k\u00f6nnen.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/","og_locale":"de_DE","og_type":"article","og_title":"Datenbank\u00e4nderungen erkennen und ... - ZEISS Digital Innovation Blog","og_description":"Dieser Beitrag zeigt anhand eines Beispiels, wie relationale Datenbanken mit Debezium und Apache Kafka besser verwaltet werden k\u00f6nnen.","og_url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/","og_site_name":"Digital Innovation Blog","article_publisher":"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/","article_published_time":"2021-02-16T09:49:13+00:00","og_image":[{"width":2000,"height":1125,"url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg","type":"image\/jpeg"}],"author":"Richard Mogwitz","twitter_card":"summary_large_image","twitter_creator":"@ZEISS_di","twitter_site":"@ZEISS_di","twitter_misc":{"Verfasst von":"Richard Mogwitz","Gesch\u00e4tzte Lesezeit":"8\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/","name":"Datenbank\u00e4nderungen erkennen und ... - ZEISS Digital Innovation Blog","isPartOf":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#primaryimage"},"image":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg","datePublished":"2021-02-16T09:49:13+00:00","dateModified":"2021-02-16T09:49:13+00:00","author":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/3465908d8147bde7af2b97ae3f00354e"},"description":"Dieser Beitrag zeigt anhand eines Beispiels, wie relationale Datenbanken mit Debezium und Apache Kafka besser verwaltet werden k\u00f6nnen.","breadcrumb":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#primaryimage","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi.jpg","width":2000,"height":1125,"caption":"Architektur des Prototypen"},{"@type":"BreadcrumbList","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/datenbankaenderungen-teil-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/"},{"@type":"ListItem","position":2,"name":"Datenbank\u00e4nderungen erkennen und streamen mit Debezium und Apache Kafka (Teil 2) \u2013 Ein Beispiel"}]},{"@type":"WebSite","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/","name":"Digital Innovation Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/3465908d8147bde7af2b97ae3f00354e","name":"Richard Mogwitz","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/mogwitz_richard-e1608623929823-150x150.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/mogwitz_richard-e1608623929823-150x150.jpg","caption":"Richard Mogwitz"},"description":"Richard Mogwitz studiert Angewandte Informatik an der HTW Dresden und ist seit 2019 bei der ZEISS Digital Innovation als Werkstudent t\u00e4tig. Dabei besch\u00e4ftigt er sich haupts\u00e4chlich mit der Entwicklung von .NET-Anwendungen, aber auch mit der Programmierung von Web-Applikationen mit Blazor und Angular.","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/richardmogwitz\/"}]}},"author_meta":{"display_name":"Richard Mogwitz","author_link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/richardmogwitz\/"},"featured_img":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/02\/202102_Datenbankaenderungen_Teil_2_1_fi-600x338.jpg","coauthors":[],"tax_additional":{"categories":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/java\/\" class=\"advgb-post-tax-term\">Java<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">.NET<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Java<\/span>","<span class=\"advgb-post-tax-term\">.NET<\/span>"]},"tags":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Datenbanken<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Debezium<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Streaming-Plattform<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Apache Kafka<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Kafka<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Change-Events<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Daten\u00e4nderungen<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Datenbank\u00e4nderungen<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Change Data Capture<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">rela<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Datenbanken<\/span>","<span class=\"advgb-post-tax-term\">Debezium<\/span>","<span class=\"advgb-post-tax-term\">Streaming-Plattform<\/span>","<span class=\"advgb-post-tax-term\">Apache Kafka<\/span>","<span class=\"advgb-post-tax-term\">Kafka<\/span>","<span class=\"advgb-post-tax-term\">Change-Events<\/span>","<span class=\"advgb-post-tax-term\">Daten\u00e4nderungen<\/span>","<span class=\"advgb-post-tax-term\">Datenbank\u00e4nderungen<\/span>","<span class=\"advgb-post-tax-term\">Change Data Capture<\/span>","<span class=\"advgb-post-tax-term\">rela<\/span>"]}},"comment_count":"0","relative_dates":{"created":"Posted 5\u00a0Jahren ago","modified":"Updated 5\u00a0Jahren ago"},"absolute_dates":{"created":"Posted on Februar 16, 2021","modified":"Updated on Februar 16, 2021"},"absolute_dates_time":{"created":"Posted on Februar 16, 2021 9:49 a.m.","modified":"Updated on Februar 16, 2021 9:49 a.m."},"featured_img_caption":"","series_order":"","_links":{"self":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/2007","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/users\/107"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/comments?post=2007"}],"version-history":[{"count":21,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/2007\/revisions"}],"predecessor-version":[{"id":2238,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/2007\/revisions\/2238"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media\/2188"}],"wp:attachment":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media?parent=2007"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/categories?post=2007"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/tags?post=2007"},{"taxonomy":"topics","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/topics?post=2007"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}