FinTechSep 9, 2026قراءة 10 دقائق

بيانات سوق L2 تحت الاندفاع: فجوات التسلسل والاسترداد والـ fan-out إلى مئات الجلسات

بيانات السوقOrder Bookبنية التداول التحتيةFan-Out
تعذّر تحميل الصورة

المعالج الذي يُسقط تحديثات order book ويعيد ترتيبها تحت الاندفاع هو عادةً عطلان منفصلان خلف عرَض واحد: التعامل مع التسلسل في جانب الاستقبال، وطبقة توزيع تغيّر فيها جلسة بطيئة واحدة ما تتلقاه كل جلسة أخرى. هكذا يُبنى التسلسل والاسترداد والـ fan-out والـ back pressure، وهنا يكفّ الـ conflation عن الصدق.

المعالج الذي يُسقط تحديثات L2 ويعيد ترتيبها تحت الاندفاع هو عادةً عطلان منفصلان خلف عرَض واحد. أحدهما في جانب الاستقبال، حيث يُتتبَّع تسلسل التغذية وحيث يجب كشف الفجوة لا ابتلاعها. والآخر في جانب التوزيع، حيث يُوزَّع دفتر موحَّد واحد بالـ fan-out على جلسات كثيرة، فيغيّر قارئ بطيء واحد ما يصل إلى الباقين.

لكل منهما علاج مختلف، وتطبيق العلاج الخاطئ ينقل العرَض بدل أن يزيله. وما يلي هو شكل خط المعالجة حين يكون على التسلسل أن ينجو من الاندفاع: ما الفجوة فعلًا، وكيف يصل الاسترداد لقطةً بتدفق حي، وكيف يحسم الـ fan-out الترتيب مرة واحدة، وأين يكون الـ conflation صادقًا.

الإجابة القصيرة بنيوية. يُحسم الترتيب في مكان واحد بالضبط، في أعلى مجرى كل جلسة: كاتب واحد لكل أداة يطوي التغذية المرقّمة في دفتر، وتتلقى الجلسات مشاهد مشتقة من ذلك الطي - ولا تعيد ترتيب أي شيء لنفسها أبدًا. وما تستطيع amBrain إثباته علنًا: بورصة مصغّرة بنيناها تعمل في بيئة الإنتاج على استضافة MOEX المشتركة، وبنينا طرفية التداول Spectre Trade، وزمن استجابة بيانات السوق الذي ننشره مقاس - أقل من 5 ms على المسارات التي نبنيها. وهذا الرقم يصف مساراتنا نحن، لا اختبار أداء للتصميم أدناه.

رقم التسلسل يَعِد بالترتيب لا بالتسليم

التغذيات ترقّم تحديثاتها، وذلك الرقم هو المرجع الوحيد للترتيب لديك. أما وقت الوصول فليس مرجعًا: مسارات الـ multicast تعيد الترتيب، وقنوات عدة تحمل أداة واحدة، وطوابير الاستقبال موزعة على الأنوية، والاندفاع يشدّ ذلك كله. والمعالج الذي يرتّب حسب الوصول صحيح فقط ما دامت الشبكة هادئة - وهي الحالة التي لم يقلق منها أحد.

ست خصائص للتغذية يجب معرفتها قبل كتابة منطق الاسترداد. وكل واحدة منها تغيّر معنى الفجوة.

  • الوحدة التي يغطيها التسلسل - قناة أو أداة أو دفتر. فالرقم لكل قناة لا يخبرك أي أداة فقدت تحديثًا، والرقم لكل أداة لا يخبرك أن قناة توقفت
  • قاعدة الزيادة: تتابع صارم داخل الوحدة، أو تصاعد مع ثقوب مسموح بها. كلاهما موجود، وقراءة الثانية على أنها الأولى تنتج عمليات استرداد لم تكن لازمة قط
  • هل تبدأ الأرقام من جديد عند حد الجلسة وما الذي يشير إلى ذلك - فبداية جديدة تُقرأ على أنها فجوة ترسل كل أداة إلى الاسترداد في اللحظة نفسها
  • هل تحمل نبضات الـ heartbeat التسلسل الحالي. فبدونها يبدو الاتصال الميت والأداة الهادئة سواء
  • هل توجد إعادة إرسال وعلى أي نافذة. فإن لم توجد، يكون الاسترداد باللقطة هو طريق العودة الوحيد، وعليه أن يكون رخيصًا بما يكفي لاستخدامه كثيرًا
  • بأي رقم تسلسل تتحاذى اللقطة. فبدونه لا يمكن وصل اللقطة بتدفق حي إطلاقًا

