النقاط الرئيسية

  • يخزن دفتر الأستاذ الخاص بـ Binance أرصدة الحسابات والمعاملات، كما يتيح أيضًا للخدمات إجراء المعاملات.

  • إنه يخلق الظروف اللازمة للإنتاجية العالية، والتوافر على مدار الساعة طوال أيام الأسبوع، ودقة البيانات على مستوى البت.

إن الدور الذي تلعبه Binance Ledger خلف الكواليس يجعلها واحدة من أهم تقنيات Binance. تعرف على كيفية عملها بالضبط والمشكلات التي تحلها في تشغيل أكبر بورصة للعملات المشفرة في العالم هنا.

هل تساءلت يومًا ما الذي يجعل Binance مميزًا؟ مع الحاجة إلى معالجة ملايين المعاملات يوميًا عبر قاعدة مستخدمين ضخمة، فمن الجدير إلقاء نظرة على ما تمتلكه Binance.

تكمن العمليات التقنية لدى Binance في Ledger الخاص بها. يقوم Ledger بتخزين أرصدة الحسابات والمعاملات، مع تمكين الخدمات من إجراء المعاملات.

لدى Binance متطلبات عالية للغاية بالنسبة للـ Ledger

كما تتخيل، ترتفع متطلبات الـ Ledger ليواكب الطلب الهائل على المستخدمين. وهناك ثلاث نقاط رئيسية يجب مراعاتها:

  • إنتاجية عالية مع القدرة على التعامل مع عدد كبير من TPS (المعاملات في الثانية) في أوقات الذروة.

  • التوفر على مدار الساعة (24/7) بدون توقف (downtime).

  • دقة بيانات على مستوى البت (bit-level)، دون فقد أموال أو أخطاء في المعاملات.

لنلقِ نظرة على مثال بسيط لإدخال في الـ Ledger. إليك معاملة شائعة يقوم فيها الحساب 1 بتحويل 1 BTC إلى الحساب 2.

الرصيد قبل المعاملة:

معرّف الحساب

اللقطة والاستعادة (Snapshot & Recovery)

الرصيد

1

BTC         

10

2

BTC

0.1

جدول-1

الرصيد بعد المعاملة:

معرّف الحساب

الأصل

الرصيد

1

BTC         

9

2

BTC

1.1

جدول-2

في هذه المعاملة، توجد أوامرَان:

  1. الحساب 1    -1 BTC

  2. الحساب 2   +1 BTC

عند إجراء المعاملة، سيتم تخزين سجلَّيْن للرصيد لأغراض التدقيق والتسوية.

معرّف الحساب

الأصل

التغيّر

معرّف المعاملة

الوقت

100001

BTC

-1

tx-001

2022-01-01  01:02:03

100002

BTC

+1

tx-001

2022-01-01  01:02:03

جدول-3

حلّ الصناعة المعياري

يعتمد حلّ دفتر أستاذ (Ledger) صناعي معياري واحد على قاعدة بيانات علائقية. بالعودة إلى المثال السابق، يمكن ترجمة أَمْرَي المعاملة إلى بيانين SQL وتنفيذهما داخل معاملة قاعدة بيانات (جدول-4).

بدء معاملة;

تحديث balance_1 set balance = balance - 1 

WHERE account_id=1 and asset = ‘BTC’ and balance - 1 >= 0; 

إذا لم يتأثر أي صف (0 صف) فقم بالترجيع (rollback);

تحديث balance_2 set balance = balance + 1 

WHERE account_id=2 and asset = ‘BTC’ and balance + 1 >= 0; 

إذا لم يتأثر أي صف (0 صف) فقم بالترجيع (rollback);

تثبيت (commit);

جدول-4

مزايا الحل

  1. إن تنفيذه بسيط للغاية.

  2. من السهل تطبيق تقنيات ضبط قواعد البيانات الشائعة مثل فصل القراءة/الكتابة والتجزئة لتحسين الأداء.

  3. ليس من الصعب على فريق devops التعافي من حالات فشل (failover)، وكذلك مراقبة قاعدة بيانات تجارية وصيانتها.

عيوب الحل

  1. سينخفض TPS بشكل حاد عند حدوث حالات سباق (race conditions) بسبب أقفال الصفوف (row locks).

  2. من الصعب التوسع أفقيًا لتحسين الأداء.

مشكلة الحساب الساخن (Hot Account)

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

يمكن عندها لباقي المعاملات ألا تفعل شيئًا سوى الانتظار حتى يتم تحرير القفل. نسمّي هذه الحالة مشكلة الحساب الساخن، وتُظهر الاختبارات الداخلية أن TPS سينخفض على الأقل 10 مرات في هذه الحالة. يمكنك رؤية هذه المشكلة في الجدول 5 أدناه.

مثال على الحساب الساخن:

Tx 1 (تحويل 1 BTC من الحساب 1 إلى الحساب 2)

Tx 2 (تحويل 2 BTC من الحساب 1 إلى الحساب 3)

