الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

تاريخ إنشاء فكونتاكتي موجود على ويكيبيديا، وقد رواه بافيل نفسه. يبدو أن الجميع يعرفها بالفعل. حول الأجزاء الداخلية والهندسة المعمارية والهيكلية للموقع على HighLoad++ Pavel قال لي مرة أخرى في عام 2010. لقد تسربت العديد من الخوادم منذ ذلك الحين، لذلك سنقوم بتحديث المعلومات: سنقوم بتشريحها، وإخراج الدواخل، ووزنها، وإلقاء نظرة على جهاز VK من وجهة نظر فنية.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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



لأكثر من أربع سنوات كنت أتعامل مع جميع أنواع المهام المتعلقة بالواجهة الخلفية.

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

خلال هذا الوقت، كان لي يد في العديد من مكونات الموقع. أريد أن أشارك هذه التجربة.

الهندسة المعمارية العامة

كل شيء كالعادة يبدأ بخادم أو مجموعة خوادم تقبل الطلبات.

الخادم الأمامي

يقبل الخادم الأمامي الطلبات عبر HTTPS وRTMP وWSS.

HTTPS - هذه طلبات لإصدارات الويب الرئيسية وإصدارات الويب المحمولة للموقع: vk.com وm.vk.com، والعملاء الرسميين وغير الرسميين الآخرين لواجهة برمجة التطبيقات (API) الخاصة بنا: عملاء الأجهزة المحمولة، والمراسلون. لدينا حفل استقبال RTMP-حركة البث المباشر مع خوادم أمامية منفصلة و WSS- اتصالات لتدفق API.

بالنسبة لـ HTTPS وWSS على الخوادم، فإن الأمر يستحق ذلك NGINX. بالنسبة لعمليات بث RTMP، قمنا مؤخرًا بالتبديل إلى الحل الخاص بنا kiveولكن الأمر خارج عن نطاق التقرير. من أجل التسامح مع الخطأ، تعلن هذه الخوادم عن عناوين IP مشتركة وتعمل في مجموعات بحيث لا يتم فقدان طلبات المستخدم في حالة وجود مشكلة على أحد الخوادم. بالنسبة إلى HTTPS وWSS، تقوم هذه الخوادم نفسها بتشفير حركة المرور من أجل المشاركة في تحميل وحدة المعالجة المركزية على عاتقها.

لن نتحدث أكثر عن WSS وRTMP، ولكن فقط عن طلبات HTTPS القياسية، والتي ترتبط عادةً بمشروع ويب.

الخلفية

عادة ما توجد خلف الواجهة خوادم خلفية. يقومون بمعالجة الطلبات التي يتلقاها الخادم الأمامي من العملاء.

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

توزيع الحمل

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

جمع المقاييس وإعادة التوازن

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

لدينا الآلاف من هذه الخوادم. يقوم كل خادم فعلي بتشغيل مجموعة kPHP لإعادة تدوير جميع النوى (لأن kPHP عبارة عن خيط واحد).

خادم المحتوى

CS أو Content Server عبارة عن وحدة تخزين. CS هو خادم يقوم بتخزين الملفات ويعالج أيضًا الملفات التي تم تحميلها وجميع أنواع المهام المتزامنة في الخلفية التي تحددها له واجهة الويب الرئيسية.

لدينا عشرات الآلاف من الخوادم الفعلية التي تقوم بتخزين الملفات. يحب المستخدمون تحميل الملفات، ونحن نحب تخزينها ومشاركتها. يتم إغلاق بعض هذه الخوادم بواسطة خوادم pu/pp خاصة.

بو / ص

إذا قمت بفتح علامة تبويب الشبكة في VK، فقد رأيت pu/pp.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

ما هو بو / ص؟ إذا قمنا بإغلاق خادم تلو الآخر، فهناك خياران لرفع وتنزيل ملف إلى الخادم الذي تم إغلاقه: مباشرة من خلال http://cs100500.userapi.com/path أو عبر الخادم الوسيط - http://pu.vk.com/c100500/path.