حيث تكون الخاصية مجهولة فعلًا، قِسها بدل أن تبرمج تخمينًا. فكل واحدة من الست تصير فرعًا في مسار الاسترداد، والافتراض الخاطئ هناك يُكتشف لاحقًا في صورة دفتر يخالف منصة التداول بصمت.

الفجوة وتبدّل الترتيب يبدوان متطابقين بضع مللي ثانية

كلاهما يبدأ بالطريقة نفسها: التحديث التالي لا يحمل الرقم الذي توقعته. الفرق هو الزمن، لذا لا يُصنَّف الأمر عند الوصول بل عند انقضاء انتظار محدود.

  • خارج الترتيب: توقعت N، ووصلك N+2، ثم يصل N+1 والانتظار ما زال مفتوحًا. لا شيء ناقص، والكلفة الوحيدة هي الانتظار
  • تكرار أو إعادة إرسال: رقم عند آخر رقم مطبَّق أو دونه. يُسقَط دون المساس بالدفتر، ويُحصى، لأن ارتفاع معدل التكرار يقول شيئًا عن المسار
  • فجوة: انقضى الانتظار ولم يصل N+1 قط. لا يستطيع الدفتر تجاوز الثقب، وتذهب هذه الأداة إلى الاسترداد
  • متأخر: الرقم الصحيح، لكنه متأخر عن أن يفيد. وصلت البايتات، وهو في اتجاه المصب خسارة

قاعدة واحدة تمنع الفساد من أن يصير صامتًا: لا يُطبَّق التحديث إلا حين يكون تسلسله هو المتوقَّع بالضبط. وكل ما عدا ذلك يذهب إلى مخزن الانتظار أو إلى الاسترداد. فالدفتر الذي يقبل دلتا خارجة عن الترتيب يواصل تقديم الأسعار ويبدو سليمًا - ويُكتشف خلافه مع منصة التداول لاحقًا، من عميل، عند تنفيذ لم يكن له معنى.

الانتظار بنية محدودة لا طابور ينمو. يحمل التحديثات السابقة للرقم المتوقع، مفهرسة بالتسلسل، فيكون إطلاقها بحثًا مباشرًا لا فرزًا.

  • الإطلاق حلقة: طبّق الرقم المتوقع، ثم طبّق ما هو مخزّن أصلًا ما دامت الأرقام متتابعة
  • المهلة يُعبَّر عنها بالزمن، لا بعدد التحديثات المعلّقة وحده - فالاندفاع يملأ نافذة قائمة على العدد أبكر بكثير مما قصد التصميم
  • ما ينتظره المخزن المؤقت ينتظره كل مستهلك. فاضبط المهلة على إعادة الترتيب المقاسة على مسارك أنت، لا على رقم بدا آمنًا
  • فيضان المخزن المؤقت هو نفسه إعلان فجوة: فالانتظار محدود في الذاكرة كما هو محدود في الزمن
  • الانتظار لكل أداة أو لكل قناة، لا عامًا أبدًا. فأداة واحدة هادئة يجب ألا تحبس كل ما حولها

الاسترداد لقطة تُوصَل بتدفق كنت تخزّنه مؤقتًا أصلًا

