كيف نضمن نمو CityMobile

صورة

اسمي إيفان ، وأنا رئيس تطوير الخادم في Citimobil. اليوم سأتحدث عن ماهية تطوير الخادم هذا ، وما هي المشاكل التي واجهناها وكيف نخطط للتطوير.

بداية النمو


قليل من الناس يعرفون أن CityMobile كانت موجودة منذ فترة طويلة ، 13 عامًا. ذات مرة كانت شركة صغيرة تعمل فقط في موسكو. كان هناك عدد قليل جدًا من المطورين ، وكانوا يعرفون جيدًا كيف يعمل النظام - لأنهم هم أنفسهم من أنشأوه. بدأ سوق سيارات الأجرة في التطور آنذاك ، وكانت الأحمال بنسًا واحدًا. لم يكن لدينا حتى مهمة توفير التسامح مع الخطأ والتحجيم.

في عام 2018 ، استثمرت Mail.Ru Group في CityMobile ، وبدأنا في النمو بسرعة. لم يكن هناك وقت لإعادة كتابة المنصة ، أو على الأقل إعادة هيكلة كبيرة ، كان من الضروري تطوير قدراتها الوظيفية من أجل اللحاق بمنافسنا الرئيسي ، وتوظيف الأشخاص بسرعة. عندما انضممت إلى الشركة ، شارك 20 مطورًا فقط في الواجهة الخلفية ، وكان جميعهم تقريبًا قيد المحاكمة. لذلك ، قررنا "قطف الثمار المنخفضة": لإجراء تغييرات بسيطة تعطي نتيجة هائلة.

في ذلك الوقت ، كان لدينا متراصة في PHP وثلاث خدمات على Go ، بالإضافة إلى قاعدة رئيسية واحدة في MySQL التي كان المترابط يصل إليها (تم استخدام الخدمات كمستودعات لـ Redis و EasticSearch). وبالتدريج ، مع زيادة الحمل ، بدأت طلبات النظام الثقيلة في إبطاء القاعدة.

ما الذي يمكن عمله بهذا؟

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

في هذا النموذج ، عمل النظام لبعض الوقت ، ثم بدأت الوظائف تظهر أكثر تطلبًا على الأجهزة. كان هناك المزيد والمزيد من الطلبات مع كل أسبوع: لم يمر حتى أسبوع بدون رقم قياسي جديد. بالإضافة إلى ذلك ، وضعنا قنبلة موقوتة تحت نظامنا. في السابق ، كان لدينا نقطة واحدة فقط من الفشل - القاعدة الرئيسية لـ MySQL ، ولكن مع إضافة عبد كانت هناك نقطتان من هذه النقاط: السيد والعبد. سيؤدي فشل أي من هذه الآلات إلى فشل كامل للنظام.

للحماية من ذلك ، بدأنا في استخدام وكيل محلي لأداء فحص العبيد. هذا سمح لنا باستخدام العديد من العبيد دون تغيير الكود. قدمنا ​​فحوصات تلقائية منتظمة لحالة كل عبد ومقاييسه العامة:

  • لا ؛
  • تأخر الرقيق
  • توفر المنفذ ؛
  • عدد الأقفال ، إلخ.

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

مزيد من النمو


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

وجدنا حلاً ناجحًا - تارانتول. كان من الصعب إعادة كتابة النظام لذلك ، لذلك قمنا بحل المشكلة بشكل مختلف: باستخدام أداة النسخ المتماثل mysql-tarantoolإجراء نسخ متماثل لبعض الجداول من MySQL إلى Tarantool. جميع طلبات القراءة التي نشأت خلال النقص في السيارات ، بدأنا بالبث في تارانتول ومنذ ذلك الحين لم نعد نشعر بالقلق من العواصف الرعدية والأعاصير! وقمنا بحل المشكلة مع نقطة الفشل أسهل: قمنا على الفور بتثبيت العديد من النسخ المتماثلة التي نصل إليها من خلال التحقق الصحي من خلال HAProxy. يتم نسخ كل مثيل تارانتول بواسطة وحدة نسخ منفصلة. كمكافأة سارة ، قمنا أيضًا بحل مشكلة تأخر العبيد في هذا القسم من التعليمات البرمجية: النسخ المتماثل من MySQL إلى Tarantool يعمل بشكل أسرع بكثير من MySQL إلى MySQL.

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

أولاً ، في ذلك الوقت كنا قد بدأنا بالفعل في إنشاء خدمات جديدة بنشاط (على سبيل المثال ، مكافحة الاحتيال ، التي كتب عنها زملائي بالفعل ). علاوة على ذلك ، تتطلب الخدمات على الفور قابلية التخزين. بالنسبة لـ Redis ، بدأنا في استخدام مجموعة Redis فقط ، وبالنسبة لـ Tarantool - Vshard. حيث نستخدم MySQL ، بدأنا في استخدام Vitess لمنطق جديد . قواعد البيانات هذه قابلة للتجزئة على الفور ، لذلك لا توجد مشاكل في التسجيل تقريبًا ، وإذا ظهرت فجأة ، فسيكون من السهل حلها عن طريق إضافة خوادم. الآن نستخدم Vitess فقط للخدمات غير المهمة ودراسة المزالق ، ولكن في المستقبل ، سيكون على جميع قواعد بيانات MySQL.

ثانيًا ، نظرًا لأنه كان من الصعب والطويل تنفيذ Vitess للمنطق الحالي ، فقد ذهبنا بطريقة أبسط ، وإن كانت أقل عالمية: بدأنا في توزيع القاعدة الرئيسية عبر خوادم مختلفة ، جدولًا تلو الآخر. لقد كنا محظوظين للغاية: فقد اتضح أن الحمل الرئيسي على السجل يتم إنشاؤه بواسطة الجداول غير المهمة للوظيفة الرئيسية. وعندما نصنع مثل هذه الجداول ، فإننا لا نخلق نقاطًا إضافية لفشل الأعمال. كان العدو الرئيسي بالنسبة لنا هو الترابط القوي للجداول في الكود باستخدام JOINs (كان هناك JOINs و 50-60 جداول لكل منها). نقطعهم بلا رحمة.

حان الوقت الآن لاستدعاء نمطين مهمين جدًا لتصميم أنظمة التحميل العالي:

  • Graceful degradation. , - . , , , , .. , .
  • Circuit breaker. , . , , , . ? ( - graceful degradation). , FPM- , . - ( ) , . , - , ( ).

لذا ، بدأنا في التوسع على الأقل ، ولكن لا تزال هناك نقاط فشل.

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

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

ماذا بعد؟

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

كيف نتطور أكثر؟


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

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

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

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

استمر في تقسيم القواعد. سننتقل إلى Vitess في جميع الخدمات.

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

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

All Articles