الجزء 2: تتبع تغييرات البيانات (CDC) في MongoDB باستخدام Debezium و Memphis.dev

هذا الجزء الثاني من سلسلة من مقالات المدونة حول بناء نظام تحديث تسلسلي حدثي باستخدام Memphis.dev.

في مقالتنا الأخيرة المدونة قدمنا تنفيذًا مرجعيًا للتقاط أحداث تحديث بيانات الإصدار (CDC) من قاعدة بيانات PostgreSQL باستخدام Debezium Server و Memphis.dev. عن طريق استبدال Apache Kafka بـ Memphis.dev، قلل الحل بشكل كبير من الموارد التشغيلية والجهد الزائد – مما أنقذ المال وأعطى المطورين الفرصة للتركيز على بناء وظائف جديدة.

ومع ذلك، لا يتم استخدام قاعدة البيانات PostgreSQL فحسب، بل يوفر Debezium موصلات لقواعد بيانات مختلفة، بما في ذلك قاعدة البيانات المستندة غير العلائقية MongoDB. MongoDB مرغوب بين المطورين، وخاصة أولئك الذين يعملون بلغات البرمجة الديناميكية، حيث يتجنب تضارب المطابقة الكائن-العلائقية. يمكن للمطورين تخزين الكائنات والاستعلام عنها وتحديثها مباشرة في قاعدة البيانات.

في هذا المقال، نوضح كيفية تكييف حل CDC لـ MongoDB.

نظرة عامة على الحل

هنا، نصف هيكل الحل المرجعي لتقديم أحداث تحديث بيانات الإصدار باستخدام Memphis.dev. لم يتغير الهيكل مقارنةً بـ مقالتنا السابقة إلا باستبدال PostgreSQL بـ MongoDB.

A Todo Item generator script writes randomly generated records to MongoDB. Debezium Server receives CDC events from MongoDB and forwards them to the Memphis REST gateway through the HTTP client sink. The Memphis REST gateway adds the messages to a station in Memphis.dev. Lastly, a consumer script polls Memphis. dev for new messages and prints them to the console.

  • جهاز إنشاء مشروع المهام: يدخل مشروع مهمة عشوائية يتم إنشاؤها في مجموعة MongoDB كل 0.5 ثانية. يحتوي كل مشروع مهمة على وصف، تاريخ إنشاء المهمة، تاريخ استحقاق اختياري، وحالة الإكتمال.
  • MongoDB: مُعد بقاعدة بيانات واحدة تحتوي على مجموعة واحدة (todo_items).
  • خادم Debezium: مثيل لخادم Debezium معد بمصادر MongoDB وموصلات مصدر عميل HTTP.
  • بوابة REST في ممفيس.ديف: تستخدم التكوين القياسي.
  • ممفيس.ديف: معد بمحطة واحدة (todo-cdc-events) ومستخدم واحد (todocdcservice).
  • مستهلك الطباعة: سكريبت يستخدم SDK Python لممفيس.ديف لاستهلاك الرسائل وطباعتها على وحدة التحكم.

البدء

البرنامج التعليمي للتنفيذ متاح في دليل mongodb-debezium-cdc-example من مستودع حلول الأمثلة في ممفيس. مكتبة Docker Compose ستكون مطلوبة لتشغيله.

تشغيل التنفيذ

قم بإنشاء تصادف Docker لـ خادم Debezium، والمستهلك الطابع، وإعداد قاعدة البيانات (إنشاء الجدول وإنشاء المستخدم).

حاليًا، التنفيذ يعتمد على إصدار ما قبل الإصدار النهائي لخادم Debezium لدعم توكن JWT. سيتم بناء صورة Docker مباشرة من الفرع الرئيسي لمستودعات Debezium و Debezium Server. لاحظ أن هذه الخطوة يمكن أن تستغرق مدة طويلة (~20 دقيقة) لتشغيلها. عندما يتم إصدار Debezium Server 2.3.0، سننتقل لاستخدام صورة Docker العلوية.

الخطوة 1: بناء الصور

Shell

 

$ docker compose build --pull --no-cache

الخطوة 2: بدء مزود الخدمة Memphis.dev وبوابة REST

ابدأ مزود الخدمة Memphis.dev وبوابة REST. لاحظ أن خدمة Memphis-rest-gateway تعتمد على خدمة مزود الخدمة Memphis، لذا ستُبدأ خدمة مزود الخدمة Memphis كذلك.

