العمل مع Apache Kafka في Node.js باستخدام مكتبة KafkaJS
\n\nApache Kafka هي منصة موزعة لتدفق الأحداث، أصبحت المعيار الفعلي لبناء أنظمة تبادل الرسائل عالية التحميل. في نظام Node.js، واحدة من أشهر وأكثر المكتبات استقرارًا للتفاعل مع Kafka هي KafkaJS. وهي عميل حديث وغير متزامن بالكامل، مكتوب بلغة JavaScript النقية، ويدعم جميع إمكانيات Kafka الأساسية: المنتجين، المستهلكين، مجموعات المستهلكين، إدارة الإزاحات (offsets)، والمعاملات.
\n\nفي هذه المقالة، سنشرح بالتفصيل كيفية تثبيت KafkaJS، وإعداد الاتصال بمجموعة Kafka، وإرسال وقراءة الرسائل، بالإضافة إلى أفضل الممارسات للعمل مع هذه المكتبة في بيئة الإنتاج.
\n\nتثبيت وإعداد KafkaJS
\n\nيتم تثبيت المكتبة باستخدام مدير الحزم القياسي npm:
\n\nnpm install kafkajs\n\nبعد التثبيت، يجب إنشاء عميل مع تحديد عناوين الوسطاء (brokers) ومعرف العميل. مثال على الحد الأدنى من التكوين:
\n\nconst { Kafka } = require('kafkajs');\n\nconst kafka = new Kafka({\n clientId: 'my-app',\n brokers: ['localhost:9092']\n});\n\nفي بيئة الإنتاج، يُوصى بتحديد عدة وسطاء مفصولين بفواصل لضمان تحمل الأخطاء، بالإضافة إلى إعداد SSL ومصادقة SASL:
\n\nconst kafka = new Kafka({\n clientId: 'my-production-app',\n brokers: ['broker1:9092', 'broker2:9092', 'broker3:9092'],\n ssl: true,\n sasl: {\n mechanism: 'scram-sha-256',\n username: 'myuser',\n password: 'mypassword'\n }\n});\n\nالمنتج: إرسال الرسائل إلى الموضوع (topic)
\n\nالمنتج مسؤول عن نشر الرسائل في موضوع Kafka المحدد. توفر KafkaJS وضعين لتشغيل المنتج: بسيط (send) ومعاملاتي (للتوصيل الدقيق). دعنا نلقي نظرة على مثال أساسي لإرسال رسالة:
\n\nconst producer = kafka.producer();\n\nasync function sendMessage() {\n await producer.connect();\n\n await producer.send({\n topic: 'test-topic',\n messages: [\n { key: 'user1', value: 'Hello Kafka from Node.js!' },\n { key: 'user2', value: JSON.stringify({ orderId: 123, amount: 2500 }) }\n ]\n });\n\n await producer.disconnect();\n}\n\nsendMessage().catch(console.error);\n\nالنقاط الرئيسية:
\n- \n
- topic — اسم الموضوع الذي سيتم إرسال الرسالة إليه. \n
- messages — مصفوفة من الكائنات، يمكن أن يحتوي كل منها على
key(اختياري) وvalue(سلسلة نصية أو Buffer). \n - يُوصى دائمًا باستدعاء
producer.connect()مرة واحدة عند بدء التطبيق وإعادة استخدام الاتصال. \n
لتحسين الأداء في الإنتاج، استخدم تجمع الاتصالات وإعداد acks:
const producer = kafka.producer({\n allowAutoTopicCreation: false,\n transactionTimeout: 30000\n});\n\nawait producer.send({\n topic: 'orders',\n messages: [{ value: 'New order' }],\n acks: -1 // انتظار التأكيد من جميع النسخ المتماثلة\n});\n\nالمستهلك: قراءة الرسائل من الموضوع
\n\nيسمح المستهلك بقراءة الرسائل من موضوع واحد أو أكثر. المفهوم الأكثر أهمية هو مجموعات المستهلكين (consumer groups)، التي تضمن موازنة الحمل وتضمن معالجة كل رسالة بواسطة مستهلك واحد فقط من المجموعة.
\n\nconst consumer = kafka.consumer({ groupId: 'my-group' });\n\nasync function consumeMessages() {\n await consumer.connect();\n await consumer.subscribe({ topic: 'test-topic', fromBeginning: true });\n\n await consumer.run({\n eachMessage: async ({ topic, partition, message }) => {\n console.log({\n partition,\n offset: message.offset,\n key: message.key.toString(),\n value: message.valu