نكتب في PostgreSQL على ضوء فرعي: مضيف واحد ، يوم واحد ، 1 تيرابايت

تحدثت مؤخرًا عن كيفية استخدام الوصفات القياسية لزيادة أداء استعلامات "قراءة" SQL من قاعدة بيانات PostgreSQL. سنتحدث اليوم عن كيفية جعل التسجيل في قاعدة البيانات أكثر فاعلية دون استخدام أي "تقلبات" في التكوين - ببساطة عن طريق تنظيم تدفقات البيانات بشكل صحيح.


رقم 1. التقسيم


هناك مقال حول كيف ولماذا يستحق تنظيم التقسيم التطبيقي "نظريًا" بالفعل ، سنركز هنا على ممارسة استخدام بعض الأساليب في إطار خدمة المراقبة الخاصة بنا لمئات خوادم PostgreSQL .

"حالات الأيام الخوالي ..."


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

كانت الأوقات ملحمية تقريبًا ، وكانت متغيرات PostgreSQL 9.x مختلفة ذات صلة ، لذلك كان يجب إجراء جميع الأقسام "يدويًا" - من خلال وراثة الجدول ومشغلات التوجيه الديناميكي EXECUTE.


تحول الحل الناتج إلى كونه عالميًا بما يكفي ليتمكن من ترجمته إلى جميع الجداول:


PG10:


لكن التقسيم من خلال الوراثة لم يكن مناسبًا تاريخياً للعمل مع دفق كتابة نشط أو عدد كبير من الأقسام الفرعية. على سبيل المثال ، قد تتذكر أن الخوارزمية لاختيار القسم المطلوب لها تعقيد تربيعي ، وأنها تعمل مع أكثر من 100 قسم ، فأنت تفهم كيف ...

في PG10 ، تم تحسين هذا الموقف بشكل كبير من خلال تنفيذ الدعم للتقسيم الأصلي . لذلك ، حاولنا على الفور تطبيقه فورًا بعد ترحيل التخزين ، ولكن ...

كما اتضح بعد حفر الدليل ، الجدول المقسم أصلاً في هذا الإصدار:

  • لا يدعم وصف الفهارس
  • لا يدعم المحفزات عليه
  • لا يمكن أن تكون نفسها "سلالة"
  • لا تدعم INSERT ... ON CONFLICT
  • لا يمكن أن يفرخ القسم تلقائيًا

من المؤلم الحصول على أشعل النار على جبهتنا ، أدركنا أنه لا يمكننا الاستغناء عن تعديل التطبيق ، وقمنا بتأجيل المزيد من البحث لمدة ستة أشهر.

PG10: الفرصة الثانية


لذا ، بدأنا في حل المشاكل بدورها:

  1. نظرًا لأن العوامل المشغلة ON CONFLICTأصبحت ضرورية في بعض الأماكن ، فقد أنشأنا جدول وكيل وسيطًا لحلها .
  2. لقد تخلصنا من "التوجيه" في المحفزات - أي من EXECUTE.
  3. لقد أخرجوا جدول قالب منفصل مع جميع المؤشرات بحيث لم تكن موجودة حتى على جدول الوكيل.


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

قواميس النشر


كما هو الحال في أي نظام تحليلي ، كان لدينا أيضًا "حقائق" و "تخفيضات" (قواميس). في حالتنا ، بهذه الصفة ، على سبيل المثال ، كان نص "النموذج" من نفس النوع من الاستعلامات البطيئة أو نص الاستعلام نفسه.

تم تقسيم "الحقائق" الخاصة بنا بالأيام لفترة طويلة ، لذلك قمنا بحذف الأقسام القديمة بهدوء ، ولم يزعجونا (السجلات!). ولكن مع القواميس ،

تحولت المشاكل ... لا يعني أن هناك الكثير منها ، ولكن تبين أن حوالي 100 تيرابايت من "الحقائق" عبارة عن قاموس لـ 2.5 تيرابايت . لا يمكنك بسهولة حذف أي شيء من مثل هذه الطاولة ، ولن تضغط عليه في الوقت المناسب ، وأصبحت الكتابة إليه أبطأ تدريجيًا.

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

  • الكتابة / القراءة بشكل أسرع نظرًا لصغر حجم القسم
  • تستهلك ذاكرة أقل من خلال العمل مع فهارس أكثر إحكاما
  • تخزين بيانات أقل بسبب القدرة على إزالة عفا عليها الزمن بسرعة

