
في ظل ظروف التحميل الكبير ، يزداد تعقيد تحسين قواعد البيانات العلائقية بأحجام كبيرة ، حيث أن شراء أجهزة أكثر قوة يعد مكلفًا ولا توجد طريقة لإيقاف تشغيل التطبيق ليلًا لعملية تغيير قاعدة بيانات طويلة وترحيل البيانات.
تحدثنا مؤخرًا عن كيفية
تحسين رمز PHP لتطبيقنا . الآن جاء دور المقالة حول كيفية تغيير الهيكل الداخلي لقاعدة البيانات الأكثر أهمية والأكثر تحميلًا في Badoo ، دون أن نفقد طلبًا واحدًا.
المريض
يعد المستخدمون DataBase ، أو UDB ، خدمة تبدأ أي طلب على Badoo. إنه يحل العديد من المشكلات: أولاً ، هو المستودع المركزي لبيانات المستخدم الرئيسية التي يحصل عليها التفويض (على سبيل المثال ، البريد الإلكتروني أو user_id أو facebook_id). بالإضافة إلى تخزين هذه البيانات ، توفر الخدمة تحكمًا فريدًا (بحيث لا يمكن لمستخدمين لهما نفس البريد الإلكتروني ، facebook_id ، وما إلى ذلك ، التسجيل في النظام). وتقدم نفس الخدمة معلومات حول أي من الآلاف من القطع تحتوي على جميع بيانات المستخدم الأخرى.
في نهاية عام 2018 ، يخزن UDB البيانات من أكثر من 800 مليون مستخدم ، والتي تشغل حوالي 1 تيرابايت من مساحة القرص. يتم تقديم كل هذا من خلال أزواج من خوادم MySQL الرئيسية في كل مركز من مراكز البيانات لدينا. في المجموع ، يعالجون أكثر من 140،000 طلب في الثانية.
سقوط UDB يعني عدم إمكانية الوصول إلى جميع Badoo ، لأن الرمز لن يكون قادرًا على العثور على القشرة التي تقع عليها بيانات المستخدم. لذلك ، يتم وضع مطالب ضخمة عليه من أجل الموثوقية والتوافر.
نظرًا لهذا النوع من الخصوصية ، فإن إجراء تغييرات في بنية التخزين يعد مكلفًا للغاية ، لذلك أخذنا تصميم UDB في 2013 على محمل الجد. ومع ذلك ، بمرور الوقت ، تتغير المتطلبات وكذلك ملفات تعريف التحميل. في محاولة لتكييف النظام مع المتطلبات الجديدة ومستويات الحمل ، تم إجراء العديد من التغييرات البسيطة والبسيطة ، لكن لسوء الحظ ، فإن هذه التغييرات بعيدة عن أن تكون الأكثر فعالية. وحدث اليوم ، بدلاً من الاختراق التالي أو شراء أجهزة باهظة الثمن ، كان من الأفضل إجراء التحسين على المستوى العالمي. كذلك سننظر في المراحل الرئيسية لهذا المسار.
تحسينات غير الغازية
أي تغييرات على بنية قاعدة بيانات كبيرة ومحملة مكلفة للغاية بسبب تعقيد عملية ترحيل البيانات. لذلك ، أولاً وقبل كل شيء ، يجب استنفاد جميع خيارات التحسين التي لا تؤثر على بنية البيانات ، ولكن تقتصر على التعليمات البرمجية واستعلامات SQL. ربما سيكون هذا كافياً لتأجيل مشكلة عبء العمل المفرط لبضع سنوات ، مما سيتيح لك القيام بشيء أكثر أهمية بالنسبة إلى العمل في هذا الوقت.
كلما فهمت نظامك بشكل أفضل ، كلما كان من الأسهل عليك إيجاد طرق لتحقيق مثل هذه التحسينات. تأكد من جمع كل المقاييس التي يمكن أن تساعدك. لا يتعلق هذا فقط بمقاييس النظام مثل استخدام وحدة المعالجة المركزية واستخدام ذاكرة الوصول العشوائي أو مقاييس قاعدة بيانات محددة ، بل يتعلق أيضًا بمقاييس مستوى التطبيق الخاصة بالتطبيق المرتبط بقاعدة بيانات محسّنة. كم عدد الطلبات في الثانية الواحدة لديها أنواع مختلفة من العمليات؟ ما هو وقت ردهم؟ ما هو حجم المدخلات والمخرجات؟ في هذه المقاييس ، يمكنك الحكم على نجاح التحسين. من غير المحتمل أنك تحتاج إلى تحسين يقلل استخدام وحدة المعالجة المركزية قليلاً على خادم قاعدة البيانات ، ولكن في نفس الوقت يزيد وقت الاستجابة للتطبيق الخاص بك بمقدار عشر مرات.

