نموذج وقت التشغيل
نموذج وقت التشغيل يحدد كيف تعالج Asset Core تغييرات الحالة وتخدم الاستعلامات مع ضمانات حتمية وقابلة للتدقيق. إنه العمود الفقري المفاهيمي لكل واجهة برمجة تطبيقات (API) وSDK وسير عمل تشغيلي ستواجهه في أماكن أخرى في الوثائق.
المشكلة التي يحلها هذا المفهوم
تواجه الأنظمة الموزعة توتراً أساسياً بين الاتساق، والتوافر، وتحمل التقسيم. غالباً ما تضحي الأساليب التقليدية بأحد هذه العناصر لتحقيق الآخرين، مما يؤدي إلى مشاكل يصعب تصحيحها وأصعب في إعادة إنتاجها. في الأنظمة المكانية، تظهر هذه الإخفاقات كمواضع غير صحيحة، وتحديثات متضاربة، وانجراف حالة لا يمكن استردادها.
- حالات السباق عندما يقوم كتاب متعددون بتحديث نفس الحالة
- التحديثات المفقودة عندما تتداخل التغييرات المتزامنة مع بعضها البعض
- سلوك غير حتمي يجعل عملية تصحيح الأخطاء والتدقيق صعبة
- بروتوكولات التوافق المكلفة التي تضيف تأخيرًا وتعقيدًا
تحل Asset Core هذه المشكلات من خلال اعتماد بنية كاتب واحد مع مصدر الأحداث، مما يتيح تبادل قابلية الكتابة الأفقية مقابل الحتمية المطلقة والبساطة. من خلال المساحات الاسمية، لا يزال هذا التبادل يتوسع أفقياً دون المساس بالعقد.
الأفكار الأساسية
عالم الكتابة الفردية
لكل عالم كاتب واحد فقط. هذا هو الخيار المعماري الذي يجعل كل شيء آخر ممكنًا.
في الأنظمة الموزعة، تتطلب الكتابات المتعددة تنسيقًا: أقفال موزعة، بروتوكولات توافق (Raft، Paxos)، أو اتساق نهائي مع حل النزاعات. كل نهج يتبادل شيئًا ثمينًا - إما الكمون (القفل/التوافق) أو الحتمية (الاتساق النهائي). عند تصحيح خطأ في الإنتاج، يعني “الاتساق النهائي” “قد يكون غير متسق في الوقت الحالي، حظًا سعيدًا.”
يُزيل كاتب واحد هذه الفئة الكاملة من المشاكل:
-
لا توجد تكاليف تنسيق: كاتب واحد يعني عدم وجود أقفال موزعة، عدم وجود التزام ذو مرحلتين، عدم وجود تكاليف بروتوكول الإجماع. انتقالات الحالة فورية ومحلية.
-
لا توجد حالات سباق: عندما يقوم عملية واحدة فقط بتغيير الحالة، يتم تنفيذ العمليات بترتيب إجمالي. يمكنك التفكير في السبب والنتيجة بشكل خطي. يصبح تصحيح الأخطاء تحليلًا جنائيًا، وليس تخمينًا احتماليًا.
-
لا ضريبة بروتوكول التوافق: يضيف Raft و Paxos تأخيرًا يتراوح بين 2-3 مرات وتعقيدًا كبيرًا. يقوم الكاتب الفردي بتبادل التوسع الأفقي في الكتابة من أجل البساطة والسرعة.
التبادل حقيقي: لا يمكنك توسيع معدل الكتابة أفقيًا ضمن عالم واحد. يقوم خادم الكتابة بتسلسل جميع الالتزامات من خلال خط أنابيب واحد، مما يحد من معدل الكتابة إلى ما يمكن أن يتعامل معه عقدة واحدة. لكن AssetCore يجعل هذا التبادل واضحًا ويستعيد قابلية التوسع من خلال تقسيم الفضاءات الاسمية—كل مساحة اسم هي عالم كاتب واحد معزول. في الممارسة العملية، يتوسع معدل الأداء أفقيًا من خلال تقسيم الفضاءات الاسمية. وهذا يجعل الحتمية خيار تصميم بدلاً من خاصية عرضية.
سجل الالتزام كمصدر للحقائق
تُسجل جميع تغييرات الحالة كأحداث في سجل التزام يُضاف إليه فقط:
- يتم تجميع الأحداث في دفعات قبل الإقرار
- يتم إلحاق الدفعات قبل أن يتلقى العملاء استجابات النجاح (تعتمد المتانة على الخلفية)
- السجل هو السجل المعتمد لكل ما حدث
هذا الخيار التصميمي - اعتبار السجل كمصدر موثوق - له تداعيات عميقة. يعني أن التوقعات يمكن الاستغناء عنها: إذا فقدت حالة القراءة، يمكنك إعادة التشغيل من السجل. يعني أن التحليلات والإشعارات لا يمكن أن تنحرف عن مصدر الحقيقة لأنها تستهلك نفس السجل. يعني أن تصحيح الأخطاء الجنائي يصبح سفرًا عبر الزمن: إعادة تشغيل السجل حتى أي نقطة وفحص الحالة الدقيقة. الواجهة الخلفية قابلة للتوصيل، لذا يمكنك التشغيل في الذاكرة لمحاكاة / اختبارات (سريعة، غير دائمة) أو استخدام واجهات خلفية ملف / مقسمة لاستمرار الأعطال؛ تم تصميم الواجهة لاستيعاب واجهات إضافية حسب الحاجة.
بدون ذلك، ستحتفظ بمخازن تشغيلية وتحليلية منفصلة، وستكافح من أجل تزامن البيانات، وستفقد القدرة على الإجابة بشكل قاطع على “ما كانت الحالة في الساعة 3:47 مساءً يوم الثلاثاء عندما حدث الخطأ؟” يجعل سجل الالتزام هذا السؤال تافهًا. يتيح هذا التصميم إعادة التشغيل الحتمية: نظرًا لنفس تسلسل الأحداث، سيعيد أي قارئ بناء نفس الحالة. كما يضمن أن التحليلات والإشعارات والتوقعات مستمدة دائمًا من نفس مصدر الحقيقة.
توقعات
تُعتبر التوقعات وجهات نظر مُحسّنة للقراءة عن الحالة المستمدة من سجل الالتزام:
- يقوم الـ daemon بمتابعة سجل الالتزام للدفعات الجديدة
- يتم تطبيق الأحداث عبر إعادة التشغيل لتحديث الحالة في الذاكرة
- يتم نشر اللقطات بشكل ذري لخدمة الاستعلام
تكون التوقعات متسقة في النهاية مع سجل الالتزام. الفجوة بين الأحداث الملتزمة والتوقعات المنشورة هي فجوة الحداثة، والتي يتم قياسها وكشفها من خلال نقاط نهاية القراءة.
بنية ثلاثية الطبقات
تفصل وقت التشغيل الاهتمامات عبر ثلاث طبقات. هذه ليست تجريدًا عشوائيًا - إنها الطريقة التي تحقق بها AssetCore كل من الأداء والدقة.
بدون فصل، ستختلط كل عملية وصول التخزين، والتحقق من منطق الأعمال، وتنسيق المعاملات في دالة واحدة ضخمة. هذا يجعل الاختبار صعبًا (لا يمكن اختبار التحقق بدون التخزين)، وإعادة التشغيل هشة (منطق الأعمال أثناء إعادة التشغيل يعرض للخطر عدم الحتمية)، والأداء غير متوقع (لا يمكن تحسين المسار الساخن بشكل منفصل عن مسار التحقق).
تمنحك الطبقات الثلاث لـ AssetCore:
| الطبقة | المسؤولية | السلوك |
|---|---|---|
| L1 (التخزين) | تغييرات البيانات الخام | لا تحقق، لا أحداث |
| L2 (العمليات) | المنطق التجاري | يتحقق من الشروط المسبقة، يصدر أحداث |
| L3 (المعاملات) | التنسيق | يسجل التراجع، يتعامل مع إعادة التشغيل |
L1 (Storage) هي طبقة الأداء. تعرض مُعدلات بسيطة: “قم بتعيين هذا الرصيد إلى N”، “ضع هذه الحالة عند الإحداثيات (x,y)”. لا تحقق، لا أحداث، فقط تغيير في الحالة. هذا ما يستخدمه التشغيل المتكرر - تطبيق حالة نقي، سريع، وحتمي.
L2 (Operations) هي طبقة الصحة. تتحقق من الشروط المسبقة (“هل يوجد هذا الحاوية؟”، “هل هناك مساحة في هذا الموضع؟”)، تنفذ منطق الأعمال، وتصدر أحداثًا تصف ما الذي تغير. هنا تعيش قواعد المجال الخاصة بك.
L3 (المعاملات) هي طبقة التنسيق. تسجل خطوات التراجع لكل عملية بحيث يمكن أن تؤدي الأخطاء إلى التراجع. تدير دورة حياة الالتزام: تنفيذ العمليات بالتسلسل، ختم الأحداث في دفعة، إضافة إلى سجل الالتزام الخلفي، وإرجاع النجاح.
هذا الفصل يضمن أن:
- إعادة تشغيل سريعة: تم تحسين إعدادات L1 لمسار الأداء الساخن، بدون عبء التحقق
- منطق الأعمال القابل للاختبار: يمكن اختبار L2 بدون بنية تحتية للتخزين
- الاسترجاع الذري: يمكن لسجل التراجع L3 عكس أي تسلسل من العمليات
التكلفة: المزيد من طبقات التجريد. المكسب: يمكنك إعادة التشغيل عند آلاف الأحداث في الثانية لأن L1 مفصول عن منطق التحقق الخاص بـ L2.
كيف يتناسب مع النظام
نموذج التشغيل يشكل كل جانب من جوانب Asset Core:
مسار الكتابة:
- عميل يرسل طلب الالتزام
- يقوم الـ daemon بالتحقق من صحة وتنفيذ العمليات (L2/L3)
- يتم ختم الأحداث وإضافتها إلى سجل الالتزام الخلفي
- يتلقى العميل النجاح مع رقم التسلسل
مسار القراءة:
- قراءة سجل التزام ذيول الخدمة
- يتم إعادة تشغيل الأحداث عبر L1 setters (idempotent)
- يتم نشر التوقعات عبر التبادل الذري
- الاستعلامات المقروءة من العرض الحالي
الاسترداد:
- تحميل نقطة التحقق (آخر حالة معروفة جيدة)
- إعادة تشغيل الأحداث من موقع نقطة التحقق
- استئناف التشغيل العادي
المتغيرات الرئيسية والضمانات
الحتمية
نظرًا لتسلسل الأحداث نفسه، فإن إعادة التشغيل تنتج حالة متطابقة بايت. هذا هو ما يجعل تصحيح الأخطاء عبر الزمن، واستعادة الكوارث، والتدقيق الجنائي ممكنًا.
الحتمية أصعب مما تبدو. تحتوي معظم الأنظمة على مصادر خفية من عدم الحتمية: ساعات النظام (كل إعادة تشغيل ترى طابع زمني مختلف)، الحسابات العشرية العائمة (التقريب يختلف حسب وحدة المعالجة المركزية)، توليد الأرقام العشوائية (غير قابلة للتكرار)، واستدعاءات واجهة برمجة التطبيقات الخارجية (نتائج مختلفة في كل مرة). عندما يعتمد إعادة بناء الحالة على أي من هذه، تصبح إعادة التشغيل احتمالية - قد تحصل على نفس الحالة، أو قد لا تحصل عليها.
يعمل AssetCore على القضاء على عدم الحتمية من خلال القيود المعمارية:
- الأحداث تحمل حمولات هجينة (دلتا + حالة ما بعد)، ويستخدم إعادة التشغيل حقول حالة ما بعد (القيم الدقيقة التي يجب تعيينها، وليس العمليات لحسابها)
- إعادة التشغيل تستخدم L1 setters (لا حسابات، لا تحقق، فقط تطبيق الحالة)
- لا توجد تبعيات خارجية أثناء إعادة التشغيل (لا استدعاءات API، لا قراءات ساعة، لا عشوائية)
ما يتيحه هذا: إعادة التشغيل إلى أي نقطة في السجل وفحص الحالة الدقيقة، وإعادة بناء التوقعات من الصفر بثقة، وإثبات ما حدث ومتى لأغراض التدقيق. ما تتخلى عنه: لا يمكنك استدعاء واجهات برمجة التطبيقات الخارجية من العمليات أو الاعتماد على الوقت الفعلي—يجب أن يتدفق كل شيء من خلال سجل الالتزام.
التماثل
تطبيق نفس الحدث مرتين ليس له تأثير إضافي. هذه هي الخاصية التي تجعل إعادة التشغيل آمنة بعد الأعطال وفشل الشبكة.
بدون خاصية التكرار، فإن إعادة تشغيل الأحداث تكون خطيرة. إذا كان الحدث يقول “أضف 10 إلى هذا الرصيد”، فإن إعادة تشغيله مرتين تضيف 20 - لقد قمت بتغيير الحالة. إذا كان الحدث يقول “نقل الحالة إلى الموضع (3,5)”، فإن إعادة تشغيله قد تنجح في المرة الأولى وتفشل في الثانية (لأنها موجودة بالفعل)، مما يتسبب في سلوك متباين. يجب على الأنظمة التي ليست متكررة تتبع بالضبط أي الأحداث قد تم تطبيقها، مما يقدم محاسبة معقدة وأنماط فشل.
يضمن AssetCore أن تكون إعادة التشغيل غير قابلة للتغيير من حيث التصميم:
- الأحداث تحمل الحالة النهائية للتعيين (ليس دلتا للتطبيق)
- تعيد عملية التشغيل ببساطة الكتابة فوق تلك الحالة (تطبيق “تعيين الرصيد إلى 50” مرتين ينتج 50، وليس 100)
- آمن لإعادة المحاولة بعد الفشل (إذا لم تكن متأكدًا من تطبيق حدث ما، فقط قم بتطبيقه مرة أخرى)
ما يتيحه هذا: استعادة من الأعطال دون منطق استئناف معقد، وإعادة المحاولة دون تلف في الحالة، وثقة بأن “إعادة تشغيل السجل” دائمًا ما ينتج نفس النتيجة. ما تتخلى عنه: الأحداث أكبر قليلاً (تحمل الحالة بعد، وليس فقط دلتا)، لكن البساطة التشغيلية تستحق ذلك.
الذرة
تنجح جميع العمليات في المعاملة أو تفشل معًا. هذه هي الضمانة التي تمنع فساد الحالة الجزئية.
بدون الذرية، فإن فشل في العملية 5 من 10 يترك العمليات 1-4 ملتزمة و6-10 غير منفذة. حالتك الآن غير متسقة داخليًا - حاوية تم إنشاؤها ولكن لم يتم ملؤها أبدًا، تحويل تم تنفيذه جزئيًا، مثيل تم نقله ولكن مرجع الوالد له قديم. يتطلب تصحيح الأخطاء إعادة بناء “ما كان يجب أن يحدث”، وهو ما يكون غالبًا مستحيلًا. يرى المستخدمون حالة فاسدة، وتفشل العمليات بشكل غير متوقع، ويتآكل الثقة.
يطبق AssetCore الذرية من خلال سجل التراجع:
- تسجل سجلات L3 خطوات التراجع أثناء التنفيذ (عمليات عكسية لكل تغيير في الحالة)
- تؤدي الأخطاء إلى التراجع عن جميع التغييرات (إعادة تشغيل سجل التراجع بالعكس، واستعادة الحالة السابقة بالضبط)
- لا توجد التزامات جزئية مرئية (الاستعلامات لا ترى أبداً الحالات الوسيطة)
استجابة الخطأ تخبرك بأي عملية فشلت ولماذا، لكن الحالة تبقى نظيفة. ما تكسبه: الثقة في أن المعاملات الفاشلة لا تترك أي أثر، ولا حاجة لتنظيف يدوي بعد الفشل، والتناسق الداخلي هو ضمان وليس جهدًا أفضل. ما تتخلى عنه: لا يمكنك “تأكيد ما نجح وتخطي ما فشل” - إذا فشلت أي عملية، يتم التراجع عن المعاملة بالكامل. هذه ليست علة، بل هي التصميم. إذا كنت بحاجة إلى تقدم جزئي، قم بتقسيم المعاملة إلى تأكيدات أصغر مع نقاط تفتيش واضحة.
سلامة التصادم
مع وجود سجل التزام دائم، يستعيد النظام بشكل صحيح من الأعطال، دون فقدان البيانات ودون تدخل يدوي. هذا ما يجعل AssetCore آمناً للتشغيل في بيئة الإنتاج.
تتطلب معظم الأنظمة إجراءات تشغيل دقيقة بعد حدوث عطل: التحقق من الحالة التالفة، تسوية المعاملات الجارية، التحقق من التناسق بين النسخ، وربما الاستعادة من النسخة الاحتياطية. هذه الإجراءات عرضة للأخطاء (قد يغفل البشر عن بعض الخطوات) وتستغرق وقتًا طويلاً (تستغرق عملية الاستعادة من دقائق إلى ساعات). والأسوأ من ذلك، أن بعض الأعطال لا يمكن استعادتها تلقائيًا - فهي تتطلب إصلاحات يدوية للبيانات أو قبول فقدان البيانات.
تجعل بنية AssetCore استعادة النظام تلقائية وبدون فقدان البيانات عندما يكون سجل الالتزام دائمًا:
- سجل الالتزام يبقى محفوظًا بعد إعادة التشغيل عندما يكون مدعومًا بتخزين دائم
- تسجل نقاط التفتيش التقدم (لقطات لحالة الإسقاط في مواضع السجل المعروفة)
- يعيد التشغيل بناء أي حالة مفقودة (تحميل نقطة التحقق، إعادة التشغيل من تلك النقطة إلى رأس السجل)
بعد حدوث عطل، يستأنف خادم الكتابة من آخر نقطة تفتيش ويواصل معالجة السجل. يقوم خوادم القراءة بإعادة تحميل نقاط التفتيش الخاصة بها وإعادة التشغيل للأمام. مع وجود خلفية دائمة، لا يتم فقدان أي حالة (السجل يحتوي على كل شيء)، ولا يتطلب الأمر تدخلًا يدويًا (الاسترداد تلقائي)، ولا يمكن حدوث فساد (إعادة التشغيل حتمية وغير قابلة للتكرار). في أوضاع الذاكرة، تكون التاريخ متعمدة زائلة والاسترداد هو إعادة تشغيل نظيفة. ما تكسبه: بساطة تشغيلية، ثقة في استرداد الكوارث، لا صفحات في الساعة 3 صباحًا لإصلاح الحالة الفاسدة. ما تتخلى عنه: وقت الاسترداد يتناسب مع عدد الأحداث منذ آخر نقطة تفتيش، ولكن يتم أخذ نقاط التفتيش بشكل متكرر (قابل للتكوين، عادةً كل بضع ثوان).
انظر أيضًا
- الانتعاش وإعادة التشغيل - مدى “انتعاش” البيانات المقروءة
- المعاملات والعمليات - الوحدة الذرية للتغيير