Shell

 

$ docker compose up -d memphis-rest-gateway
Shell

 

 
[+] Running 4/4
 ⠿ Network mongodb-debezium-cdc-example_default                   Created                                                        0.0s
 ⠿ Container mongodb-debezium-cdc-example-memphis-metadata-1      Healthy                                                        6.0s
 ⠿ Container mongodb-debezium-cdc-example-memphis-1               Healthy                                                       16.8s
 ⠿ Container mongodb-debezium-cdc-example-memphis-rest-gateway-1  Started

الخطوة 3: إنشاء محطة ومستخدم مقابل في Memphis.dev

يتم تسليم الرسائل إلى “المحطات” في Memphis.dev؛ إنها تعادل “المواضيع” التي تستخدمها مزودات الخدمة للرسائل. انتقل بمتصفحك إلى الموقع:9000. انقر على الرابط “تسجيل الدخول باستخدام الجذر” في أسفل الصفحة.

قم بتسجيل الدخول باسم المستخدم الجذر وكلمة المرور memphis.

اتبع الخريطة الجديدة لإنشاء محطة تحمل اسم todo-cdc-events.

انشئ مستخدمًا يسمى todocdcservice بنفس قيمة كلمة المرور.

انقر فوق “التالي” حتى ينتهي الوصفي:

انقر فوق “انتقل إلى ملخص المحطة” للانتقال إلى صفحة ملخص المحطة.

الخطوة 4: بدء عملية الطباعة المستهلكة

استخدمنا SDK البايثون لـ Memphis.dev لإنشاء برنامج مستهلك يستأنف جرد محطة todo-cdc-events ويطبع الرسائل على وحدة التحكم.

Shell

 

$ docker compose up -d printing-consumer
Shell

 

 
[+] Running 3/3
 ⠿ Container mongodb-debezium-cdc-example-memphis-metadata-1  Hea...                                                             0.5s
 ⠿ Container mongodb-debezium-cdc-example-memphis-1           Healthy                                                            1.0s
 ⠿ Container printing-consumer                                Started     

الخطوة 5: بدء وتكوين MongoDB

لالتقاط التغييرات، يجب تمكين وظيفة التكرار في MongoDB. تتطلب ذلك عدة خطوات:

  • يجب تحديد اسم مجموعة التكرار. يمكن القيام بذلك عن طريق تمرير اسم مجموعة التكرار على سطر الأوامر أو في ملف التكوين. في ملف Docker Compose، نقوم بتشغيل MongoDB بوساطة الحجة على سطر الأوامر –replSet rs0 لتحديد اسم مجموعة التكرار.
  • عند استخدام التكرار وتمكين التفويض، يجب توفير ملف المفتاح المشترك لكل مثيل مكرر. قمنا بإنشاء ملف المفتاح وفقًا للتعليمات الموجودة في مستندات MongoDB. ثم أنشأنا صورة تعمل على توسيع الصورة الرسمية لـ MongoDB من خلال تضمين ملف المفتاح.
  • من الضروري تهيئة مجموعة المكرر بمجرد تشغيل MongoDB. نحن نستخدم سكربت يقوم بتهيئة المثيل عند بدء التشغيل. يستدعي السكربت الأمر replSetInitiate مع قائمة أضداد الأيبي والمواقع لكل مثيل MongoDB في مجموعة المكرر. يتسبب هذا الأمر في تواصل المثيلات من MongoDB مع بعضها البعض واختيار قائد.

بشكل عام، يتم استخدام مجموعات المكرر لزيادة الموثوقية (التوافر العالي). معظم المستندات التي ستجدها تصف كيفية إعداد مكرر مع عدة مثيلات MongoDB. في حالتنا، يستفيد موصل MongoDB لـ Debezium من وظيفة التكرار للتقاط أحداث تغيير البيانات. على الرغم من أننا نمر بخطوات تهيئة مجموعة المكرر، إلا أننا نستخدم مثيل واحد فقط من MongoDB.

إن سكريبت مولد عناصر المهام يخلق عنصر مهمة جديدة كل نصف ثانية. تُولد قيم الحقول بشكل عشوائي. يتم إضافة العناصر إلى مجموعة MongoDB بالاسم “todo_items”.

