تطور نهج نشر التعليمات البرمجية في Reddit

الصورة

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

"من المهم أن تتبع اتجاه تطورك لكي تتمكن من توجيهه في الوقت المناسب إلى اتجاه مفيد."

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

تطور النظام الذي يوفر كل هذا على مر السنين. دعونا نرى ما تغير فيه كل هذا الوقت ، وما بقي دون تغيير.

بداية القصة: عمليات النشر المستقرة والمتكررة (2007-2010)


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

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

الصورة

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

#            `make -C /home/reddit/reddit static` `rsync /home/reddit/reddit/static public:/var/www/` #    app-        #    ,   foreach $h (@hostlist) { `git push $h:/home/reddit/reddit master` `ssh $h make -C /home/reddit/reddit` `ssh $h /bin/restart-reddit.sh` } 

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

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

وصل فوجنا (2011)


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

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

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

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

الصورة

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

نشر أداة إعادة التدوير (2012)


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

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

لحل مشكلة عمليات إعادة التشغيل المتتالية ، قمنا بتعديل قائمة المضيفين قبل النشر. قلل الخلط من المخاطر وسمح بتسريع العملية.

الصورة

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

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

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

 sudo /opt/reddit/deploy.py fetch reddit sudo /opt/reddit/deploy.py deploy reddit f3bbbd66a6 sudo /opt/reddit/deploy.py fetch-names sudo /opt/reddit/deploy.py restart all 

تجدر الإشارة بشكل خاص إلى أسماء الجلب: هذه التعليمات فريدة من نوعها لـ r2.

أوتوسكالينج (2013)


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

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

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

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

لذلك عملت لفترة.

عدد كبير جدًا من الخوادم (2014)


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

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

الصورة

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

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

الصورة

الكثير من الناس (2015)


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

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

العديد من الخدمات (اثنتين) (2015 أيضًا)


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

25 خدمة (2016)


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

وسادة هوائية (2017)


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

استخدمت عملية Gunicorn الرئيسية نفس نموذج uWSGI ، وإعادة تحميل جميع العمال في نفس الوقت. كانت عمليات العامل الجديد غير قادرة على خدمة الطلبات حتى تم تحميلها بالكامل. تراوح وقت إطلاق monolith من 10 إلى 30 ثانية. هذا يعني أنه خلال هذه الفترة الزمنية لن نتمكن من معالجة الطلبات على الإطلاق. لإيجاد طريقة للخروج من هذا الموقف ، استبدلنا عملية gunicorn الرئيسية بمدير عمل Stripe's Einhorn ، مع الحفاظ على حزمة Gunicorn HTTP وحاوية WSGI . أثناء إعادة التشغيل ، يقوم Einhorn بإنشاء عامل جديد ، وينتظر حتى يصبح جاهزًا ، ويتخلص من عامل قديم واحد ، ويكرر العملية حتى يكتمل التحديث. هذا يخلق وسادة هوائية ويسمح لنا بالحفاظ على عرض النطاق الترددي عند مستوى أثناء عمليات النشر.

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

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

إذا نظرنا إلى الوراء


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

المستقبل


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

الصورة

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


All Articles