نتيجة لمجموعة الإجراءات الكاملة ، انخفض حمل وحدة المعالجة المركزية بنسبة 30٪ تقريبًا ، وبنسبة قرص بنسبة 50٪ :


في الوقت نفسه ، واصلنا كتابة نفس الشيء بالضبط إلى قاعدة البيانات ، فقط مع حمل أقل.

# 2 تطوير قواعد البيانات وإعادة هيكلتها


لذا ، استقرنا على حقيقة أنه لكل يوم لدينا قسم خاص بنا مع البيانات. في الواقع ، هذا CHECK (dt = '2018-10-12'::date)هو مفتاح التقسيم وشرط أن يقع السجل في قسم معين.

نظرًا لأن جميع التقارير في خدمتنا يتم إنشاؤها وفقًا لتاريخ محدد ، فإن المؤشرات من "الأوقات غير المقسمة" كانت جميع أنواعها (الخادم ، التاريخ ، نموذج الخطة) ، (الخادم ، التاريخ ، عقدة الخطة) ، ( التاريخ ، فئة الخطأ ، الخادم) ، ...

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


اتجاه التحسين واضح - ما عليك سوى إزالة حقل التاريخ من جميع الفهارس على الجداول المقسمة. مع حجم التداول لدينا ، فإن المكسب يبلغ حوالي 1 تيرابايت / أسبوع !

والآن دعونا نلاحظ أن هذا التيرابايت لا يزال يتعين تدوينه بطريقة أو بأخرى. وهذا يعني أنه علينا أيضًا تحميل قرص أقل الآن ! في هذه الصورة ، فإن التأثير الذي تم الحصول عليه من التنظيف ، الذي خصصناه أسبوعًا له ، مرئي بوضوح:



# 3 "تشويه" حمولة الذروة


واحدة من المشاكل الكبيرة للأنظمة المحملة هي المزامنة المفرطة لبعض العمليات التي لا تتطلبها. في بعض الأحيان "لأنهم لم يلاحظوا" ، في بعض الأحيان "كان الأمر أسهل" ، ولكن عليك عاجلاً أم آجلاً التخلص منه.

نقرّب الصورة السابقة - ونرى أن القرص "يهتز" مع حمولة ذات سعة مزدوجة بين العينات المجاورة ، والتي من الواضح أنه لا يجب أن تكون "إحصائيًا" مع العديد من العمليات:



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

setInterval(sendToDB, interval)

تكمن المشكلة هنا على وجه التحديد في حقيقة أن جميع سلاسل الرسائل تبدأ في نفس الوقت تقريبًا ، لذا فإن أوقات الإرسال لها تتزامن دائمًا تقريبًا "إلى النقطة". عفوًا رقم 2 ...

لحسن الحظ ، يمكن تصحيح ذلك بسهولة عن طريق إضافة فترة زمنية "عشوائية" :

setInterval(sendToDB, interval * (1 + 0.1 * (Math.random() - 0.5)))

# 4. التخزين المؤقت ، يمكن أن تكون الحاجة


المشكلة الثالثة التقليدية للحمولة العالية هي نقص ذاكرة التخزين المؤقت حيث يمكن أن تكون.

على سبيل المثال ، جعلنا من الممكن تحليل انهيار عقد الخطة (كل هذه Seq Scan on users) ، لكننا نسينا على الفور أنها ، في الأساس ، هي نفسها ، قد نسيت.

لا ، بالطبع ، لا يتم كتابة أي شيء لقاعدة البيانات بشكل متكرر ، وهذا يقطع الزناد به INSERT ... ON CONFLICT DO NOTHING. لكن البيانات لا تصل إلى القاعدة على أي حال ، وعليك القيام بقراءة إضافية للتحقق من الصراع . عفوًا رقم 3 ...

الفرق في عدد السجلات المرسلة إلى قاعدة البيانات قبل / بعد تمكين التخزين المؤقت واضح:



وهذا انخفاض متزامن في حمل التخزين:



مجموع


تيرابايت في اليوم يبدو مخيفا فقط. إذا قمت بكل شيء بشكل صحيح ، فهذا فقط 2 ^ 40 بايت / 86400 ثانية = ~ 12.5 ميجابايت / ثانية ، والتي تم الاحتفاظ بها حتى مسامير IDE المكتبية. :)

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


All Articles