تاريخ فكونتاكتي موجود على ويكيبيديا ، وقد أخبره بافيل نفسه. يبدو أن الجميع يعرفها بالفعل.
تحدث بافل عن الدواخل ، والهندسة المعمارية وتصميم الموقع على HighLoad ++
مرة أخرى في عام 2010 . تسربت الكثير من الخوادم منذ ذلك الحين ، لذلك سنقوم بتحديث المعلومات: نقوم بتشريح ، وسحب الدواخل ، والوزن - نحن ننظر إلى جهاز VK من وجهة نظر تقنية.
أليكسي أكولوفيتش (
AterCattus ) هو مطور خلفية في فريق فكونتاكتي. نص هذا التقرير هو إجابة جماعية للأسئلة المتداولة حول تشغيل النظام الأساسي والبنية التحتية والخوادم والتفاعل بينهما ، ولكن ليس حول التطوير ، وتحديداً
حول الأجهزة . بشكل منفصل - حول قواعد البيانات وما VK في مكانها ، حول جمع السجلات ومراقبة المشروع بأكمله ككل. التفاصيل تحت خفض.
منذ أكثر من أربع سنوات ، كنت أقوم بجميع أنواع المهام المتعلقة بالواجهة الخلفية.
- قم بتنزيل وتخزين ومعالجة وتوزيع الوسائط: الفيديو ، البث المباشر ، الصوت ، الصور ، المستندات.
- بنية أساسية ، منصة ، مراقبة مطور ، سجلات ، مخابئ إقليمية ، CDN ، بروتوكول RPC خاص.
- التكامل مع الخدمات الخارجية: الدفع عبر البريد ، تحليل الروابط الخارجية ، تغذية RSS.
- ساعد الزملاء في العديد من القضايا ، للحصول على الإجابات التي يجب عليك أن تغوص في رمز غير معروف.
خلال هذا الوقت ، كان لي يد في العديد من مكونات الموقع. أريد أن أشارك هذه التجربة.
العمارة العامة
كل شيء ، كالعادة ، يبدأ بخادم أو مجموعة من الخوادم التي تقبل الطلبات.
الخادم الأمامي
يقبل الخادم الأمامي الطلبات عبر HTTPS و RTMP و WSS.
HTTPS هي طلبات لإصدارات الويب الرئيسية والجوّالة للموقع: vk.com و m.vk.com ، وغيرهما من العملاء الرسميين وغير الرسميين لواجهة برمجة التطبيقات لدينا: عملاء الجوال ، والمراسلون الفوريون. لدينا حركة مرور
RTMP للبث المباشر مع خوادم أمامية منفصلة واتصالات
WSS لواجهة البث المباشر.
بالنسبة إلى HTTPS و WSS ،
يتم تثبيت
nginx على الخوادم. بالنسبة إلى عمليات البث RTMP ، انتقلنا مؤخرًا إلى حل
kive الخاص
بنا ، ولكنه يتجاوز نطاق التقرير. للتسامح مع الأخطاء ، تعلن هذه الخوادم عن عناوين IP مشتركة وتعمل كمجموعات بحيث في حالة وجود مشكلة على أحد الخوادم ، لا تضيع طلبات المستخدم. بالنسبة إلى HTTPS و WSS ، تقوم نفس الخوادم بتشفير حركة المرور للمشاركة في تحميل وحدة المعالجة المركزية على نفسها.
علاوة على ذلك ، لن نتحدث عن WSS و RTMP ، ولكن فقط عن طلبات HTTPS القياسية ، والتي ترتبط عادةً بمشروع ويب.
الخلفية
وراء الجبهة وعادة ما تكون خوادم الخلفية. يعالجون الطلبات التي يتلقاها الخادم الأمامي من العملاء.
هذه
خوادم kPHP تقوم بتشغيل البرنامج الخفي HTTP لأن HTTPS قد تم فك تشفيره بالفعل. kPHP هو خادم يعمل وفقًا
لطراز prefork : فهو يبدأ العملية الرئيسية ومجموعة من العمليات الفرعية ويمرر مآخذ الاستماع إليهم ويقومون بمعالجة طلباتهم. في الوقت نفسه ، لا تتم إعادة تشغيل العمليات بين كل طلب من المستخدم ، ولكن ببساطة إعادة تعيين حالتها إلى حالة القيمة الصفرية الأولية - طلب حسب الطلب ، بدلاً من إعادة التشغيل.
تقاسم الحمل
ليست جميع أعمالنا الخلفية مجموعة كبيرة من الآلات التي يمكنها التعامل مع أي طلب.
نقسمهم إلى مجموعات منفصلة : عامة ، متحركة ، api ، فيديو ، انطلاق ... لن تؤثر المشكلة على مجموعة منفصلة من الأجهزة على أي شخص آخر. في حالة وجود مشاكل في الفيديو ، فإن المستخدم الذي يستمع إلى الموسيقى لا يعرف حتى هذه المشكلات. أي الواجهة الخلفية لإرسال الطلب إلى يتم حلها بواسطة nginx على المقدمة في التكوين.
جمع القياسات وإعادة التوازن
لفهم عدد السيارات التي تحتاجها في كل مجموعة ، نحن
لا نعتمد على QPS . خلفية مختلفة ، لديهم طلبات مختلفة ، كل طلب لديه تعقيد حساب QPS مختلفة. لذلك ، نحن نستخدم
مفهوم الحمل على الخادم ككل - على وحدة المعالجة المركزية و perf .
لدينا الآلاف من هذه الخوادم. تعمل مجموعة kPHP على كل خادم فعلي للاستفادة من جميع النواة (لأن kPHP مترابط واحد).
خادم المحتوى
CS أو خادم المحتوى هو التخزين . 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 سابقًا ،
بتسريح عدد كبير من موظفي Sun. يمكننا القول أنه في هذه اللحظة لم تعد الشركة موجودة. عند اختيار اسم للنظام الجديد ، قرر مدراءنا تكريم هذه الشركة واحترامها ، واسمه نظام Sun الجديد. بيننا ، نسميها ببساطة "أشعة الشمس".

كان Pp بعض المشاكل.
IP واحد لكل مجموعة هو ذاكرة التخزين المؤقت غير فعالة . العديد من الخوادم الفعلية لها عنوان IP مشترك ، وليس هناك طريقة للتحكم في الخادم الذي سيأتي الطلب إليه. لذلك ، إذا جاء مستخدمون مختلفون لنفس الملف ، ثم إذا كان هناك ذاكرة تخزين مؤقت على هذه الخوادم ، فإن الملف يستقر في ذاكرة التخزين المؤقت لكل خادم. هذا مخطط غير فعال للغاية ، لكن لا يمكن فعل شيء.
نتيجةً لذلك ،
لا يمكننا مشاركة المحتوى ، لأنه لا يمكننا تحديد خادم معين لهذه المجموعة - لديهم عنوان IP مشترك. أيضًا ، لبعض الأسباب الداخلية ،
لم تتح لنا الفرصة لوضع مثل هذه الخوادم في المناطق . وقفت فقط في سان بطرسبرج.
مع الشموس ، قمنا بتغيير نظام الاختيار. الآن لدينا
التوجيه anycast :
التوجيه الديناميكي ، anycast ، الشيطان الاختيار الذاتي. كل خادم لديه IP الفردية الخاصة به ، ولكن في الوقت نفسه شبكة فرعية مشتركة. تم تكوين كل شيء بطريقة بحيث في حالة فقدان خادم واحد ، تنتشر حركة المرور إلى خوادم أخرى من نفس المجموعة تلقائيًا. من الممكن الآن تحديد خادم معين ،
ولا توجد ذاكرة تخزين مؤقت مفرطة ، ولا تتأثر الموثوقية.
دعم الوزن . الآن يمكننا أن نضع السيارات ذات السعات المختلفة حسب الضرورة ، وأيضًا في حالة حدوث مشاكل مؤقتة ، قم بتغيير أوزان "شمس" العاملة لتقليل الحمل عليها حتى "تستريح" وتعمل مرة أخرى.
المشاركة بواسطة معرف المحتوى . الأمر المضحك في المشاركة هو أننا عادةً ما نقوم بمشاركة المحتوى بحيث يتبع المستخدمون المختلفون نفس الملف من خلال نفس "الشمس" بحيث يكون لديهم ذاكرة تخزين مؤقت مشتركة.
أطلقنا مؤخرًا تطبيق Clover. هذا اختبار بث مباشر عبر الإنترنت حيث يقوم مقدم العرض بطرح الأسئلة ويستجيب المستخدمون في الوقت الفعلي عن طريق اختيار الخيارات. التطبيق يحتوي على دردشة حيث يمكن للمستخدمين الفيضانات.
يمكن لأكثر من 100 ألف شخص الاتصال في وقت واحد للبث. انهم جميعا كتابة الرسائل التي يتم إرسالها إلى جميع المشاركين ، جنبا إلى جنب مع الرسالة يأتي الرمزية آخر. إذا كان 100 ألف شخص يأتون من أجل صورة رمزية واحدة في "شمس" واحدة ، فيمكنها أحيانًا التمرير فوق سحابة.
لمقاومة رشقات من الطلبات من نفس الملف ، فإننا نضمن نظامًا غبيًا ينشر الملفات عبر جميع "suns" المتوفرة في المنطقة ، وذلك من أجل نوع ما من المحتوى.
الشمس في الداخل
عكس الوكيل إلى nginx أو ذاكرة التخزين المؤقت في الأقراص RAM أو Optane / NVMe السريعة. مثال:
http://sun4-2.userapi.com/c100500/path
- رابط إلى "الشمس" ، والتي هي في المنطقة الرابعة ، مجموعة الخوادم الثانية. يتم إغلاق ملف المسار ، والذي يقع فعليًا على الخادم 100500.
مخبأ
نضيف عقدة أخرى إلى مخططنا المعماري - بيئة التخزين المؤقت.

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

هذا هو التخزين المؤقت لمحتوى الوسائط المتعددة ، لا يتم تخزين بيانات المستخدم هنا - فقط الموسيقى والفيديو والصور.
لتحديد منطقة المستخدم ، نقوم
بتجميع بادئات شبكة 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 محركًا جديدًا. لم لا.
لدينا محرك منفصل
memcached ، والذي يشبه المحرك المعتاد ، ولكن مع مجموعة من الكعك ، والتي لا تبطئ. لا ClickHouse ، ولكن يعمل أيضا. هناك
pmemcached بشكل منفصل - وهو
memcached المستمر الذي يمكن تخزين البيانات أيضا على القرص ، وأكثر من ذلك يحصل في ذاكرة الوصول العشوائي حتى لا تفقد البيانات عند إعادة التشغيل. هناك محركات مختلفة للمهام الفردية: قوائم الانتظار ، والقوائم ، والمجموعات - كل ما هو مطلوب في مشروعنا.
مجموعات
من وجهة نظر الكود ، ليست هناك حاجة لتخيل المحركات أو قواعد البيانات كعمليات أو كيانات أو حالات معينة. يعمل الرمز بشكل خاص مع الكتل ، مع مجموعات من المحركات -
نوع واحد لكل كتلة . دعنا نقول أن هناك كتلة memcached - انها مجرد مجموعة من الآلات.
لا يحتاج الرمز إلى معرفة الموقع الفعلي وحجم وعدد الخوادم. يذهب إلى الكتلة من قبل بعض المعرف.
لكي ينجح هذا ، تحتاج إلى إضافة كيان آخر ، والذي يقع بين الرمز والمحركات -
الوكيل .
وكيل RPC
وكيل -
حافلة متصلة ، والتي تدير الموقع بأكمله تقريبا. في الوقت نفسه ،
لا يوجد لدينا اكتشاف للخدمة - بدلاً من ذلك ، هناك تهيئة لهذا الوكيل ، والتي تعرف موقع جميع المجموعات وكل شظايا هذه المجموعة. يتم ذلك عن طريق مدراء.
لا يهتم المبرمجون عمومًا بالمقدار وأين وما يكلفه - فهم يذهبون إلى المجموعة. هذا يتيح لنا الكثير. عند استلام الطلب ، يعيد الوكيل توجيه الطلب ومعرفة أين - يحدد ذلك.

في الوقت نفسه ، الوكيل هو نقطة حماية ضد فشل الخدمة. إذا تباطأ أي محرك أو تعطل ، فإن الوكيل يفهم ذلك ويستجيب لذلك من جانب العميل. يسمح لك هذا بإزالة المهلة - لا ينتظر الرمز استجابة المحرك ، لكنه يدرك أنه لا يعمل ويجب عليك أن تتصرف بشكل مختلف. يجب إعداد التعليمات البرمجية لحقيقة أن قواعد البيانات لا تعمل دائمًا.
تطبيقات محددة
أحيانًا ما زلنا نريد حقًا الحصول على نوع من الحلول المخصصة كمحرك. في الوقت نفسه ، تقرر عدم استخدام وكيلنا rpc الجاهز ، المصمم خصيصًا لمحركاتنا ، ولكن لإنشاء وكيل منفصل لهذه المهمة.
بالنسبة إلى MySQL ، التي لا تزال لدينا في بعض الأماكن ، نستخدم db-proxy ، و ClickHouse -
Kittenhouse .
هذا يعمل بشكل عام من هذا القبيل. هناك خادم ، kPHP ، Go ، Python تعمل عليه - بشكل عام ، أي رمز يمكن أن يتبع بروتوكول RPC الخاص بنا. ينتقل الرمز محليًا إلى RPC-proxy - على كل خادم يوجد به رمز ، يتم تشغيل الوكيل المحلي الخاص به. بناءً على الطلب ، يفهم الوكيل إلى أين يذهبون.

إذا أراد أحد المحركات الانتقال إلى محرك آخر ، حتى لو كان جارًا ، فإنه يمر عبر وكيل ، لأن الجار يمكن أن يكون في مركز بيانات مختلف. لا ينبغي ربط المحرك بمعرفة موقع أي شيء آخر غير نفسه - لدينا هذا الحل القياسي. ولكن بالطبع هناك استثناءات :)
مثال على مخطط 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;
هذا هو بروتوكول ثنائي ، وأقرب التماثلية هو
protobuf. يصف المخطط مسبقًا الحقول الاختيارية والأنواع المعقدة - امتدادات العددية المدمجة والاستعلامات. كل شيء يعمل وفقا لهذا البروتوكول.
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 ، ولكن المبدأ واحد.
لكي لا يقوم المحرك بإعادة قراءة السجل بالكامل أثناء إعادة التشغيل خلال سنوات عديدة ، تقوم المحركات بكتابة
لقطات - الحالة الحالية . إذا لزم الأمر ، قرأوا أولاً منه ، ثم قرأوا من binlog. تتم كتابة جميع السجلات الثنائية بنفس التنسيق الثنائي - وفقًا لنظام TL- ، بحيث يمكن للمشرفين إدارتها بالتساوي مع أدواتهم. ليست هناك حاجة لمثل هذه اللقطات. هناك عنوان عام يشير إلى أن لقطة الشاشة هي int ، سحر المحرك ، وأي جسم ليس مهمًا لأحد. هذه هي مشكلة المحرك الذي سجل اللقطة.
سوف أصف بإيجاز مبدأ العمل. يوجد خادم يعمل عليه المحرك. انه يفتح binlog فارغة جديدة للتسجيل ، ويكتب حدث تغيير فيه.

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

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

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

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