بعد أن بدأنا في جمع مقاييس إضافية على مستوى التطبيق لـ UDB ، تمكنا من فهم أفضل للعمليات المنجزة التي تنشئ 80٪ من الحمل وهي أول المرشحين للدراسة ، والتي تستخدم قليلاً أو لا تستخدم على الإطلاق.
أظهر تحليل مفصل للعملية الأكثر تكرارًا (استرجاع المستخدمين الذين يستوفون معايير معينة) أنه على الرغم من حقيقة أن جميع بيانات المستخدم المتاحة مطلوبة من قاعدة البيانات ، في الواقع ، يستخدم التطبيق في 95٪ من الحالات user_id فقط. فقط بفصل هذه الحالة إلى طريقة API منفصلة ، والتي تستخرج عمودًا واحدًا فقط من الجدول ، تمكنا من الاستفادة من استخدام فهرس التغطية وإزالة حوالي 5٪ من تحميل وحدة المعالجة المركزية من خادم قاعدة البيانات باستخدام هذا.
أظهر تحليل عملية متكررة أخرى أنه على الرغم من أنه يتم تنفيذها لكل طلب HTTP ، في الواقع ، فإن البيانات التي يسترجعها نادرة للغاية. لقد ترجمنا هذا الطلب إلى نموذج كسول.
الهدف الرئيسي من المقاييس في حالة مشروع التحسين هو تحسين فهم قاعدة البيانات الخاصة بك والعثور على الأجزاء الأكثر بدانة. لا معنى لقضاء الكثير من الوقت والجهد في تحسين الاستعلامات التي تشكل أقل من 1٪ من ملف تعريف التحميل الخاص بك. إذا لم يكن لديك مقاييس تسمح لك بفهم ملف تعريف التحميل الخاص بك ، فقم بجمعها. مع هذه التحسينات على جانب الكود ، تمكنا من إزالة حوالي 15 ٪ من استخدام وحدة المعالجة المركزية من 80 ٪ من قاعدة البيانات المستهلكة.
اختبار الأفكار
إذا كنت ترغب في تحسين قاعدة البيانات المحملة عن طريق تغيير هيكلها ، فيجب أن تبدأ بمراجعة أفكارك على منصة اختبار ، لأن التحسينات التي تبدو واعدة جدًا من الناحية النظرية قد لا يكون لها تأثير إيجابي في الممارسة (وأحيانًا يكون لها تأثير سلبي). ومن غير المرجح أن ترغب في معرفة ذلك فقط بعد ترحيل بيانات طويل على الإنتاج.
كلما كان تكوين الحامل الخاص بك أقرب إلى تكوين الإنتاج ، زادت موثوقية النتائج. نقطة مهمة هي ضمان الحمل الصحيح للحامل. يمكن أن يؤدي تشغيل عشوائي أو نفس الاستعلامات إلى نتائج خاطئة. الخيار الأفضل هو استخدام الطلبات الحقيقية من الإنتاج. بالنسبة إلى UDB ، قمنا بتسجيل الدخول من كل طلب قراءة لواجهة برمجة التطبيقات العاشرة (بما في ذلك المعلمات) في شكل مجرد سجل JSON في ملف. ليوم واحد ، جمعنا سجلًا بحجم 65 جيجابايت من 700 مليون طلب.
لم نختبر السجل ، مقارنةً بعدد طلبات القراءة ، فهو صغير جدًا ولا يؤثر على حملنا. ومع ذلك ، قد لا يكون هذا هو الحال في قضيتك. إذا كنت تريد تحميل منصة الاختبار مع طلبات الكتابة ، فسيتعين عليك جمع كل طلب ، لأن تخطي طلبات الكتابة يمكن أن يؤدي إلى أخطاء تناسق على منصة الاختبار.
والخطوة التالية هي أن تفقد السجل على الحامل بشكل صحيح. استخدمنا 400 من عمال PHP ، تم إطلاقهم من
السحابة النصية الخاصة بنا ، والتي قرأت السجل الذي تم جمعه من قائمة الانتظار السريعة وتنفيذ الطلبات بالتسلسل. في هذه الحالة ، يتم تعبئة قائمة الانتظار مع برنامج نصي آخر بسرعة محددة بدقة. لاختبار الأفكار ، استخدمنا سرعة x10 ، التي ضاعفتها حقيقة أننا جمعناها من الإنتاج فقط كل طلب العاشرة ، أعطت نفس كمية RPS كما في الإنتاج.

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

