من طلب تجمع للافراج. تقرير Yandex.Taxi

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


- مساء الخير! اسمي سيرجي ، أنا رئيس مجموعة الأتمتة في Yandex.Taxi. باختصار ، تتمثل المهمة الرئيسية لمجموعتنا في تقليل الوقت الذي يقضيه المطورون في حل مشكلاتهم. وهذا يشمل كل شيء من CI إلى عمليات التطوير والاختبار.

ماذا تنميتنا تفعل عندما يتم كتابة الكود؟

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



إن تغطية الاختبار ليست جيدة كما نود ، لكننا نحاول الحفاظ عليها عند مستوى كافٍ.

للاختبار ، نستخدم Google Test وإطار عمل مكتوب ذاتيًا ، والذي لا نختبر فقط الجزء "python" ، ولكن أيضًا الجزء "plus". يتيح لك إطار عملنا بدء الخدمات وتحميل البيانات إلى قاعدة البيانات قبل كل اختبار وتحديث ذاكرة التخزين المؤقت ومسح جميع الطلبات الخارجية وما إلى ذلك. إطار عمل فعال بما يسمح لك بتشغيل أي شيء كما تريد ، وقفل أي شيء حتى لا نحصل على أي قصد طلبات خارج.

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

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

وبطبيعة الحال ، نحن نختبر خدماتنا ومكوناتنا فقط ، لأنه لا ينبغي لنا اختبار الخدمات الخارجية ، بل نبتل كل شيء خارجيًا.

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

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

نقطة أخرى مهمة هي التحقق من النمط. إذا كان كل شيء بسيطًا بالنسبة لـ "الإيجابيات" ، فإننا نستخدم تنسيق clang ونتحقق مما إذا كان الرمز يطابقه أم لا ، ثم نستخدم Python ما يصل إلى أربعة محللين: Flake8 ، Pylint ، Mypy ، ويبدو أن autopep8.

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

بعد قيامك بإنشاء الرمز ، تم التحقق منه محليًا ، يمكنك القيام بطلب تجمع. يتم إنشاء طلبات التجمع على جيثب.



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

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

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

بالإضافة إلى الاختبار الروتيني ، يلزم أحيانًا اختبار الحمل. إذا كنت تقوم بتحرير التعليمات البرمجية التي تعد جزءًا من خدمة محملة بدرجة عالية ، فيمكننا إجراء اختبارات تحميل لذلك. في Python ، هناك عدد قليل من الخدمات المحملة بدرجة عالية ، بعضها أعاد كتابته في C ++ ، لكن مع ذلك ، لا تزال قائمة ، وفي بعض الأحيان يكون هناك مكان نحتاج إليه. اختبار الحمل يحدث من خلال نظام Lunapark. يستخدم Yandex.Tank ، إنه متاح مجانًا ، يمكنك تنزيله ومشاهدته. يسمح لك الخزان بإطلاق النار على بعض الخدمات ، وبناء الرسوم البيانية ، والقيام بطرق تحميل مختلفة وإظهار الحمل الذي كان موجودًا حاليًا على الخدمة والموارد المستخدمة. يكفي النقر على الزر من خلال TeamCity ، وسيتم جمع الحزمة ، وبعد ذلك سيكون من الممكن لفه عند الضرورة. أو ببساطة ملء وتشغيله يدويا هناك.



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

ما نلفت الانتباه في العملية:



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

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

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

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

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



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



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

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

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

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

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

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

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

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

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

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



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



عندما تتم كتابة الرمز ومراجعته واختباره ، ويتم تنفيذ جميع عمليات الترحيل ، يمكنك دمجها بأمان في GitHub ومتابعة إصدارها.

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

يتم كل هذا مع TeamCity.



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

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

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



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

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

لقد مرت التمهيدية ، كل شيء على ما يرام. وإذا حدث خطأ ما ، إذا كانت المشاكل فجأة؟



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



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

Source: https://habr.com/ru/post/ar439704/


All Articles