الوصل هو الجزء الذي يختل. فاللقطة دفتر عند رقم تسلسل ما، وهي قديمة لحظة إنتاجها؛ وما يجعلها صالحة للاستخدام هو التدفق التزايدي المخزّن أثناء جلبها.

  • خزّن التدفق التزايدي مؤقتًا قبل طلب اللقطة. فاللقطة التي لا يقف خلفها تدفق حي تصل وهي متأخرة عن السوق أصلًا
  • اقرأ رقم التسلسل الذي تتسق معه اللقطة. وإن لم تنشر التغذية رقمًا، فهي عمليًا تغذية لقطات فقط، وعلى التصميم أن يقول ذلك صراحة
  • تخلّص من التحديثات المخزّنة عند تسلسل اللقطة أو دونه، ثم طبّق الباقي بالترتيب. وإن لم يكن أولها التحديث الذي يلي اللقطة مباشرة، فقد فشل الوصل ويبدأ الاسترداد من جديد
  • إن امتلأ المخزن المؤقت قبل وصول اللقطة، فأعد بدء الاسترداد بدل تطبيق جزء منه - فالاسترداد المطبَّق جزئيًا لا يمكن تمييزه عن دفتر سليم
  • انشر الأداة بحالة متدهورة أثناء استردادها، كحالة صريحة على التدفق. فدفتر فيه ثقب، يُقدَّم على أنه الحالي، أسوأ من لا دفتر
  • تحقّق بعد الوصل: بالـ checksum الذي تنشره التغذية إن كانت تنشره، أو بتطابق دفترك المطوي مع اللقطة التالية

الاسترداد حدث عادي لا حادث، وكلفته تنتمي إلى خطة السعة: كم يستغرق جلب اللقطة، وكم من التدفق يُخزَّن مؤقتًا في أثناء ذلك، وكم أداة تستطيع الاسترداد معًا قبل أن تصير خدمة اللقطات عنق الزجاجة.

Fan-out: تطبيع مرة، وترميز مرة، وإرسال للكثيرين

مئات جلسات الطرفيات تريد الدفتر نفسه. والخطأ الذي يتضاعف تحت الاندفاع هو أداء عمل لكل جلسة وهو ليس بطبيعته كذلك: إعادة بناء دفتر لكل مشترك، أو ترميز التحديث نفسه تسلسليًا مرة لكل socket.

  • كاتب واحد لكل shard من الأدوات يملك الدفتر. والقرّاء لا يعدّلونه أبدًا، ما يزيل القفل وسؤال أي نسخة هي المرجع معًا
  • الكاتب ينشر تحديثات ذات إصدارات في ring buffer يتابعه القرّاء بإيقاعهم، فلا يبطّئ القارئ المتأخر أحدًا
  • كل تحديث يُرمَّز مرة واحدة لكل صيغة على السلك ويُشارَك بين الجلسات بالإشارة. والتأطير والتحكم بالتدفق وحدهما لكل جلسة
  • كل جلسة تحمل رقم تسلسل صادر خاصًا بها، فيستطيع العميل كشف خسائره دون أن يعرف شيئًا عن التغذية في الأعلى
  • الترتيب مضمون لكل أداة، لأن هذا هو الضمان الذي يعتمد عليه العملاء. أما الترتيب عبر الأدوات فإما أن يُوعد به صراحة ويُنفَّذ، وإما ألا يُوعد به إطلاقًا
  • خارج العملية الواحدة يصبح الـ fan-out طبقة مُرحِّلات: كل مُرحِّل يأخذ اشتراكًا واحدًا في الأعلى ويخدم حصة من الجلسات، فيبقى عمل الكاتب ثابتًا

كلفة الـ fan-out يحدّدها عددُ مرات تحويل التحديث، لا عددُ الـ sockets التي تستقبله. فالترميز مرة واحدة وتمرير إشارة يتوسّع مع عدد الجلسات؛ أما إعادة بناء دفتر لكل جلسة فلا.

