ضغط البيانات في Apache Ignite. تجربة سبيربنك

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

لذلك ، عندما يكون وضع الاستمرار قيد التشغيل ، ونتيجة لتغيير البيانات في ذاكرة التخزين المؤقت ، يبدأ Ignite الكتابة إلى القرص:

  1. محتوى ذاكرة التخزين المؤقت
  2. اكتب أمامك سجل (يشار إليها فيما بعد باسم WAL)

توجد آلية تسمى ضغط WAL لفترة طويلة لضغط WALs. قدم Apache Ignite 2.8 الذي تم إصداره مؤخرًا آليتين إضافيتين لضغط البيانات على القرص: ضغط صفحة القرص لضغط محتويات ذاكرة التخزين المؤقت وضغط لقطة صفحة WAL لضغط بعض سجلات WAL. المزيد عن كل هذه الآليات الثلاث أدناه.

ضغط صفحة القرص


كيف تعمل


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

يتم تخزين البيانات على القرص في النموذج التالي: يتم إنشاء ملف منفصل لكل قسم من كل مجموعة من مجموعات ذاكرة التخزين المؤقت ، في هذا الملف ، بترتيب تصاعدي من الفهرس ، تنتقل الصفحات واحدة تلو الأخرى. يحتوي معرف الصفحة الكاملة على معرف مجموعة ذاكرة التخزين المؤقت ورقم القسم وفهرس الصفحة في الملف. وبالتالي ، من خلال معرف الصفحة الكاملة ، يمكننا تحديد الملف والإزاحة بشكل فريد في كل صفحة. يمكنك قراءة المزيد عن ذاكرة الصفحة في مقالة على Apache Ignite Wiki: Ignite Persistent Store - تحت الغطاء .

تعمل آلية ضغط صفحة القرص ، كما يوحي الاسم ، على مستوى الصفحة. عند تشغيل هذه الآلية ، يتم العمل مع البيانات في ذاكرة الوصول العشوائي كما هي ، دون أي ضغط ، ولكن في وقت حفظ الصفحات من ذاكرة الوصول العشوائي إلى القرص ، يتم ضغطها.

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

  • لا يمكننا استخدام فهرس الصفحات لحساب الإزاحة التي يقع فيها في الملف.
  • , , . , . , .
  • , , , .

من أجل عدم حل هذه المشاكل على المستوى الخاص بها ، يستخدم ضغط صفحة القرص في Apache Ignite آلية نظام الملفات تسمى الملفات المتفرقة. الملف المتناثر هو ملف يمكن من خلاله تمييز بعض المناطق المليئة بالأصفار على أنها ثقوب. في هذه الحالة ، لن يتم تخصيص كتل نظام الملفات لتخزين هذه الثقوب ، ونتيجة لذلك يتم حفظ مساحة القرص.

من المنطقي أنه من أجل تحرير كتلة نظام الملفات ، يجب أن يكون حجم الثقب أكبر من أو يساوي كتلة نظام الملفات ، الأمر الذي يفرض قيودًا إضافية على حجم الصفحة في Apache Ignite: من أجل الضغط لإعطاء بعض التأثير على الأقل ، يجب أن يكون حجم الصفحة أكبر من حجم كتلة نظام الملفات . إذا كان حجم الصفحة يساوي حجم الكتلة ، فلن نتمكن مطلقًا من تحرير كتلة واحدة ، لأنه من أجل تحرير كتلة واحدة ، نحتاج إلى صفحة مضغوطة لاحتلال 0 بايت. إذا كان حجم الصفحة يساوي حجم كتلتين أو 4 كتل ، يمكننا بالفعل تحرير كتلة واحدة على الأقل إذا تم ضغط صفحتنا إلى 50٪ على الأقل أو 75٪ على التوالي.

وبالتالي ، فإن الوصف النهائي للآلية: عند كتابة صفحة على القرص ، تتم محاولة لضغط الصفحة. إذا كان حجم الصفحة المضغوطة يسمح بتحرير كتلة واحدة أو أكثر من نظام الملفات ، فإن الصفحة مكتوبة بشكل مضغوط ، يتم ثقب "مكان" بدلاً من الكتل التي تم تحريرها (يتم إجراء استدعاء نظام fallocate()بعلامة "ثقب المثقاب"). إذا كان حجم الصفحة المضغوطة لا يسمح بتحرير الكتل ، يتم حفظ الصفحة كما هي ، في شكل غير مضغوط. يتم اعتبار جميع إزاحة الصفحة أيضًا وبدون ضغط ، عن طريق ضرب فهرس الصفحة في حجم الصفحة. مطلوب أي نقل ذاتي للصفحات. إزاحة الصفحة ، وكذلك بدون ضغط ، تقع على حدود كتل نظام الملفات.



في التنفيذ الحالي ، لا يمكن لـ Ignite العمل إلا مع الملفات المتفرقة ضمن نظام التشغيل Linux ، لذا لا يمكن تمكين ضغط صفحة القرص إلا عند استخدام Ignite على نظام التشغيل هذا.

خوارزميات الضغط التي يمكن استخدامها لضغط صفحة القرص: ZSTD، LZ4، Snappy. بالإضافة إلى ذلك ، هناك وضع تشغيل (SKIP_GARBAGE) ، حيث يتم التخلص من المكان غير المستخدم في الصفحة فقط دون تطبيق الضغط على البيانات المتبقية ، مما يسمح بتقليل الحمل على وحدة المعالجة المركزية مقارنة بالخوارزميات المذكورة أعلاه.

تأثير الأداء


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

للقيام بذلك ، نحتاج إلى تذكر كيفية قراءة وكتابة الصفحات عند الوصول إليها:

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

