قاعدة بيانات بدون تخصيص للذاكرة الديناميكية

يتفاجأ بعض الأشخاص الذين قرأوا TIGER_STYLE.md (دليل ترميز TigerBeetle) عندما علموا أن TigerBeetle لا تخصص أي ذاكرة بعد بدء التشغيل. ذاكرة ثابتة ومخصصة ديناميكيًا

دعنا نلخص تخصيص الذاكرة بشكل عام. في معظم اللغات ، يمكنك اختيار الحصول على كائنات ومصفوفات ذات حجم ثابت عند بدء تشغيل البرنامج. أو يمكنك تغيير حجم الكائن والمصفوفة أثناء تشغيل البرنامج ، ربما لإضافة مفاتيح جديدة إلى الكائن أو ربما لتكبير المصفوفة لتناسب المزيد من العناصر.

على سبيل المثال ، إذا قمت بإنشاء مصفوفة فارغة في JavaScript وأدخلت عناصر فيها ، فقد تخصص المصفوفة وتعيد تخصيصها في الخلفية لاستيعاب المدخلات الجديدة. هذا هو تخصيص الذاكرة الديناميكي.

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

تمت كتابة TigerBeetle بلغة Zig. ومثل JavaScript ، يمكنك اختيار استخدام هياكل البيانات التي تخصص الذاكرة ديناميكيًا (مثل مصفوفات JavaScript) أو يمكنك اختيار تخصيص الذاكرة بشكل ثابت فقط. TigerBeetle يفعل هذا الأخير.

ولكن الجزء المثير للاهتمام من مكتبة Zig القياسية هو أن هياكل البيانات الخاصة بها مصممة لتكون متوافقة مع التخصيص الثابت. على سبيل المثال ، يستخدم TigerBeetle Zig's ArrayList و HashMap ولكن بأحجام ثابتة. تساعد طرق مثل ArrayList.addOneAssumeCapacity و HashMap.putAssumeCapacityNoClobber على اكتشاف الأخطاء حيث نخصص المزيد من الذاكرة عن طريق الخطأ. ما نحصل عليه

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

يسمح لنا تخصيص الذاكرة الثابتة بمعالجة الحمل الزائد بسهولة. مع العناصر الثابتة وأحجام المصفوفات ، لا يوجد مخزن مؤقت يستمر في النمو عندما يحاول العميل الذي تم تكوينه بشكل خاطئ إجراء عدد كبير جدًا من الاتصالات أو إرسال عدد كبير جدًا من الرسائل في وقت واحد. / p>

وهذا يجعل TigerBeetle أكثر قابلية للتنبؤ للمشغلين. مثل cgroups في قاعدة البيانات الخاصة بك.

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

بشكل أساسي ، يعمل TigerBeetle بكميات ثابتة من كل شيء: عدد التوصيلات رسائل متزامنة لكل اتصال الحد الأقصى لعدد النسخ المتماثلة في المجموعة حجم الرسالة طلبات البحث لكل رسالة (طلبات البحث مجمعة دائمًا) إلخ

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

على سبيل المثال ، إليك كيفية حساب مقدار الذاكرة اللازمة لتخزين الرسائل لبروتوكول إجماع TigerBeetle (حتى بالنسبة لجميع مجموعات التفاعلات المتزامنة وتغييرات البروتوكول): /// عدد الرسائل الكاملة المخصصة للتهيئة بواسطة تجمع الرسائل المتماثلة. /// يجب أن تكون هناك رسائل كافية للتأكد من استمرار تقدم النسخة المتماثلة ، لتجنب حدوث حالة توقف تام. pub const messages_max_replica = messages_max: { var sum: usize = 0 ؛ sum + = config.io_depth_read + config.io_depth_write ؛ // I / O log sum + = config.clients_max ؛ // نسخة طبق الأصل مجموع + = 1 ؛ // نسخة طبق الأصل sum + = config.pipeline_max ؛ // نسخة طبق الأصل مجموع + = 1 ؛ // Replica.commit_prepare // النصاب المتماثل .do_view_change_from_all_replicas: // Replica.recovery_response_quorum يُستخدم فقط للاسترداد ولا يزيد الحد الأقصى. // جميع نصاب القانون الأخرى عبارة عن مجموعات بت. sum + = config.replicas_max ؛ sum + = config.connections_max ؛ // Connection.recv_message sum + = config.connections_max * config.connection_send _...