المستهلك البطيء سياسة تختارها لا حادثة تقع

في مكان ما توجد جلسة على شبكة سيئة، أو طرفية تعطّلت حلقة الرسم فيها، ويمتلئ مخزنها الصادر. وهناك أربعة سلوكيات ممكنة، اثنان منها لا يُختاران إلا بالصدفة.

  • حجب الكاتب حتى تُفرَّغ الجلسة البطيئة: أبدًا. فهو يحوّل اتصالًا سيئًا واحدًا إلى حدث latency لكل من على الـ shard
  • تكبير الطابور بلا حد: المستهلك البطيء يصير استنزافًا للذاكرة، ثم انقطاعًا لا صلة له بالجلسة الأصلية
  • طابور محدود مع conflation: صحيح لحالة الدفتر، حيث يريد العميل الصورة الحالية لا كل خطوة وسيطة
  • طابور محدود مع قطع الاتصال عند حد أعلى: صحيح للتدفقات التي لا تقبل الـ conflation، حيث إسقاط بند يُسقط معنى
  • أيًّا كانت السياسة، فالطابور لكل جلسة، ويُقاس التأخر باستمرار - عمق الطابور، والمسافة بين التسلسل المنشور والتسلسل المكتوب إلى الـ socket
  • قطع الاتصال يذكر سببه. فالإغلاق بلا تفسير تُعاد محاولته في حلقة؛ أما المفسَّر فيتبعه اشتراك جديد

الـ back pressure هو نقطة التقاء الجانبين. فإذا استطاع المسار الصادر أن يضغط على كاتب الدفتر، فإن طرفية بطيئة تؤخّر في النهاية طيّ التغذية، ويبدأ كشف الفجوات بإطلاق التنبيهات لأسباب لا علاقة لها بمنصة التداول. ووجود ring buffer محدود بين الاثنين يقطع هذه السلسلة.

الـ conflation صادق مع الحالة وخاطئ مع الأحداث

الدفتر حالة: العميل يريد المستويات الحالية، والقيمة التي استُبدلت أصلًا لا تحمل معنى بذاتها. أما شريط الصفقات فسجل أحداث، كل بند فيه واقعة حدثت ولا يمكن اختصارها بالتجميع.

  • ما يخضع للـ conflation: تحديثات المستويات السعرية، وقمة الدفتر، والعمق المجمّع، والإحصاءات المشتقة كآخر سعر أو حجم الجلسة
  • ما لا يخضع للـ conflation: الصفقات والطبعات، وتقارير الأوامر والتنفيذات، وتغيّرات المزاد والمراحل، وكل ما يجمعه العميل عبر الزمن - فالشريط المبني على تدفق خاضع للـ conflation رقم خاطئ يُحمَل بثقة
  • طبّق الـ conflation لكل مفتاح، لا لكل تدفق. فالاحتفاظ بآخر تحديث لكل مستوى سعري يحفظ الدفتر؛ أما الاحتفاظ بآخر تحديث إجمالًا فيرمي كل مستوى لم يتغيّر أخيرًا
  • التحديث الخاضع للـ conflation يحمل رقم تسلسل الحالة التي يمثّلها، فيعرف العميل النقطة التي يقابلها
  • فترة الـ conflation جزء من زمن الاستجابة الذي تعلنه. فالتدفق الخاضع للـ conflation على فترة لا يصفه زمن الاستجابة المقاس على التدفق غير الخاضع لها
  • العميل الذي يحتاج كل حالة وسيطة - اختبار رجعي أو سجل امتثال - يأخذ التدفق غير الخاضع للـ conflation ويدفع الثمن في عرض النطاق

الـ conflation تغيير في الشكل لا إعداد ضغط. فمتى خضع تدفق للـ conflation، لم يعد بوسع العميل إعادة بناء ما جرى بين تحديثين، ولا يجوز أن يُقال له إن التدفق كامل. ونشر الاثنين معًا - تدفق دفتر خاضع للـ conflation وتدفق أحداث غير خاضع له - هو ما يُبقي نوعَي العملاء على صواب.