وبالتالي ، فإن التأثير على عمليات القراءة:

  • (disk IO), .
  • (CPU), sparse . IO sparse ( sparse , , ).
  • (CPU), .
  • .
  • ( ):
  • (disk IO), .
  • (CPU, disk IO), sparse .
  • (CPU), .

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

كيفية تمكين وتكوين


كما ذكر أعلاه ، فإن الحد الأدنى من إصدار Apache Ignite يدعم ضغط صفحة القرص: 2.8 ويدعم فقط نظام تشغيل Linux. يتم التشغيل والضبط على النحو التالي:

  • يجب أن يحتوي مسار الفئة على وحدة ضغط اشتعال. بشكل افتراضي ، يتم وضعه في توزيع Apache Ignite في الدليل libs / الاختياري ولا يتم تضمينه في مسار الفئة. يمكنك ببساطة نقل الدليل مستوى واحد إلى libs ثم عند تشغيله من خلال ignite.sh سيتم تشغيله تلقائيًا.
  • Persistence ( DataRegionConfiguration.setPersistenceEnabled(true)).
  • ( DataStorageConfiguration.setPageSize() ).
  • , () ( CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

WAL compaction



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

تنقسم الإدخالات في WAL إلى منطقية ومادية. المنطقية هي المفاتيح والقيم نفسها. مادية - تعكس تغييرات الصفحة في مخزن الصفحات. إذا كانت السجلات المنطقية يمكن أن تكون مفيدة لبعض الحالات الأخرى ، فلا حاجة إلى السجلات المادية إلا لاستردادها في حالة السقوط والسجلات مطلوبة فقط من لحظة آخر نقطة تفتيش ناجحة. لن نتطرق هنا إلى التفاصيل ونشرح سبب نجاح هذه الطريقة ، ولكن يمكن لأي شخص مهتم أن يشير إلى المقالة المذكورة بالفعل على Apache Ignite Wiki: Ignite Persistent Store - تحت غطاء المحرك .

غالبًا ما يمثل أحد السجلات المنطقية العديد من السجلات المادية. أي ، على سبيل المثال ، تؤثر عملية وضع ذاكرة تخزين مؤقت واحدة على عدة صفحات في ذاكرة الصفحة (صفحة تحتوي على البيانات نفسها ، وصفحات بها فهارس ، وصفحات بقوائم مجانية). في بعض الاختبارات الاصطناعية ، اتضح أن السجلات المادية تشغل ما يصل إلى 90 ٪ من ملف WAL. علاوة على ذلك ، يحتاجون إلى وقت قصير جدًا (بشكل افتراضي ، الفاصل الزمني بين نقاط التفتيش هو 3 دقائق). سيكون من المنطقي التخلص من هذه البيانات بعد فقدان أهميتها. هذا هو بالضبط ما تقوم به آلية ضغط WAL ، ويتخلص من السجلات المادية ويضغط السجلات المنطقية المتبقية باستخدام ملف zip ، بينما ينخفض ​​حجم الملف بشكل كبير جدًا (أحيانًا عشرات المرات).

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



تأثير الأداء


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

كيفية تمكين وتكوين


يمكنك تمكين ضغط WAL باستخدام الخاصية WalCompactionEnabledc DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). أيضًا ، باستخدام طريقة DataStorageConfiguration.setWalCompactionLevel () ، يمكنك تعيين نسبة الضغط إذا لم تكن راضيًا عن القيمة الافتراضية (BEST_SPEED).

ضغط لقطة صفحة WAL


كيف تعمل


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

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

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

بالنسبة لضغط صفحة القرص لضغط لقطة صفحة WAL ، يمكن استخدام خوارزميات الضغط ZSTD و LZ4 و Snappy وكذلك وضع SKIP_GARBAGE.

تأثير الأداء


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

يؤثر هذا على تدفق البيانات على النحو التالي: نحصل على تأثير سلبي (CPU) بسبب الحاجة إلى ضغط الصفحة في كل مرة قبل الكتابة إلى القرص وتأثير إيجابي (القرص IO) عن طريق تقليل كمية البيانات التي تتم كتابتها. وفقًا لذلك ، كل شيء بسيط هنا ، إذا كان أداء النظام يعتمد على وحدة المعالجة المركزية ، فإننا نحصل على القليل من التدهور ، إذا حصلنا على زيادة في القرص I / O.

بشكل غير مباشر ، فإن تقليل حجم WALs يؤثر أيضًا (بشكل إيجابي) على التدفقات التي تسقط مقاطع WAL في الأرشيف وتدفق ضغط WAL.

أظهرت اختبارات الأداء الحقيقية في بيئتنا على البيانات الاصطناعية زيادة طفيفة (زادت الإنتاجية بنسبة 10٪ -15٪ ، وانخفض زمن الوصول بنسبة 10٪ -15٪).

كيفية تمكين وتكوين


الحد الأدنى للإصدار Apache Ignite هو 2.8. يتم التشغيل والضبط على النحو التالي:

  • يجب أن يحتوي مسار الفئة على وحدة ضغط اشتعال. بشكل افتراضي ، يتم وضعه في توزيع Apache Ignite في الدليل libs / الاختياري ولا يتم تضمينه في مسار الفئة. يمكنك ببساطة نقل الدليل مستوى واحد إلى libs ثم عند تشغيله من خلال ignite.sh سيتم تشغيله تلقائيًا.
  • يجب تمكين المثابرة (ممكن من خلال DataRegionConfiguration.setPersistenceEnabled(true)).
  • DataStorageConfiguration.setWalPageCompression(), ( DISABLED).
  • DataStorageConfiguration.setWalPageCompression(), javadoc .


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

All Articles