بدء معاملة;

بدء معاملة;

تحديث balance set balance = balance - 1 

WHERE account_id=1 and asset = ‘BTC’ and balance - 1 >= 0; 

(تم قفل الصف: account_id=1 and asset = ‘BTC’)

إذا لم يتأثر أي صف (0 صف) فقم بالترجيع (rollback);

تحديث balance set balance = balance - 2 

WHERE account_id=1 and asset = ‘BTC’ 

و balance - 2 >= 0; 

إذا لم يتأثر أي صف (0 صف) فقم بالترجيع (rollback);

تحديث balance set balance = balance + 1 

WHERE account_id=2 and asset = ‘BTC’ and balance + 1 >= 0; 

إذا لم يتأثر أي صف (0 صف) فقم بالترجيع (rollback);

انتظار القفل

تثبيت (commit);

انتظار القفل

الحصول على القفل، ثم التنفيذ

تحديث balance set balance = balance + 2 

WHERE account_id=3 and asset = ‘BTC’ and balance + 1 >= 0; 

إذا لم يتأثر أي صف (0 صف) فقم بالترجيع (rollback);

تثبيت (commit);

جدول-5

حلّ Ledger لدى Binance 

كيف نعالج مشكلة الحساب الساخن؟

أحد الحلول الممكنة لمشكلتنا هو تحويل نموذج متعدد الخيوط (multi-threaded) بشكل مبتكر إلى وضع أحادي الخيط (single-threaded). يؤدي ذلك إلى تجنب مشكلة حالات السباق، ونتيجة لذلك، لن توجد مشكلة حساب ساخن.

نموذج الخيط الجديد

التواصل المعتمد على الرسائل

بعد تطبيق نموذج الخيوط الجديد، يجب حل مشكلة تواصل. طبقة آلة الحالة (state machine) أحادية الخيط، لكن طبقة الشبكة متعددة الخيوط؛ فكيف يمكننا التواصل بكفاءة بين الاثنين؟

يُعدّ Disruptor [1] الخطوة التالية في هذا اللغز. فهو ينشئ طابورًا (queue) عالي الأداء وبدون أقفال (lock-free) اعتمادًا على تصميم buffer حلقي (ring buffer).

عالية التوفر

حتى الآن، حققنا أداءً عاليًا باستخدام نموذج داخل الذاكرة (in-memory) وتخزين RocksDB [2] محليًا. لكن مرة أخرى تظهر تحديات جديدة. الآن نحتاج إلى ضمان توفر بيانات مرتفع.

لضمان اتساق البيانات بين العقد، نستخدم خوارزمية إجماع Raft [3]. وهذا يعني أن عدد نسخ البيانات الاحتياطية يساوي عدد العقد غير القائدة (non-leader) الموجودة. كما تضمن الخوارزمية أن النظام سيظل يعمل حتى إذا كانت ما لا يقل عن نصف العقد سليمة، بهدف توفير توفر خدمة مرتفع.

أدوار نطاق Raft:

  • القائد (Leader). يعالج القائد جميع طلبات العملاء ويقوم بتكرار العملية إلى جميع الأتباع (followers).

  • التابع (Follower). يتبع الأتباع القائد لجميع العمليات. إذا فشل القائد، سيتم انتخاب أحد الأتباع كقائد جديد. 

  • المتعلّم (Learner). المتعلمون هم أتباع غير مصوّتين يرسلون سجلات التغييرات الخاصة بكل معاملة/تبديل idempotent إلى خدمات أخرى.

أدوار نطاق Raft

CQRS (فصل مسؤولية الأوامر عن الاستعلامات)

معيار أساسي آخر نريد ضمانه هو أن يمتلك الـ Ledger أداء كتابة أعلى وقدرة على التعامل مع ظروف استعلامات أكثر تنوعًا. ولتحقيق ذلك، نحتاج إلى إنشاء مجالات (domains) مختلفة. يوفر نطاق raft كفاءة أعلى في الكتابة اعتمادًا على rocksdb+raft، بينما تستمع طبقة العرض (view domain) إلى رسائل نطاق raft وتقوم بحفظها في قاعدة بيانات علائقية للاستعلامات الخارجية. يمكننا أيضًا تطبيق فصل مسؤولية الأوامر عن الاستعلامات على مستوى المعمارية.

معمارية الـ Ledger

المعمارية العامة

مصطلحات بين Raft وLedger:

Raft

Ledger

آلات حالة مكررة (replicated state machines)

عُقد الـ ledger

الحالة

الرصيد

الأمر

المعاملة

جدول-6

أدوار طبقة العرض (View Domain)

  • مركز Ledger لـ Raft

استهلاك الرسالة التي ينتجها المتعلّم وتخزين بيانات المعاملة والرَصيد في MySQL لأغراض الاستعلام.

معالجة الطلب