إعادة الاتصال إعادة مزامنة، وهي تصل كلها دفعة واحدة

حين تعود جلسة، يكون الدفتر الذي تحمله بلا قيمة ما لم يستطع الخادم إثبات الاستمرارية. والوضع الافتراضي لقطة جديدة لكل اشتراك، برقم تسلسلها، تُطبَّق على عميل أسقط حالته المحلية أولًا.

  • الاستئناف من رقم تسلسل لا يُتاح إلا حيث يوجد مخزن إعادة تشغيل محدود. وحين يكون الرقم المطلوب قد انقضى عمره، يقول الخادم ذلك ويعود إلى لقطة بدل إرسال تدفق فيه ثقب
  • حالة الجلسة عبر إعادة الاتصال قرار صريح: إما أن يحتفظ الخادم بالاشتراكات مدة محدودة تحت رمز جلسة، وإما أن يعيد العميل ذكرها عند الاتصال. كلاهما يعمل؛ أما الخليط الضمني فلا
  • التسليم المكرر بعد الاستئناف متوقع، والعميل يتخلص منه بالتسلسل. وتنفيذ at-least-once مع ترقيم التسلسل أسهل صوابًا من exactly-once
  • عمليات إعادة الاتصال تصل معًا، لأن ما قطع جلسة واحدة قطع عادةً جلسات كثيرة. وتراجع زمني متفاوت عند العميل وتحكّم في القبول عند الخادم يمنعان الاسترداد من أن يصير الانقطاع الثاني
  • لقطات ذلك الحشد تأتي من ذاكرة تخزين مؤقت لكل أداة تُحدَّث بإيقاع منتظم، فيهيّئ الكاتب اللقطة وفق جدول لا مرة لكل جلسة تعيد الاتصال
  • الدفتر في جانب العميل يُعاد بناؤه ولا يُرقَّع أبدًا. فالطرفية التي تحتفظ بمستوياتها القديمة وتطبّق دلتات جديدة فوقها تحمل خطأ ما قبل القطع إلى دفتر يبدو الآن جديدًا

العطل الذي يستحق التصميم له ليس إعادة اتصال واحدة. إنه حدث شبكي يعيد مئات الجلسات في الثانية نفسها، كل واحدة تطلب لقطة لكل أداة كانت تراقبها، بينما يسترد جانب الاستقبال من الفجوة التي أحدثها الحدث نفسه.

ما تستطيع amBrain إثباته علنًا: نبني منصات تداول منخفضة زمن الاستجابة، و matching engines، وأنظمة مزايدة آنية بلغة Rust من يريفان، أرمينيا، وزمن استجابة بيانات السوق الذي ننشره - أقل من 5 ms - مقاس على المسارات التي نبنيها. وإن كان معالجك يفقد التسلسل تحت الاندفاع، فالحديث الذي يستحق أن يجري هو الذي يفصل جانب الاستقبال عن جانب التوزيع قبل إعادة كتابة أي منهما.

هل لديك تصميم مشابه على الطاولة؟

أحضر بنيتك الحالية وسيناريو الفشل الذي يقلقك، وسنراجعه معًا خلال نصف ساعة.

مقالات ذات صلة

تعذّر تحميل الصورة
FinTech
Sep 9, 2026قراءة 10 دقائق

توظيف مهندسين أم الاستعانة بشريك تقني: كيف تحسب كلفة المسارين

اقرأ المقال
تعذّر تحميل الصورة
FinTech
Sep 8, 2026قراءة 9 دقائق

تصميم matching engine بلغة Rust: price-time priority بلا وقفات GC

اقرأ المقال
تعذّر تحميل الصورة
FinTech
Sep 8, 2026قراءة 8 دقائق

فحوص المخاطر قبل التداول داخل مسار الأوامر

اقرأ المقال