Pu هو الاسم التاريخي لتحميل الصور، وpp هو وكيل الصور. أي أن أحد الخوادم مخصص لتحميل الصور والآخر للتحميل. الآن لم يتم تحميل الصور فقط، ولكن تم الحفاظ على الاسم.

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

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

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

النقطة المثيرة للجدل هي أنه في هذه الحالة يحتفظ العميل بعدد أقل من الاتصالات. إذا كان هناك نفس عنوان IP لعدة أجهزة - مع نفس المضيف: pu.vk.com أو pp.vk.com، فإن متصفح العميل لديه حد لعدد الطلبات المتزامنة لمضيف واحد. ولكن في زمن انتشار HTTP/2 في كل مكان، أعتقد أن هذا لم يعد ذا أهمية كبيرة.

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

منذ وقت ليس ببعيد حصلنا على نسخة محسنة من الوكيل. الآن سأخبرك كيف تختلف عن تلك العادية ولماذا يعد ذلك ضروريًا.

تعرض جيد للشمس

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

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

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

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

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

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

ومن أجل مقاومة تدفقات الطلبات لنفس الملف، فإننا بالنسبة لنوع معين من المحتوى نقوم بتشغيل مخطط غبي ينشر الملفات عبر جميع "الشموس" المتاحة في المنطقة.

الشمس من الداخل

عكس الوكيل على nginx، وذاكرة التخزين المؤقت إما في ذاكرة الوصول العشوائي (RAM) أو على أقراص Optane/NVMe السريعة. مثال: http://sun4-2.userapi.com/c100500/path — رابط إلى “الشمس” التي تقع في المنطقة الرابعة مجموعة الخادم الثانية. يقوم بإغلاق ملف المسار الموجود فعليًا على الخادم 100500.

مخبأ

نضيف عقدة أخرى إلى مخططنا المعماري - بيئة التخزين المؤقت.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

هذا هو التخزين المؤقت لمحتوى الوسائط المتعددة، ولا يتم تخزين بيانات المستخدم هنا - فقط الموسيقى والفيديو والصور.

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

كيف يعمل؟

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

في الوقت نفسه، تأتي الشياطين - الخدمات في المناطق - من وقت لآخر إلى واجهة برمجة التطبيقات وتقول: "لدي ذاكرة تخزين مؤقت كذا وكذا، أعطني قائمة بالملفات الأكثر شيوعًا في منطقتي والتي لم تصلني بعد. " " تقدم واجهة برمجة التطبيقات (API) مجموعة من الملفات مرتبة حسب التصنيف، ويقوم البرنامج الخفي بتنزيلها ونقلها إلى المناطق وتسليم الملفات من هناك. هذا هو الفرق الأساسي بين pu/pp وSun من ذاكرات التخزين المؤقت: فهم يقدمون الملف من خلال أنفسهم على الفور، حتى لو لم يكن هذا الملف في ذاكرة التخزين المؤقت، وتقوم ذاكرة التخزين المؤقت أولاً بتنزيل الملف على نفسها، ثم تبدأ في إعادته.

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

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

نظرنا إلى الهندسة المعمارية العامة.

  • خوادم أمامية تقبل الطلبات.
  • الخلفيات التي تعالج الطلبات.
  • المخازن المغلقة بواسطة نوعين من الوكلاء.
  • مخابئ الإقليمية.

ما هو المفقود من هذا الرسم البياني؟ وبالطبع قواعد البيانات التي نقوم بتخزين البيانات فيها.

قواعد البيانات أو المحركات

نحن لا نسميها قواعد البيانات، ولكن المحركات - المحركات، لأننا ليس لدينا قواعد بيانات بالمعنى المقبول عموما.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

هذا إجراء ضروري.. حدث هذا لأنه في الفترة 2008-2009، عندما حقق VK نموًا هائلاً في شعبيته، كان المشروع يعمل بالكامل على MySQL وMemcache وكانت هناك مشاكل. أحب MySQL التعطل وإتلاف الملفات، وبعد ذلك لم يعد بإمكانه استردادها، وتدهور أداء Memcache تدريجيًا وكان لا بد من إعادة تشغيله.

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

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

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

أنواع المحركات

كتب الفريق عددًا لا بأس به من المحركات. فيما يلي بعض منها فقط: صديق، تلميحات، صورة، ipdb، رسائل، قوائم، سجلات، memcached، meowdb، أخبار، nostradamus، صورة، قوائم التشغيل، pmemcached، sandbox، بحث، تخزين، إعجابات، مهام، ...

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

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

مجموعات

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

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

لكي يعمل هذا، تحتاج إلى إضافة كيان آخر يقع بين الكود والمحركات - الوكيل.

وكيل RPC

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

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

تطبيقات محددة

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

بالنسبة لـ MySQL، والتي لا يزال لدينا هنا وهناك، نستخدم db-proxy، وبالنسبة لـ ClickHouse - كيتنهاوس.

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

مثال على مخطط TL الذي تعمل بموجبه جميع المحركات.

memcache.not_found                                = memcache.Value;
memcache.strvalue	value:string flags:int = memcache.Value;
memcache.addOrIncr key:string flags:int delay:int value:long = memcache.Value;

tasks.task
    fields_mask:#
    flags:int
    tag:%(Vector int)
    data:string
    id:fields_mask.0?long
    retries:fields_mask.1?int
    scheduled_time:fields_mask.2?int
    deadline:fields_mask.3?int
    = tasks.Task;
 
tasks.addTask type_name:string queue_id:%(Vector int) task:%tasks.Task = Long;

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

RPC عبر TL عبر TCP/UDP... UDP؟

لدينا بروتوكول RPC لتنفيذ طلبات المحرك الذي يعمل أعلى مخطط TL. كل هذا يعمل عبر اتصال TCP/UDP. TCP مفهوم، ولكن لماذا نحتاج UDP كثيرًا؟

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

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

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

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

تخزين البيانات المستمر

محركات تكتب binlogs. binlog هو ملف يُضاف في نهايته حدث لتغيير الحالة أو البيانات. في حلول مختلفة يطلق عليه بشكل مختلف: السجل الثنائي، WAL, AOF، ولكن المبدأ هو نفسه.

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

سأصف بسرعة مبدأ التشغيل. يوجد خادم يعمل عليه المحرك. يفتح سجلًا فارغًا جديدًا للكتابة ويكتب حدثًا لتغييره.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

يقرأ الموضع الذي كان في وقت إنشاء اللقطة وحجم السجل.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

النسخ المتماثل للبيانات

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

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

التأخر هنا صغير جدًا، ومن الممكن معرفة مقدار تأخر النسخة المتماثلة عن السيد.

مشاركة البيانات في وكيل RPC

كيف تعمل المشاركة؟ كيف يفهم الوكيل المجموعة التي يجب إرسالها إليها؟ الرمز لا يقول: "أرسل مقابل 15 قطعة!" - لا، يتم ذلك عن طريق الوكيل.

أبسط مخطط هو firstint - الرقم الأول في الطلب.

get(photo100_500) => 100 % N.

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

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

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

hash(photo100_500) => 3539886280 % N

نحصل أيضًا على التجزئة وباقي القسمة ورقم الجزء.

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

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

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

السجلات

نكتب السجلات بعدة طرق. الأكثر وضوحا وبسيطة هو إرسال سجلات إلى memcache.

ring-buffer: prefix.idx = line

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

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

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

المحرك قديم جدًا، وهناك مجموعات عمرها بالفعل 6-7 سنوات. هناك مشكلات نحاول حلها، على سبيل المثال، بدأنا في استخدام ClickHouse بشكل نشط لتخزين السجلات.

جمع السجلات في ClickHouse

يوضح هذا الرسم البياني كيف نسير في محركاتنا.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

  • استبدل بعض المحركات بـ ClickHouse؛
  • استبدل وكيل RPC، الذي لا يمكنه الوصول إلى ClickHouse، ببعض الحلول التي يمكنها ذلك، وعبر RPC.

المحرك بسيط - نستبدله بخادم أو مجموعة من الخوادم باستخدام ClickHouse.

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

في بعض الأحيان لا نريد تنفيذ مخطط RPC في الحلول غير القياسية، على سبيل المثال، في nginx. لذلك، لدى KittenHouse القدرة على تلقي السجلات عبر UDP.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

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

رصد