سيتم تمرير طلب المعاملة أولاً عبر طبقة الشبكة، ثم طبقة الـ ledger (معالج الطلب)، ثم طبقة raft (مزامنة سجل raft). بعد ذلك، يعود إلى طبقة الـ ledger (آلة الحالة)، ثم طبقة الشبكة (معالج الاستجابة)، وأخيرًا يرجع استجابة للعميل.

يتم تمرير البيانات عبر الطابور (queue) بين الطبقتين. 

  1. طبقة الشبكة – فك تشفير (deserialize) طلب الـ rpc ووضعه في طابور الطلبات.

  2. طبقة الـ Ledger – الحصول على الطلب من الطابور وتجهيز السياق. ثم يتم وضع بيانات ميتاداتا الطلب في طابور raft. 

  3. طبقة Raft – الحصول على بيانات ميتاداتا الطلب من طابور raft ومزامنتها بين جميع الأتباع. ثم يتم وضع النتيجة في طابور apply.

  4. طبقة الـ Ledger – الحصول على البيانات من طابور apply وتحديث آلة الحالة. ثم يتم وضع النتيجة في طابور الاستجابة.

  5. طبقة الشبكة – الحصول على النتيجة من طابور الاستجابة وتكوين بيانات الاستجابة وتسلسلها (serialize) قبل إعادتها إلى العميل.

معالجة الطلب

استعادة البيانات

ستقوم كل عقدة في الـ Ledger بإنشاء لقطة (snapshot) عامة بناءً على فترة زمنية. بالإضافة إلى ذلك، نطبّق أيضًا لقطة متسقة. يتم تشغيل كل عقدة عند نفس فهرس سجل raft لضمان أن آلة الحالة هي نفسها تمامًا عندما تُنشئ كل عقدة لقطة. ثم يتم رفع اللقطة إلى S3 للتحقق بواسطة Checker وكاحتياط بارد (cold backup).

عند إعادة تشغيل الـ Ledger، يقرأ اللقطة المحلية ويعيد بناء آلة الحالة. ثم يعيد تشغيل (replay) سجل raft المحلي ويُزامن أحدث سجل من القائد حتى يلحق بأحدث فهرس. إذا لم تكن اللقطة المحلية أو سجل raft موجودًا، فسيتم الحصول عليها من القائد.

التحمل للكوارث (Disaster tolerance)

التحمل للأعطال

لتحسين التوفر والتسامح مع الأعطال، يتم نشر عقد Ledger في مناطق (zones) مختلفة. طالما أن أكثر من نصف العقد سليمة، فلن تُفقد البيانات وسيتم إكمال failover خلال ثانية واحدة. 

حتى في حال فشل المجموعة بالكامل (وهو احتمال منخفض جدًا)، يمكننا استعادة المجموعة عبر اللقطة المتسقة المخزنة في Amazon S3 واسترجاع أحدث البيانات المفقودة عبر النظام السفلي (downstream system).

التسامح مع الأعطال

الأداء

يوضح الجدول التالي مواصفات العتاد لاختبار الأداء

المكوّن

نوع المثيل

عرض النطاق للشبكة (Gbps)

عرض نطاق EBS (Gbps)

نوع تخزين EBS

القائد/الأتباع

M6i.4xlarge

16c64g

حتى 12.5

حتى 10

2T GP3 * 3 IOPS6000  625MB/s

المتعلّم (Learner)

M6i.4xlarge

16c64g

حتى 12.5

حتى 10

2T GP3 * 3 IOPS6000  625MB/s

Benchmark

C5.4xlarge

16c32g

حتى 10

4.750

فقط حجم الجذر (Root Volume)

تثبت الاختبارات الداخلية أن مجموعة من 4 عقد (قائد واحد، واتباعان، ومتعلّم واحد) يمكنها معالجة أكثر من 10,000 TPS. وبحسب التصميم، تقوم المجموعة بمعالجة جميع المعاملات واحدة تلو الأخرى. لا توجد أقفال أو حالات سباق على الإطلاق. لذلك، في سيناريو الحساب الساخن، تكون قيمة TPS مرتفعة كما هي في السيناريوهات العادية.

TPS للحساب الساخن

يوضح الشكل التالي زمن التأخير (latency) لكل معاملة. يمكن إتمام معظم المعاملات خلال 10 مللي ثانية. ويمكن إتمام المعاملات الأبطأ خلال 25 مللي ثانية.

زمن التأخير بالمللي ثانية

تقديم خدماتنا مدعومة بـ Binance Ledger

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

اقرأ المقال التالي لمزيد من المعلومات حول بنيتنا التكنولوجية:

  • (مدونة Binance) استخدام MLOps لبناء خط أنابيب تعلّم آلي لحظي من النهاية إلى النهاية

  • (مدونة Binance) قابل مدير التكنولوجيا (CTO): Rohit يتأمل في Crypto وBlockchain وWeb3 وأول شهر له في Binance 

المراجع

[1] LMAX Disruptor

[2] RocksDB  

[3] خوارزمية إجماع Raft