كيف يعمل بحث Yandex.Market وماذا سيحدث في حالة تعطل أحد الخوادم

مرحبا اسمي يوجين. أنا أعمل في بنية بحث Yandex.Market. أريد أن أخبر مجتمع هبر بالمطبخ الداخلي للسوق - ولكن هناك شيء أخبره. بادئ ذي بدء ، كيف يعمل البحث عن السوق والعمليات والهندسة المعمارية. كيف نتعامل مع حالات الطوارئ: ماذا يحدث إذا تعطل خادم واحد؟ وإذا كان هناك 100 من هذه الخوادم؟

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



قليلا عنا: ما المشكلة التي نحلها


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

نحن نعالج جميع طلبات البحث: من مواقع market.yandex.ru و beru.ru وخدمة Supercheck و Yandex.Advisor وتطبيقات الأجهزة المحمولة. ندرج أيضًا عروض البضائع في نتائج البحث على yandex.ru.



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

ما هو: هندسة السوق


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

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

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

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

سأتحدث عن كيفية بحثنا عن قطة في الجزء الخاص بهيكل البحث.

بحث السوق الهندسة المعمارية


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


مخطط معالجة طلب مبسط

كل خدمة لديها شيء رائع - موازنها الخاص مع اسم فريد:



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

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

يسمح FQDN واحد لجميع مراكز البيانات للخدمة A بفك الارتباط بشكل عام عن المواقع. سيتم دائمًا معالجة طلبه للخدمة B. الاستثناء هو الحالة عندما تكون الخدمة في جميع مراكز البيانات.

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

محاربة ما هو غير متوقع: الموازنة وخدمات البحث المرنة


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

الوضع فظيع ، لكننا مستعدون لذلك. سأخبرك بالترتيب.

تقع البنية التحتية للبحث في العديد من مراكز البيانات:



عند التصميم ، نضع إمكانية تعطيل مركز بيانات واحد. الحياة مليئة بالمفاجآت - على سبيل المثال ، يمكن للحفارة قطع كابل تحت الأرض (نعم ، كان الأمر كذلك). يجب أن تكون السعات في مراكز البيانات المتبقية كافية لتحمل ذروة الحمل.

النظر في مركز بيانات واحد. في كل مركز بيانات نفس مخطط الموازنات:


موازن واحد هو ثلاثة خوادم فعلية على الأقل. يرصد هذا التكرار لموثوقية. موازنات العمل على HAProx.

لقد اخترنا HAProx بسبب أدائها العالي ومتطلباتها المحدودة من الموارد ووظائفها الواسعة. داخل كل خادم يعمل برنامج البحث لدينا.

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

هذا ما يحدث في الواقع: الخوادم تتعطل. لذلك ، يجب عليك مراقبة حالة جميع الخوادم باستمرار. إذا توقف الخادم عن الاستجابة ، فسيتم فصله تلقائيًا عن حركة المرور. لهذا ، HAProxy لديه فحص صحي مدمج. يذهب إلى جميع الخوادم مع طلب HTTP "/ ping" مرة واحدة في الثانية.

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

الآن عن العثور على القط. استفسارات حول النموذج / البحث؟ النص = غاضب + قطة تصل للبحث . لكي يكون البحث سريعًا ، يجب وضع فهرس القط بأكمله في ذاكرة الوصول العشوائي. حتى القراءة من SSD ليست بالسرعة الكافية.

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


لكن هذا يحدث دائمًا: أي حل ، حتى جيد ، يثير مشاكل أخرى.

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

منذ توزيع الموازن للطلبات بالتساوي ، كانت جميع الخوادم تعمل في إعادة ترتيب ، وليس فقط إعطاء البيانات.

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

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

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

يتم تجميع الخوادم في مجموعات. تحتوي كل مجموعة على ثمانية محركات بحث ومقتطف واحد.


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

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

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

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

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

استعلامات البحث داخل الكتلة هي: / shard1؟ نص = غاضب + قطة . بالإضافة إلى ذلك ، يتم إجراء الاستعلامات الفرعية للنموذج: / status باستمرار بين جميع الخوادم داخل الكتلة مرة واحدة في الثانية.

/ حالة الطلب بالكشف عن موقف عندما يكون الخادم غير متوفر.

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

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



لنقل البيانات ، قدمنا ​​مفاتيح عالمية للمستندات. الآن يصبح الموقف مستحيلًا عندما يقوم أحد المفاتيح بإرجاع المحتوى من مستند آخر.

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

والآن إلى القصص المخيفة بنهاية سعيدة. النظر في العديد من حالات عدم توفر الخادم.