قاعدة بيانات بدون تخصيص للذاكرة الديناميكية

يتفاجأ بعض الأشخاص الذين قرأوا TIGER_STYLE.md (دليل ترميز TigerBeetle) عندما علموا أن TigerBeetle لا تخصص أي ذاكرة بعد بدء التشغيل. ذاكرة ثابتة ومخصصة ديناميكيًا

دعنا نلخص تخصيص الذاكرة بشكل عام. في معظم اللغات ، يمكنك اختيار الحصول على كائنات ومصفوفات ذات حجم ثابت عند بدء تشغيل البرنامج. أو يمكنك تغيير حجم الكائن والمصفوفة أثناء تشغيل البرنامج ، ربما لإضافة مفاتيح جديدة إلى الكائن أو ربما لتكبير المصفوفة لتناسب المزيد من العناصر.

على سبيل المثال ، إذا قمت بإنشاء مصفوفة فارغة في JavaScript وأدخلت عناصر فيها ، فقد تخصص المصفوفة وتعيد تخصيصها في الخلفية لاستيعاب المدخلات الجديدة. هذا هو تخصيص الذاكرة الديناميكي.

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

تمت كتابة TigerBeetle بلغة Zig. ومثل JavaScript ، يمكنك اختيار استخدام هياكل البيانات التي تخصص الذاكرة ديناميكيًا (مثل مصفوفات JavaScript) أو يمكنك اختيار تخصيص الذاكرة بشكل ثابت فقط. TigerBeetle يفعل هذا الأخير.

ولكن الجزء المثير للاهتمام من مكتبة Zig القياسية هو أن هياكل البيانات الخاصة بها مصممة لتكون متوافقة مع التخصيص الثابت. على سبيل المثال ، يستخدم TigerBeetle Zig's ArrayList و HashMap ولكن بأحجام ثابتة. تساعد طرق مثل ArrayList.addOneAssumeCapacity و HashMap.putAssumeCapacityNoClobber على اكتشاف الأخطاء حيث نخصص المزيد من الذاكرة عن طريق الخطأ. ما نحصل عليه

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

يسمح لنا تخصيص الذاكرة الثابتة بمعالجة الحمل الزائد بسهولة. مع العناصر الثابتة وأحجام المصفوفات ، لا يوجد مخزن مؤقت يستمر في النمو عندما يحاول العميل الذي تم تكوينه بشكل خاطئ إجراء عدد كبير جدًا من الاتصالات أو إرسال عدد كبير جدًا من الرسائل في وقت واحد. / p>

وهذا يجعل TigerBeetle أكثر قابلية للتنبؤ للمشغلين. مثل cgroups في قاعدة البيانات الخاصة بك.

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

بشكل أساسي ، يعمل TigerBeetle بكميات ثابتة من كل شيء: عدد التوصيلات رسائل متزامنة لكل اتصال الحد الأقصى لعدد النسخ المتماثلة في المجموعة حجم الرسالة طلبات البحث لكل رسالة (طلبات البحث مجمعة دائمًا) إلخ

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

على سبيل المثال ، إليك كيفية حساب مقدار الذاكرة اللازمة لتخزين الرسائل لبروتوكول إجماع TigerBeetle (حتى بالنسبة لجميع مجموعات التفاعلات المتزامنة وتغييرات البروتوكول): /// عدد الرسائل الكاملة المخصصة للتهيئة بواسطة تجمع الرسائل المتماثلة. /// يجب أن تكون هناك رسائل كافية للتأكد من استمرار تقدم النسخة المتماثلة ، لتجنب حدوث حالة توقف تام. pub const messages_max_replica = messages_max: { var sum: usize = 0 ؛ sum + = config.io_depth_read + config.io_depth_write ؛ // I / O log sum + = config.clients_max ؛ // نسخة طبق الأصل مجموع + = 1 ؛ // نسخة طبق الأصل sum + = config.pipeline_max ؛ // نسخة طبق الأصل مجموع + = 1 ؛ // Replica.commit_prepare // النصاب المتماثل .do_view_change_from_all_replicas: // Replica.recovery_response_quorum يُستخدم فقط للاسترداد ولا يزيد الحد الأقصى. // جميع نصاب القانون الأخرى عبارة عن مجموعات بت. sum + = config.replicas_max ؛ sum + = config.connections_max ؛ // Connection.recv_message sum + = config.connections_max * config.connection_send _...

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow