CQRS وفصل القراءة/الكتابة
ما هو CQRS
CQRS (فصل مسؤولية استعلام القيادة) هو نهج معماري يفصل بين نموذج البيانات والمكونات المسؤولة عن الكتابة (الأوامر) والقراءة (الاستفسارات).
الفكرة: تم تحسين عملية تغيير الولاية للثوابت والمعاملات الصالحة، والقراءة للتوقعات السريعة والمستهدفة والتوسع.
المفتاح> الأوامر تغير الحالة وتعيد نتيجة العملية. تتم قراءة الطلبات فقط وليس لها آثار جانبية.
لماذا تحتاجه
قراءة الأداء: الإسقاطات المجسدة لسيناريوهات محددة (الأشرطة والتقارير والكتالوجات).
استقرار المسار الحرج: تسجيل معزول عن الانضمامات والتجمعات «الثقيلة».
حرية اختيار التخزين: OLTP للكتابة، OLAP/cache/محركات البحث للقراءة.
التطور المتسارع: أضف وجهات نظر جديدة دون خطر «كسر» المعاملات.
إمكانية الملاحظة والتدقيق (خاصة بالاقتران مع مصادر الأحداث): من الأسهل استعادة الدولة وإعادة تشغيلها.
متى يتم التقديم (ومتى لا)
مناسب إذا:- تسود القراءات بشرائح بيانات مختلفة وتجميع معقد.
- يجب أن يكون مسار التسجيل النقدي دقيقًا ويمكن التنبؤ به.
- وثمة حاجة إلى اتفاقيات/اتفاقيات مختلفة للقراءة والكتابة.
- مطلوب عزل منطق كتابة المجال عن احتياجات التحليل/البحث.
- المجال بسيط، الحمل منخفض ؛ CRUD يتأقلم.
- الاتساق القوي بين القراءة والكتابة إلزامي لجميع السيناريوهات.
- الفريق عديم الخبرة والتعقيد التشغيلي غير مقبول.
المفاهيم الأساسية
ينوي Command-Nites تغيير الحالة («CreateOrder»، «CapturePayment»). يتحقق من الثوابت.
بيانات الاستعلام والاسترجاع («GetOrderById'،» ListUserTransactions'). لا آثار جانبية.
نموذج السجلات: المجاميع/الثوابت/المعاملات ؛ التخزين - سجل العلائقية/قيمة المفتاح/الحدث.
اقرأ نموذج (إسقاط): جداول/فهارس/ذاكرة تخزين مؤقت، متزامنة بشكل غير متزامن.
الاتساق: غالبا ما يكون بين التسجيل والقراءة ؛ المسارات النقدية - من خلال القراءة المباشرة من نموذج الكتابة.
الهندسة المعمارية (هيكل عظمي)
1. خدمة الكتابة: تقبل الأوامر، وتصادق على الثوابت، وتلتقط التغييرات (قاعدة البيانات أو الأحداث).
2. Outbox/CDC: نشر مضمون لحقيقة التغييرات.
3. معالجات الإسقاط: استمع إلى الأحداث/مراكز السيطرة على الأمراض وتحديث قراءة النماذج.
4. خدمة القراءة: تقدم استفسارات من الآراء/المخابئ/عمليات البحث المجسدة.
5. Sagas/orchestration: تنسيق العمليات المتقاطعة.
6. قابلية الملاحظة: تأخر الإسقاط، النسبة المئوية للتطبيقات الناجحة، DLQ.
تصميم نموذج تسجيل
المجاميع: حدود المعاملات الواضحة (على سبيل المثال، «الطلب» و «الدفع» و «رصيد المستخدم»).
الثوابت: إضفاء الطابع الرسمي (المبالغ النقدية ≥ 0، التفرد، الحدود).
الأوامر خفية حسب المفتاح (على سبيل المثال، «الخصوصية _ المفتاح»).
المعاملات ضئيلة النطاق ؛ الآثار الجانبية الخارجية - عبر صندوق الخروج.
مثال القيادة (Pseudo-JSON)
json
{
"command": "CapturePayment",
"payment_id": "pay_123",
"amount": 1000,
"currency": "EUR",
"idempotency_key": "k-789",
"trace_id": "t-abc"
}
تصميم نموذج القراءة
ابدأ من الاستفسارات: ما هي الشاشات/التقارير المطلوبة ؟
التجريد مقبول: نموذج القراءة - «ذاكرة التخزين المؤقت المثلى».
عدة إسقاطات لمهام مختلفة: البحث (OpenSearch)، التقارير (تخزين الأعمدة)، البطاقات (KV/Redis).
TTL وإعادة تجميعها: يجب أن تكون الإسقاطات قادرة على التعافي من المصدر (إعادة تشغيل الحدث/لقطات).
الاتساق و UX
الاتساق النهائي: يمكن للواجهة عرض البيانات القديمة لفترة قصيرة.
أنماط UX: «يتم تحديث البيانات»...، واجهة مستخدم متفائلة، ومؤشرات التزامن، وتمنع الإجراءات الخطيرة حتى يتم تأكيدها.
بالنسبة للعمليات التي تتطلب اتساقا قويا (على سبيل المثال، إظهار توازن دقيق قبل الشطب)، تُقرأ مباشرة من نموذج الكتابة.
CQRS ومصادر الأحداث (اختياري)
تخزن Event Sourcing (ES) الأحداث، وحالة المجموع هي نتيجة لاجتماعها.
توفر حزمة CQRS + ES تدقيقًا مثاليًا وإعادة تجميع سهلة للتوقعات، ولكنها تزيد من التعقيد.
البديل: قاعدة بيانات OLTP العادية + outbox/CDC → الإسقاطات.
النسخ المتماثل: Outbox و CDC
Outbox (في معاملة واحدة): كتابة تغييرات المجال + كتابة حدث إلى صندوق خارجي ؛ الناشر يسلم إلى الإطار.
CDC: القراءة من سجل قاعدة البيانات (Debezium، إلخ) → التحول إلى أحداث المجال.
الضمانات: افتراضيًا مرة واحدة على الأقل، يجب أن يكون المستهلكون والتوقعات خفية.
اختيار التخزين
اكتب: علائقية (PostgreSQL/MySQL) للمعاملات ؛ KV/Document - حيث الثوابت بسيطة.
اقرأ:- KV/Redis - بطاقات وقراءات سريعة للمفاتيح ؛
- البحث (OpenSearch/Elasticsearch) - البحث/المرشحات/الجوانب ؛
- العمود (ClickHouse/BigQuery) - التقارير ؛
- Cache on CDN - public directories/content.
أنماط التكامل
طبقة واجهة برمجة التطبيقات: نقاط/خدمات منفصلة لـ «أوامر» و «استفسارات».
الخصوصية: مفتاح العملية في الرأس/الجسم ؛ تخزين المفاتيح الحديثة مع TTL.
Sagas/orchestration: المهلة، التعويضات، تكرار الخطوة.
Backpressure-Limits التوازي بين معالجات الإسقاط.
قابلية الملاحظة
مقاييس الكتابة: p95/99 وقت الأوامر، النسبة المئوية للمعاملات الناجحة، أخطاء التحقق.
اقرأ المقاييس: طلبات p95/99، مخبأ معدل الضرب، تحميل على مجموعة البحث.
تأخر الإسقاط (الوقت والرسائل)، معدل DLQ، نسبة التفريغ.
التتبع: «trace _ id» يمر عبر أمر outbox → → إسقاط الاستعلام →.
السلامة والامتثال
الفصل بين الحقوق: نطاقات/أدوار مختلفة للكتابة والقراءة ؛ مبدأ الامتياز الأقل.
PII/PCI: التقليل من الإسقاطات ؛ والتشفير أثناء الاستراحة/أثناء الطيران ؛ القناع.
مراجعة الحسابات: فريق إصلاح، ممثل، نتيجة، «تتبع _ معرف» ؛ محفوظات WORM للمجالات الحرجة (المدفوعات، KYC).
اختبار
اختبارات العقد: بالنسبة للأوامر (الأخطاء، الثوابت) والاستفسارات (الأشكال/المرشحات).
اختبارات الإسقاط: أرسل سلسلة من الأحداث/مركز السيطرة على الأمراض وتحقق من نموذج القراءة النهائية.
الفوضى/زمن الكمون: حقن زمن الكمون في معالجات الإسقاط ؛ فحص UX عند التأخير.
قابلية إعادة التشغيل: إعادة تجميع الإسقاطات على الحامل من اللقطات/السجل.
الهجرات والتطور
حقول جديدة - مضافة في الحدث/مركز السيطرة على الأمراض ؛ إعادة بناء النماذج.
الكتابة المزدوجة عند إعادة تصميم الدوائر ؛ عقد الإسقاطات القديمة حتى التبديل.
الإصدار: أحداث ونقاط النهاية «v1 »/« v2»، خطة غروب الشمس.
أعلام الميزات: إدخال استفسارات/إسقاطات جديدة على طول الكناري.
الأنماط المضادة
CQRS «من أجل الموضة» في خدمات CRUD البسيطة.
الاعتماد المتزامن على القراءة والكتابة (يقتل العزلة والمثابرة).
فهرس واحد للجميع: مزج الاستفسارات غير المتجانسة في متجر قراءة واحد.
ولا تنطوي الإسقاطات → ازدواجية وتباين.
إسقاطات غير قابلة للاسترداد (بدون إعادة تشغيل/لقطات).
أمثلة على المجالات
المدفوعات (الخدمة الإلكترونية)
اكتب: «إذن»، «التقاط»، «استرداد» في قاعدة بيانات المعاملات ؛ ينشر outbox مدفوعات. '.
اقرأ:- إعادة «بطاقة الدفع» لواجهة المستخدم ؛
- ClickHouse للإبلاغ ؛
- OpenSearch للبحث عن المعاملات.
- المسار الحرج: الترخيص ≤ 800 ms p95 ؛ اقرأ الاتساق مع واجهة المستخدم - في نهاية المطاف (حتى 2-3 ث).
KYC
اكتب: أوامر لبدء/تحديث الحالة ؛ تخزين PII في قاعدة بيانات آمنة.
اقرأ: إسقاط خفيف الوزن للأوضاع بدون PII ؛ يتم تشديد PII إذا لزم الأمر.
الأمن: نطاقات مختلفة لحالة القراءة والوصول إلى الوثائق.
الميزانيات العمومية (iGaming/Finance)
اكتب: «توازن المستخدم» مع الزيادات/الانخفاضات الذرية ؛ مفاتيح خفية للجراحة.
اقرأ: ذاكرة التخزين المؤقت لـ «التوازن السريع» ؛ للشطب - القراءة المباشرة من الكتابة (الاتساق الدقيق).
الملحمة: يتم تنسيق الودائع/الاستنتاجات من خلال الأحداث، في حالة الإخفاقات - التعويض.
قائمة التنفيذ المرجعية
- يتم إبراز مجاميع وثوابت نموذج الكتابة.
- يتم تحديد الاستفسارات الرئيسية ووضع الإسقاطات لها.
- تم تكوين Outbox/CDC ومعالجات الإسقاط الخفية.
- هناك خطة لقطة/إعادة تشغيل.
- SLO: زمن انتقال الأمر، تأخر الإسقاط، توافر القراءة/الكتابة بشكل منفصل.
- نفذت حقوق الوصول المنفصلة وتشفير البيانات.
- تنبيهات DLQ/فشل التأخير/التفريغ.
- الاختبارات: العقود، التوقعات، الفوضى، إعادة التشغيل.
التعليمات
هل مصادر الحدث إلزامية لـ CQRS ؟
لا ، ليس كذلك يمكنك البناء على قاعدة بيانات منتظمة + outbox/CDC.
كيف تتعامل مع عدم التزامن ؟
تصميم صريح UX، قياس تأخر الإسقاط، دع العمليات الحرجة تقرأ من الكتابة.
هل من الممكن الاحتفاظ بالكتابة والقراءة في نفس الخدمة ؟
نعم، الفصل المادي اختياري ؛ التقسيم المنطقي للمسؤوليات إلزامي.
ماذا عن المعاملات بين المجاميع ؟
من خلال القصص والأحداث ؛ تجنب المعاملات الموزعة إن أمكن.
النتيجة
CQRS يوحد الأيدي: مسار كتابة رفيع وموثوق به مع ثوابت واضحة وقراءات سريعة ومستهدفة من الإسقاطات المجسدة. هذا يزيد من الإنتاجية، ويبسط التطور، ويجعل النظام أكثر مرونة في مواجهة التوتر - إذا كان الاتساق وقابلية الملاحظة والهجرات منضبطة.