إذا كنت بحاجة إلى
نسخة متماثلة للقراءة من أجل تقليل الحمل على القراءة على وحدة المعالجة المركزية ، فإن محرك القراءة يرتفع ، والذي يقرأ نهاية binlog وينفذ هذه الأوامر محليًا.
التأخر هنا صغير جدًا ، وهناك فرصة لمعرفة مقدار النسخة المتماثلة خلف المعلم الرئيسي.
مشاركة البيانات في RPC-proxy
كيف يعمل التقشير؟ كيف يفهم البروكسي ما هي الكتلة العنقودية التي سترسل إليها؟ الكود لا يقول: "أرسل إلى 15 قشرة!" - لا ، يفعل وكيل.
أبسط مخطط هو firstint ، الرقم الأول في الطلب.
get(photo100_500) => 100 % N.
هذا مثال على بروتوكول نصي بسيط ، ولكن بالطبع الطلبات معقدة ومهيكلة. المثال يأخذ الرقم الأول في الاستعلام والباقي من القسمة حسب حجم الكتلة.
هذا مفيد عندما نريد الحصول على بيانات محلية لكيان واحد. لنفترض أن 100 هو معرف مستخدم أو مجموعة ، ونريد أن تكون جميع بيانات كيان واحد في نفس المجموعة لاستعلامات معقدة.
إذا لم نكن مهتمين بكيفية انتشار الطلبات عبر المجموعة ، فهناك خيار آخر -
تجزئة القشرة بأكملها .
hash(photo100_500) => 3539886280 % N
نحصل أيضًا على التجزئة والباقي من القسمة وعدد القشرة.
يعمل كلا هذين الخيارين فقط إذا كنا مستعدين لحقيقة أننا عندما نزيد حجم الكتلة ، فإننا سنقسمها أو نزيدها عدة مرات. على سبيل المثال ، لدينا 16 قطعة ، نحن في عداد المفقودين ، نريد المزيد - يمكنك الحصول على 32 بأمان دون توقف. إذا أردنا أن نتراكم عدة مرات ، فستكون هناك فترة توقف ، لأنه لن يكون من الممكن سحق كل شيء بعناية دون خسارة. هذه الخيارات مفيدة ، ولكن ليس دائمًا.
إذا كنا بحاجة إلى إضافة أو إزالة عدد عشوائي من الخوادم ،
فسيتم استخدام تجزئة متناسقة على حلقة la Ketama . ولكن في الوقت نفسه ، نفقد تمامًا موضع البيانات ، يتعين علينا تقديم طلب دمج إلى الكتلة بحيث تُرجع كل قطعة إجابتها الصغيرة ، وتجمع بالفعل الردود على الوكيل.
- . : RPC-proxy , , . , , , . proxy.

. —
memcache .
ring-buffer: prefix.idx = line
— , , — . 0 1. memcache — . .
,
Multi Get , , . , - , , , .
logs-engine . , . 600 .
, , 6–7 . , , , ClickHouse .
ClickHouse
, .

, RPC RPC-proxy, , . ClickHouse, :
- - ClickHouse;
- RPC-proxy, ClickHouse, - , , RPC.
— ClickHouse.
ClickHouse,
KittenHouse . KittenHouse ClickHouse — . , HTTP- . , ClickHouse
reverse proxy , , . .

RPC- , , nginx. KittenHouse UDP.

, UDP- . RPC , UDP. .
مراقبة
: , , . :
.
Netdata ,
Graphite Carbon . ClickHouse, Whisper, . ClickHouse,
Grafana , . , Netdata Grafana .
. , , Counts, UniqueCounts , - .
statlogsCountEvent ( 'stat_name', $key1, $key2, …) statlogsUniqueCount ( 'stat_name', $uid, $key1, $key2, …) statlogsValuetEvent ( 'stat_name', $value, $key1, $key2, …) $stats = statlogsStatData($params)
, , — , Wathdogs.
, 600 1 .
, . — , . , .
,
memcache , .
stats-daemon .
logs-collectors , , .

logs-collectors.

stas-daemom — , collector. , - memcache stats-daemon, , .
logs-collectors
meowDB — , .

«-SQL» .

2018 , -, ClickHouse. ClickHouse — ?

, KittenHouse.
«*House» , , UDP. *House inserts, , KittenHouse. ClickHouse, .

memcache, stats-daemon logs-collectors .

memcache, stats-daemon logs-collectors .
- , StatsHouse.
- StatsHouse KittenHouse UDP-, SQL-inserts, .
- KittenHouse ClickHouse.
- , StatsHouse — ClickHouse SQL.
, , . , , , . .
. , stats-daemons logs-collectors, ClickHouse , , .
, .
PHP.
git :
GitLab TeamCity . -, , — .
, diff — : , , . binlog copyfast, . ,
gossip replication , , — , . . ,
. .
kPHP
git .
HTTP- , diff — . —
binlog copyfast . , .
. copyfast' , binlog , gossip replication , -, .
graceful .
, , :
- git master branch;
- .deb ;
- binlog copyfast;
- ;
- .dep;
- dpkg -i ;
- graceful .
,
.deb ,
dpkg -i . kPHP , — dpkg? . — .
:, PHP Russia 17 PHP-. , , ( PHP!) — , PHP, .