يمكن استخدام نفس الأدوات لإجراء اختبار الفشل: زيادة السرعة (وبالتالي RPS) حتى تبدأ القاعدة في الحامل في الانخفاض. هذا سيمنحك فهمًا واضحًا لمقدار تحميل قاعدة البيانات لديك.
بعد اختبار مخطط البيانات الجديد ، من المهم أيضًا إجراء اختبار تحكم على بنية قاعدة البيانات الأصلية. إذا كانت نتائجها وأدائها الحالي على الإنتاج مختلفين تمامًا ، فيجب عليك أولاً فهم الأسباب. ربما تم تكوين خادم الاختبار بشكل غير صحيح ولا يمكنك الوثوق في بيانات اختبار التحميل.
يجدر أيضًا التأكد من أن الكود الجديد يعمل بشكل صحيح. ليس من المنطقي اختبار أداء الاستعلامات التي لا تؤدي المهمة. سيتم خدمتك جيدًا من خلال اختبارات التكامل التي تحقق لمعرفة ما إذا كانت واجهات برمجة التطبيقات القديمة والجديدة تُرجع نفس القيم على نفس مكالمات واجهة برمجة التطبيقات.
بعد تلقي النتائج على جميع الأفكار ، يبقى فقط اختيار الخيارات مع أفضل توازن بين السعر والجودة وإدخال نظام جديد للإنتاج.
تغيير المخطط
أولاً وقبل كل شيء ، لاحظت أن تغيير نظام البيانات دون إيقاف تشغيل الخدمة دائمًا ما يكون صعبًا للغاية ومكلفة ومحفوفة بالمخاطر. لذلك ، إذا كان لديك الفرصة لإيقاف التطبيق الخاص بك أثناء تغيير الهيكل - فقط قم بذلك. في حالة UDB ، للأسف ، لم نتمكن من تحمل هذا.
العامل الثاني الذي يؤثر على تعقيد تغيير الدائرة هو المقياس المخطط للتغيير. إذا كانت جميع التغييرات المقترحة على الجداول لا تتجاوز مجرد تغيير (على سبيل المثال ، إضافة زوج من الفهارس أو الأعمدة الجديدة) ، فيمكنك تحسينها باستخدام عمليات نموذجية مثل
pt-online-schema-change و
gh-ost لـ MySQL أو عبد بديل يتبعه تغيير أماكنها .
في حالتنا ، تم عرض نتيجة ممتازة في التقسيم العمودي لجدول عملاق واحد أصغر من عشرة مع أعمدة وفهارس وبيانات أخرى بتنسيق مختلف. لم يعد هذا التحويل باستخدام أدوات نموذجية ممكنًا. ماذا تفعل؟
طبقنا الخوارزمية التالية:
- نحقق حالة حيث توجد المخططات القديمة والجديدة مع البيانات الحالية في وقت واحد. يتم التسجيل في كليهما ، وفي الوقت نفسه هناك ضمان لتناسق البيانات في كلا الإصدارين. سننظر في هذا البند بالتفصيل أدناه.
- قم بالتحول التدريجي للقراءة بأكملها إلى دائرة جديدة ، للتحكم في الحمل.
- قم بإيقاف تشغيل التسجيل في المخطط القديم وحذفه.
المزايا الرئيسية لهذا النهج:
- الأمان: هناك إمكانية للتراجع الفوري حتى المرحلة الأخيرة (ما عليك سوى تبديل القراءة إلى المخطط القديم ، إذا حدث خطأ ما) ؛
- التحكم الكامل في الحمل أثناء ترحيل البيانات ؛
- لا يلزم تبديل ثقيل للطاولة الكبيرة للدائرة القديمة.
ومع ذلك ، هناك أيضا عيوب:
- الحاجة إلى الاحتفاظ بإصداري المخططات على القرص أثناء عملية الترحيل (قد يكون ذلك مشكلة إذا كان لديك مساحة صغيرة وكان الجدول الذي يتم ترحيله كبيرًا جدًا) ؛
- الكثير من التعليمات البرمجية المؤقتة لدعم عملية الترحيل ، والتي سيتم قطعها عند الانتهاء ؛
- من الممكن غسل ذاكرة التخزين المؤقت عن طريق القراءة من نظامين بالتوازي ؛ كان هناك خوف من أن تتنافس الإصدارات القديمة والجديدة على ذاكرة الوصول العشوائي (RAM) ، مما قد يؤدي إلى تدهور الخدمة (في الواقع ، أدى هذا بالفعل إلى تحميل إضافي ، نظرًا لأن الترحيل تم خارج أوقات الذروة ، فإن هذا لم يخلق مشاكل بالنسبة لنا).
الصعوبة الرئيسية في هذه الخوارزمية هي النقطة الأولى. سننظر فيه بالتفصيل.
تغيير المزامنة
هجرة البيانات الساكنة ليست صعبة للغاية. ومع ذلك ، ماذا لو لم تتمكن من إيقاف التسجيل بالكامل أثناء ترحيل قاعدة البيانات؟
هناك عدة خيارات لتحقيق التزامن للمخطط الجديد: الترحيل باستخدام التسجيل المتداول وتسجيل السجل العاطل.
ترحيل لقطة بيانات متبوعة بإعادة تشغيل سجل التغييرات التالية
يتم تسجيل كل معاملة تحديث البيانات في جدول خاص من خلال المشغلات إما على مستوى التطبيق ، أو يتم استخدام binlog النسخ المتماثل كسجل. بعد أن يكون لديك مثل هذا السجل ، يمكنك فتح معاملة وترحيل لقطة بيانات ، مع تذكر الموضع في السجل. ثم يبقى أن نبدأ في تطبيق السجل الذي تم جمعه على النظام الجديد. وبالمثل ، على سبيل المثال ،
تعمل أداة النسخ الاحتياطي MySQL
Percona XtraBackup الشهيرة .
بعد أن يستوعب النظام الجديد السجل إلى السجل الحالي ، تبدأ المرحلة الأكثر أهمية: لا تزال بحاجة إلى إيقاف التسجيل مؤقتًا في النظام القديم لفترة قصيرة من الزمن ، والتأكد من تطبيق السجل المتاح بالكامل على المخطط الجديد ، مما يعني أن البيانات بين المخططات متسقة ، على مستوى التطبيق ، قم بتمكين التسجيل مرة واحدة في كلا المصدرين.
العيوب الرئيسية لهذا النهج هي أنك ستحتاج إلى تخزين سجل العمليات بطريقة أو بأخرى ، والذي يمكن أن يخلق بحد ذاته عبءًا في عملية التبديل المعقدة ، وكذلك في احتمال كسر السجل إذا كانت الدوائر غير متجانسة لسبب ما.
سجل العاطفي
الفكرة الرئيسية لهذا النهج هي البدء في الكتابة إلى المخطط الجديد بالتوازي مع الكتابة إلى النظام القديم قبل أن تتم مزامنة التغييرات بالكامل ، ثم إكمال ترحيل البيانات المتبقية. وبالمثل ، عادة ما يتم تعبئة أعمدة جديدة في جداول كبيرة.
يمكن تنفيذ التسجيل المتزامن على كل من مشغلات قواعد البيانات وفي الكود المصدري. أنصحك بالقيام بذلك بالضبط في الشفرة ، لأنه في أي حال سيكون عليك في النهاية كتابة التعليمات البرمجية التي ستكتب البيانات إلى المخطط الجديد ، وسيوفر لك تنفيذ الترحيل على جانب الكود مزيدًا من التحكم.
هناك نقطة مهمة يجب مراعاتها وهي أنه إلى أن تكتمل عملية الترحيل ، سيكون المخطط الجديد في حالة غير متسقة. لهذا السبب ، يكون السيناريو ممكنًا عندما يؤدي تحديث جدول جديد إلى انتهاك ثابت قاعدة البيانات (مفاتيح خارجية أو فهرس فريد) ، بينما من وجهة نظر المخطط الحالي ، تكون المعاملة صحيحة تمامًا ويجب تنفيذها.
يمكن أن يؤدي هذا الموقف إلى تراجع المعاملات الجيدة بسبب عملية الترحيل. تتمثل أسهل طريقة للتغلب على هذه المشكلة في إضافة معدل IGNORE إلى جميع طلبات كتابة البيانات إلى نظام جديد أو اعتراض التراجع عن هذه المعاملة وتشغيل الإصدار دون الكتابة إلى النظام الجديد.
خوارزمية التزامن من خلال التسجيل العاطفي في حالتنا هي كما يلي:
- يمكننا تمكين التسجيل في نظام جديد بالتوازي مع التسجيل في النظام القديم في وضع التوافق (تجاهل).
- نقوم بتشغيل برنامج نصي يتخطى تدريجياً المخطط الجديد ويلتقط بيانات غير متسقة. بعد ذلك ، يجب مزامنة البيانات الموجودة في كلا الجدولين ، لكن هذا غير دقيق بسبب التعارضات المحتملة في الفقرة 1.
- نبدأ مدقق تناسق البيانات - نفتح المعاملة ونقرأ السطور من المخططات الجديدة والقديمة بمقارنة مراسلاتها.
- إذا كانت هناك صراعات ، فإننا ننهي ونعود إلى الفقرة 3.
- بعد أن أظهر المدقق أن البيانات في كلا المخططين متزامنة ، فلا ينبغي أن يكون هناك أي اختلافات أخرى بين المخططات ، ما لم نفقد بعض الفوارق بالطبع. لذلك ، ننتظر بعض الوقت (على سبيل المثال ، أسبوع) ونجري فحص تحكم. إذا أظهر أن كل شيء على ما يرام ، عندها تُنجز المهمة بنجاح ويمكنك ترجمة القراءة.
النتائج
نتيجة لتغيير تنسيق البيانات ، تمكنا من تقليل حجم الجدول الرئيسي من 544 غيغابايت إلى 226 غيغابايت ، وبالتالي تقليل التحميل على القرص وزيادة كمية البيانات المفيدة التي تناسبها في ذاكرة الوصول العشوائي.
إجمالاً ، من بداية المشروع ، باستخدام جميع الأساليب الموضحة ، تمكنا من تقليل استخدام وحدة المعالجة المركزية لخادم قاعدة البيانات من 80 ٪ إلى 35 ٪ في ذروة حركة المرور. أظهرت نتائج اختبار الإجهاد اللاحق أنه عند معدل النمو الحالي للحمل ، يمكننا البقاء على الأجهزة الموجودة لمدة ثلاث سنوات أخرى على الأقل.
يؤدي تقسيم جدول كبير إلى عدة عناصر إلى تبسيط عملية إجراء مغيرات مستقبلية في قاعدة البيانات ، وكذلك تسريع بعض البرامج النصية التي جمعت البيانات من أجل استقصاء المعلومات بشكل ملحوظ.