في ملف Docker Compose، يتم تكوين سكريبت مولد عناصر المهام ليعتمد على حالة تشغيل مثيل MongoDB السليم وإكمال نجاح سكريبت إعداد قاعدة البيانات. عند بدء سكريبت مولد عناصر المهام، سيبدأ Docker Compose أيضًا MongoDB ويعمل سكريبت إعداد قاعدة البيانات.

Shell

 

$ docker compose up -d todo-generator
Shell

 

[+] Running 3/3
 ⠿ Container mongodb                 Healthy                                                                                     8.4s
 ⠿ Container mongodb-database-setup  Exited                                                                                      8.8s
 ⠿ Container mongodb-todo-generator  Started   

الخطوة 6: بدء خدمة Debezium Server

آخر خدمة يجب بدءها هي خدمة Debezium Server. يتم تكوين الخادم بواسطة موصل مصدر لـ MongoDB وموصل صندوق التحويل الرئيسي للعميل HTTP من خلال ملف خصائص Java:

Shell

 

 
debezium.sink.type=http
debezium.sink.http.url=http://memphis-rest-gateway:4444/stations/todo-cdc-events/produce/single
debezium.sink.http.time-out.ms=500
debezium.sink.http.retries=3
debezium.sink.http.authentication.type=jwt
debezium.sink.http.authentication.jwt.username=todocdcservice
debezium.sink.http.authentication.jwt.password=todocdcservice
debezium.sink.http.authentication.jwt.url=http://memphis-rest-gateway:4444/
debezium.source.connector.class=io.debezium.connector.mongodb.MongoDbConnector
debezium.source.mongodb.connection.string=mongodb://db
debezium.source.mongodb.user=root
debezium.source.mongodb.password=mongodb
debezium.source.offset.storage.file.filename=data/offsets.dat
debezium.source.offset.flush.interval.ms=0
debezium.source.topic.prefix=tutorial
debezium.format.key=json
debezium.format.value=json
quarkus.log.console.json=false

معظم الخيارات واضحة المعنى. URL صندوق التحويل الرئيسي للعميل HTTP يستحق شرحه بالتفصيل. يتوقع بواترومب.dev موطن REST أن يستقبل طلبات POST بتنسيق المسار التالي:

/stations/{station}/produce/{quantity}

يتم استبدال {station} الأوسمة باسم المحطة التي ترسل الرسالة إليها. يتم استبدال {quantity} الأوسمة بالقيمة المفردة (لرسالة واحدة) أو التسلسل (لرسائل متعددة).

الرسالة (الرسائل) تُمرر كحاوية لطلب POST. البوابة REST تدعم ثلاثة أشكال للرسائل (نص عادي، JSON، أو بروتوكول باف). قيمة مسمى المفتاح content-type تحدد كيفية تفسير الحاوية.

عندما ينتج موضوع Debezium Server’s HTTP Client طلبات REST تتوافق مع هذه الأنماط. تستخدم الطلبات أفعال POST؛ كل طلب يحتوي على رسالة واحدة معززة بالـ JSON كحاوية، ومسمى المفتاح content-type معين إلى application/JSON. نستخدم todo-CDC-events كاسم المحطة وقيمة الكمية الفردية في عنوان URL النهائي لتوجيه الرسائل وللإشارة إلى كيفية تفسير الطلبات من قبل البوابة REST:

http://memphis-rest-gateway:4444/stations/todo-cdc-events/produce/single

الخاصية debezium.sink.http.authentication.type=jwt تشير إلى أن موضوع HTTP Client يجب أن يستخدم توكن JWT. خصائص الاسم المستعار وكلمة المرور واضحة، لكن الخاصية debezium.sink.http.authentication.jwt.The URL تستحق بعض الشرح. تُستلم التوكن الأولي باستخدام النهائي /auth/authenticate، بينما يتم تجديد التوكن باستخدام النهائي المنفصل /auth/refreshToken. تضيف التوكن JWT في موضوع HTTP Client النهائي المناسب إلى الـ URL الأساسي المعطى.

يمكن بدء Debezium Server بالأمر التالي:

Shell

 

$ docker compose up -d debezium-server
Shell

 

[+] Running 5/5
 ⠿ Container mongodb                                              Healthy                                                        1.5s
 ⠿ Container mongodb-debezium-cdc-example-memphis-metadata-1      Healthy                                                        0.5s
 ⠿ Container mongodb-debezium-cdc-example-memphis-1               Healthy                                                        1.0s
 ⠿ Container mongodb-debezium-cdc-example-memphis-rest-gateway-1  Running                                                        0.0s
 ⠿ Container debezium-server                                      Started