لدينا نوعان من السجلات: تلك التي يجمعها المسؤولون على خوادمهم وتلك التي يكتبها المطورون من التعليمات البرمجية. وهي تتوافق مع نوعين من المقاييس: النظام والمنتج.

مقاييس النظام

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

مقاييس المنتج

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

statlogsCountEvent   ( ‘stat_name’,            $key1, $key2, …)
statlogsUniqueCount ( ‘stat_name’, $uid,    $key1, $key2, …)
statlogsValuetEvent  ( ‘stat_name’, $value, $key1, $key2, …)

$stats = statlogsStatData($params)

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

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

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

إذا لزم الأمر، يمكننا الكتابة مباشرة إلى جامعي السجلات.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

لكن الكتابة من التعليمات البرمجية مباشرة إلى المجمعات، وتجاوز stas-daemom، تعد حلاً سيئًا قابلاً للتطوير لأنه يزيد الحمل على المجمع. الحل مناسب فقط إذا لم نتمكن لسبب ما من رفع برنامج memcache stats-daemon على الجهاز، أو إذا تعطل وذهبنا مباشرة.

بعد ذلك، يقوم جامعو السجلات بدمج الإحصائيات في com.meowDB - هذه هي قاعدة بياناتنا، والتي يمكنها أيضًا تخزين المقاييس.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

ثم يمكننا إجراء تحديدات ثنائية "قريبة من SQL" من الكود.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

تجربة

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

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

كان لدينا مخطط لكتابة السجلات من خلال KittenHouse.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

قررنا أضف "*House" آخر إلى الرسم التخطيطي، والتي ستتلقى المقاييس بالضبط بالتنسيق الذي يكتبها الكود الخاص بنا عبر UDP. ثم يقوم هذا المنزل بتحويلها إلى إدخالات، مثل جذوع الأشجار، وهو ما يفهمه KittenHouse. يمكنه تسليم هذه السجلات بشكل مثالي إلى ClickHouse، الذي يجب أن يكون قادرًا على قراءتها.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

تم استبدال المخطط الذي يحتوي على memcache وstats-daemon وقاعدة بيانات جامعي السجلات بهذا النظام.

الأسئلة الشائعة حول الهندسة المعمارية وعمل فكونتاكتي

تم استبدال المخطط الذي يحتوي على memcache وstats-daemon وقاعدة بيانات جامعي السجلات بهذا النظام.

  • هناك إرسالية من التعليمات البرمجية هنا، والتي تتم كتابتها محليًا في StatsHouse.
  • يكتب StatsHouse مقاييس UDP، التي تم تحويلها بالفعل إلى إدراجات SQL، إلى KittenHouse على دفعات.
  • يرسلهم KittenHouse إلى ClickHouse.
  • إذا أردنا قراءتها، فإننا نقرأها عبر تجاوز StatsHouse - مباشرة من ClickHouse باستخدام SQL العادي.

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

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

نشر

أولاً، دعونا نلقي نظرة على نشر PHP. نحن نتطور في طائرة نفاثة: يستخدم GitLab и TeamCity للنشر. يتم دمج فروع التطوير في الفرع الرئيسي، ومن الرئيسي للاختبار يتم دمجها في التدريج، ومن التدريج إلى الإنتاج.

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

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

بالنسبة لمحركاتنا، والتي هي أيضًا ثنائية بشكل أساسي، فإن المخطط مشابه جدًا:

  • فرع جيت الرئيسي؛
  • ثنائي في . DEB;
  • النسخة مكتوبة على binlog Copyfast؛
  • نسخها إلى الخوادم؛
  • يقوم الخادم بسحب ملف .dep جديد؛
  • دبكج -i;
  • إعادة إطلاق رشيقة إلى الإصدار الجديد.

الفرق هو أن ملفنا الثنائي معبأ في الأرشيف . DEB، وعند ضخها دبكج -i يتم وضعها على النظام. لماذا يتم نشر kPHP كملف ثنائي، ويتم نشر المحركات كـ dpkg؟ لقد حدث ذلك بهذه الطريقة. إنه يعمل - لا تلمسه.

روابط مفيدة:

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

المصدر: www.habr.com

إضافة تعليق