حدث فظيع: خادم واحد غير متوفر


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

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



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

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

أسوأ من ذلك: العديد من الخوادم غير متوفرة


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

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

ثم تبدأ حركة المرور الزائدة بشكل عشوائي في مراكز البيانات الأخرى. كل شيء يعمل ، الجميع سعداء.


كيف نفعل ذلك: الافراج عن الإصدارات


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



ثم يتم طرح الخدمة للاختبار ، حيث يتم التحقق من الاستقرار.

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

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

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

كل التوفيق للمستخدم: اختبار A / B


ليس من الواضح دائمًا ما إذا كانت التغييرات في الخدمة ستحقق فوائد حقيقية. لقياس مدى فائدة التغيير ، توصل الناس إلى اختبار A / B. سأتحدث قليلاً عن كيفية عمل ذلك في بحث Yandex.Market.

كل شيء يبدأ بإضافة معلمة CGI جديدة تتضمن وظائف جديدة. دع المعلمة تكون: market_new_functionality = 1 . ثم ، في الكود ، قم بتمكين هذه الوظيفة مع العلم:

If (cgi.experiments.market_new_functionality) { // enable new functionality } 

وظائف جديدة تطول في الإنتاج.

هناك خدمة مخصصة لأتمتة اختبار A / B ، الموضح بالتفصيل هنا . يتم إنشاء تجربة في الخدمة. تم تعيين حصة حركة المرور ، على سبيل المثال ، 15 ٪. يتم تعيين الفائدة ليس للطلبات ، ولكن للمستخدمين. يشار أيضا إلى وقت التجربة ، على سبيل المثال ، أسبوع.

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

نتيجة لذلك ، تضيف الخدمة تلقائيًا وسيطة market_new_functionality = 1 إلى 15٪ من المستخدمين. كما يقوم تلقائيًا بحساب المقاييس المحددة. بعد التجربة ، ينظر المحللون إلى النتائج ويستخلصون النتائج. بناءً على النتائج ، يتم اتخاذ قرار بالبدء في الإنتاج أو التنقيح.

ومن ناحية السوق ذكيا: اختبار الإنتاج


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

يوجد حل: لا يمكن استخدام علامات المعلمات CGI ليس فقط لاختبار A / B ، ولكن أيضًا لاختبار وظائف جديدة.

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

مخطط الخدمة موضح أدناه:



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

في Stop Crane ، يمكنك تعيين نوعين من القيم:

1) التعبيرات الشرطية. تنطبق عند تنفيذ إحدى القيم. على سبيل المثال:

 { "condition":"IS_DC1", "value":"3", }, { "condition": "CLUSTER==2 and IS_BERU", "value": "4!" } 

سيتم تطبيق القيمة "3" عند معالجة الطلب في موقع DC1. والقيمة هي "4" عند معالجة الطلب على المجموعة الثانية للموقع beru.ru.

2) القيم غير المشروطة. يتم استخدامها افتراضيًا في حالة عدم تلبية أي من الشروط. على سبيل المثال:

قيمة ، قيمة!

إذا انتهت القيمة بنقطة تعجب ، فيتم منحها أولوية أعلى.

محلل المعلمات CGI يوزع URL. ثم يطبق القيم من مفتاح التوقف.

تنطبق القيم ذات الأولويات التالية:

  1. أولوية أعلى من علامة توقف (علامة التعجب).
  2. القيمة من الاستعلام.
  3. القيمة الافتراضية هي من الحنفية stop.
  4. القيمة الافتراضية في الكود.

هناك الكثير من الإشارات المشار إليها في القيم الشرطية - وهي كافية لجميع السيناريوهات المعروفة لنا:

  • مركز البيانات.
  • البيئة: الإنتاج ، الاختبار ، الظل.
  • المكان: السوق ، بيرو.
  • رقم المجموعة.

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

إذا لاحظت مشكلة ، فيمكنك على الفور إرجاع القيمة السابقة للعلامة ، وسيتم التراجع عن التغييرات.

هذه الخدمة لها عيوبها: يحبها المطورون كثيرًا وغالبًا ما يحاولون دفع جميع التغييرات إلى Stop Crane. نحن نحاول مكافحة سوء الاستخدام.

تعمل طريقة Stop Crane بشكل جيد عندما يكون لديك بالفعل رمز ثابت ، جاهز للتطبيق في الإنتاج. في الوقت نفسه ، لا يزال لديك شكوك ، وتريد التحقق من الكود في ظروف "القتال".

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

اختبار سري: مجموعة الظل


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



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

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

النتائج


لذلك ، كيف بنينا البحث في السوق؟

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

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

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

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

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


All Articles