الخطوة 7: تأكد من عمل النظام

تحقق من شاشة todo-cdc-events station overview في واجهة Memphis.dev web UI للتأكد من أن المُنتج والمستهلك متصلان، وأن الرسائل تُوصل.

وطباعة السجلات لحافظة printing-consumer:

Shell

 

$ docker logs --tail 2 printing-consumer

رسالة:

Shell

 

bytearray(b'{"schema":{"type":"struct","fields":[{"type":"string","optional":true,"name":"io.debezium.data.Json","version":1,"field":"before"},{"type":"string","optional":true,"name":"io.debezium.data.Json","version":1,"field":"after"},{"type":"struct","fields":[{"type":"array","items":{"type":"string","optional":false},"optional":true,"field":"removedFields"},{"type":"string","optional":true,"name":"io.debezium.data.Json","version":1,"field":"updatedFields"},{"type":"array","items":{"type":"struct","fields":[{"type":"string","optional":false,"field":"field"},{"type":"int32","optional":false,"field":"size"}],"optional":false,"name":"io.debezium.connector.mongodb.changestream.truncatedarray","version":1},"optional":true,"field":"truncatedArrays"}],"optional":true,"name":"io.debezium.connector.mongodb.changestream.updatedescription","version":1,"field":"updateDescription"},{"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,incremental"},"default":"false","field":"snapshot"},{"type":"string","optional":false,"field":"db"},{"type":"string","optional":true,"field":"sequence"},{"type":"string","optional":false,"field":"rs"},{"type":"string","optional":false,"field":"collection"},{"type":"int32","optional":false,"field":"ord"},{"type":"string","optional":true,"field":"lsid"},{"type":"int64","optional":true,"field":"txnNumber"},{"type":"int64","optional":true,"field":"wallTime"}],"optional":false,"name":"io.debezium.connector.mongo.Source","field":"source"},{"type":"string","optional":true,"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,"name":"event.block","version":1,"field":"transaction"}],"optional":false,"name":"tutorial.todo_application.todo_items.Envelope"},"payload":{"before":null,"after":"{\\"_id\\": {\\"$oid\\": \\"645fe9eaf4790c34c8fcc2ec\\"},\\"creation_timestamp\\": {\\"$date\\": 1684007402475},\\"due_date\\": {\\"$date\\": 1684266602475},\\"description\\": \\"GMZVMKXVKOWIOEAVRYWR\\",\\"completed\\": false}","updateDescription":null,"source":{"version":"2.3.0-SNAPSHOT","connector":"mongodb","name":"tutorial","ts_ms":1684007402000,"snapshot":"false","db":"todo_application","sequence":null,"rs":"rs0","collection":"todo_items","ord":1,"lsid":null,"txnNumber":null,"wallTime":1684007402476},"op":"c","ts_ms":1684007402478,"transaction":null}}')

تنسيق رسائل CDC

الرسائل الواردة مُنسقة بتنسيق JSON. تحتوي الرسائل على حقلين علويين (المخطط والبدن). يصف المخطط مخطط السجل (أسماء الحقول وأنواعها)، بينما يصف البدن التغيير في السجل. يحتوي الكائن البدن نفسه على حقلين (قبل وبعد) يشيران إلى قيمة السجل قبل وبعد التغيير.

بالنسبة لـ MongoDB، يرمز Debezium Server سجل السجل كسلسلة نصية من الجسور اليابسة:

Shell

 

 
{
"before" : null,

"after" : "{\\"_id\\": {\\"$oid\\": \\"645fe9eaf4790c34c8fcc2ed\\"},\\"creation_timestamp\\": {\\"$date\\": 1684007402978},\\"due_date\\": {\\"$date\\": 1684266602978},\\"description\\": \\"buy milk\\",\\"completed\\": false}"
}

سيكون لهذا آثار على معالجة الرسائل في الخلفية، والتي سنوضحها في مقال للمدونة في المستقبل في هذه السلسلة.

مبروك! أنت الآن تمتلك مثالًا مُنشطًا لكيفية التقاط أحداث تغيير البيانات من قاعدة بيانات MongoDB باستخدام Debezium Server ونقل الأحداث إلى Memphis.dev لمعالجة الخلفية.

الجزء 3 قريبًا!

Source:
https://dzone.com/articles/part-2-change-data-capture-cdc-for-mongodb-with-de