مرحبا بالجميع. كما تعلمون ، كنت أكتب وأتحدث أكثر عن التخزين ، Vertica ، تخزين البيانات الضخمة والأشياء التحليلية الأخرى. الآن تقع جميع قواعد البيانات الأخرى في مجال مسؤوليتي ، ليس فقط التحليلي ، ولكن أيضًا OLTP (PostgreSQL) ، و NOSQL (MongoDB ، Redis ، Tarantool).
سمح لي هذا الوضع بالنظر إلى منظمة لديها العديد من قواعد البيانات كمنظمة لديها قاعدة بيانات واحدة غير متجانسة (غير متجانسة). قاعدة بيانات واحدة غير متجانسة موزعة ، تتكون من مجموعة من قواعد بيانات PostgreSQL و Redis و Mong ... وربما قاعدة بيانات أو اثنتين من قواعد بيانات Vertica.
يولد عمل هذه القاعدة الموزعة الفردية مجموعة من المهام المثيرة للاهتمام. بادئ ذي بدء ، من وجهة نظر الأعمال ، من المهم أن كل شيء طبيعي مع نقل البيانات على طول هذه القاعدة. أنا لا أستعمل على وجه التحديد مصطلح النزاهة والاتساق ، لأن المصطلح معقد ، وفي الفروق الدقيقة المختلفة للنظر في DBMS (A C ID and C AP نظرية) لها معنى مختلف.
يتفاقم الوضع مع قاعدة موزعة إذا حاولت شركة التحول إلى هندسة الخدمات الصغيرة. تحت القطة ، أتحدث عن كيفية ضمان سلامة البيانات في بنية الخدمات الصغيرة دون المعاملات الموزعة والاتصال الضيق. (وفي النهاية أشرح لماذا اخترت هذا التوضيح للمقال).

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

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

إن العمل مع هذه "حديقة الحيوانات" لقواعد البيانات يرفع مهمة استعادة النظام في البيانات إلى مستوى جديد تمامًا من التعقيد.
بنية ACID والخدمات الصغيرة
دعونا نلقي نظرة على مهمة ترتيب الأشياء من خلال مجموعة متطلبات ACID المستندة إلى DBMS الكلاسيكية: سنقوم بتوسيع جوهر كل حرف من الاختصار وتوضيح الصعوبات التي تواجهها هذه الرسالة في بنية الخدمات الدقيقة.
(A) CID - الذرية. الذرية - كل شيء أو لا شيء.
وفقًا لمتطلبات Atomicity ، من الضروري إكمال جميع الخطوات (مع التكرار المحتمل) ، إذا فشلت خطوة مهمة ، قم بإلغاء الخطوات المكتملة.
يوضح الرسم التوضيحي أعلاه عملية اختبار شراء خدمة VIP: يتم حجز المال في الفواتير (1) ، ويتم تنشيط خدمة المكافأة للمستخدم (2) ، ويتم تغيير نوع المستخدم إلى Pro (3) ، ويتم خصم الأموال المحجوزة في الفواتير (4). يجب إكمال جميع الخطوات الأربع أو عدم إكمالها.

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

ACI (D) - المتانة. شرط المتانة يعني أن آثار العمليات لا تختفي.
في ظل ظروف ثبات Polyglot ، يمكن أن تعمل الخدمة على قاعدة بيانات يمكن أن "تفقد" بانتظام البيانات المسجلة فيها. يمكن الحصول على خدعة مماثلة حتى من قواعد البيانات الصلبة مثل PostgreSQL ، إذا تم تمكين النسخ المتزامن غير المتزامن هناك. يوضح الرسم التوضيحي كيف يمكن تدمير التغييرات المسجلة في Master ، والتي لم تصل إلى Slave عبر النسخ المتزامن غير المتزامن ، عن طريق حرق الخادم الرئيسي. لضمان متطلبات المتانة ، من الضروري أن تكون قادرًا على تشخيص واسترداد هذه الخسائر بشكل صحيح.

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

تتمثل إحدى المزايا الرئيسية لبنية الخدمات الصغيرة في القدرة على زيادة الأداء بشكل خطي عن طريق إضافة المزيد والمزيد من الخوادم. اتضح أنه إذا استخدمنا التزامًا على مرحلتين لضمان التكامل الموزع ، فستصبح هذه العملية عنق الزجاجة ، وتعيق نمو الإنتاجية ، على الرغم من الزيادة في عدد الخوادم.
كيف يمكنك ضمان التكامل الموزع (متطلبات ACiD) بدون تنفيذ على مرحلتين ، مع القدرة على التدرج الخطي في الأداء؟
يجادل البحث الحديث (على سبيل المثال ، تقييم التحكم في التزامن الموزع. VLDB 2017 ) بأن ما يسمى بـ "النهج المتفائل" يمكن أن يساعد. يمكن توضيح الفرق بين الالتزام على مرحلتين و "النهج المتفائل" المعمم من خلال الفرق بين المتجر السوفياتي القديم (مع عداد) وسوبر ماركت حديث مثل أوشان. في متجر به عداد ، يعتبر كل عميل مشبوهًا ، ويتم تقديمه بأقصى قدر من التحكم. ومن هنا جاءت الخطوط والصراعات. وفي السوبر ماركت ، يعتبر المشتري صادقًا افتراضيًا ، ويعطونه فرصة الاقتراب من الرفوف وملء العربات. بالطبع ، هناك أدوات مراقبة للقبض على المحتالين (الكاميرات والأمن) ، ولكن معظم المشترين لا يضطرون للتعامل معها على الإطلاق.
لذلك ، يمكن توسيع وتوسيع السوبر ماركت ببساطة عن طريق وضع المزيد من المكاتب النقدية. وهي تشبه بنية الخدمات المصغرة: إذا تم ضمان التكامل الموزع من خلال "نهج متفائل" ، عندما يتم تحميل العمليات التي حدث فيها خطأ فقط بالإضافة إلى عمليات الفحص. وتسير العمليات العادية بدون فحوصات إضافية.
من المهم. يتضمن "النهج المتفائل" العديد من الخوارزميات. أود أن أخبركم عن الملحمة - خوارزمية الحفاظ على التكامل الموزع ، التي أوصى بها كريس ريتشاردسون.
Sagas - عناصر الخوارزمية
خوارزمية تبلد لديها خياران. لذلك ، أود في البداية أن أصف عالميًا العناصر المطلوبة للخوارزمية بحيث يكون الوصف مناسبًا لكلا الخيارين.
العنصر 1. قناة ثابتة موثوقة لتقديم الحدث بين الخدمات ، وضمان "مرة واحدة على الأقل التسليم". على سبيل المثال إذا اكتملت الخطوة 2 من العملية بنجاح ، فيجب أن يصل الإخطار (الحدث) حول هذا إلى الخطوة 3 مرة واحدة على الأقل ، وتكون عمليات التسليم المتكررة مقبولة ، ولكن لا يجب فقدان أي شيء. تعني "المستمرة" أنه يجب على القناة تخزين الإشعارات لبعض الوقت (من يومين إلى ثلاثة أيام في الأسبوع) بحيث يمكن استعادة الخدمة التي فقدت أحدث التغييرات بسبب فقدان قاعدة البيانات (راجع مثال المتانة ، في الشكل التوضيحي هذا هو الخطوة 2) هذه التغييرات عن طريق إعادة تشغيل الأحداث من القناة.

العنصر 2. Idempotency لمكالمات الخدمة من خلال استخدام مفتاح idempotency فريد. تخيل أنني (المستخدم) أبدأ عملية شراء حزمة VIP (انظر مثال Atomicity). في بداية العملية ، أعطيت مفتاحًا فريدًا ، مفتاح idempotency ، على سبيل المثال ، 42. بعد ذلك ، يجب إجراء استدعاء لكل خطوة من الخطوات (1 → 2 → 3 → 4) باستخدام مفتاح idempotency المشار إليه. في الفقرة أعلاه ، تم ذكر إمكانية تكرار وصول نفس الرسالة إلى الخدمة (في الخطوة). يجب أن تكون الخدمة (الخطوة) قادرة تلقائيًا على تجاهل الوصول المتكرر للحدث المعالج ، والتحقق من التكرار بواسطة مفتاح idempotency. بمعنى ، إذا كانت جميع الخدمات (خطوات العملية) عاطلة ، فمن أجل تلبية متطلبات Atomicity والمتانة ، يكفي إعادة التوجيه إلى الخطوات المقابلة للأحداث من القنوات. الخطوات التي تخطيت الأحداث ستنفذها ، والخطوات التي أكملت بالفعل الأحداث ستتجاهلها بسبب idempotency.

العنصر 3. إلغاء مكالمات الخدمة (الخطوات) بواسطة مفتاح idempotency.
لضمان Atomicity (انظر المثال) ، إذا توقفت / سقطت العملية مع مفتاح idempotency ، على سبيل المثال ، في الخطوة 3 ، فمن الضروري إلغاء التنفيذ الناجح للخطوتين 1 و 2 للمفتاح 42. لهذا ، يجب أن يكون لكل خطوة عملية إلزامية خطوة "تعويض" ، طريقة API تلغي تنفيذ الخطوة المطلوبة لمفتاح idempotency المحدد (42). يعد تنفيذ المكالمات التعويضية عنصرًا صعبًا ولكنه ضروري في تحسين الخدمات كجزء من تنفيذ خوارزمية التبلد.

العناصر الثلاثة المذكورة أعلاه ذات صلة بكلا نسختين من تطبيق "sag": منسقة ومصممة الرقصات.
ساجاس مدبرة
من السهل فهم وتنفيذ الخوارزمية الأبسط والأكثر وضوحًا للقصص المنظمة. في مقال ممتاز ، وصف kevteev الخوارزمية وعملية تنفيذ آلية sagas المدبرة في Avito. تفترض الخوارزمية الخاصة بهم وجود خدمة تحكم ، مكالمات خدمة "منسقة" في إطار عمليات الأعمال المخدومة. قد يكون لخدمة المراقبة نفسها قاعدة بيانات خاصة بها (على سبيل المثال ، PostgreSQL) ، والتي تعمل كقناة موثوقة لتقديم الأحداث المستمرة (العنصر 1).
تصميم الرقصات
ملحمة الرقصات أكثر صعوبة. هنا ، يجب أن يعمل ناقل البيانات الذي ينفذ المتطلبات التالية كقناة ثابتة موثوقة: النشر بالنسيان والنسيان ، وتسليم حدث النشر والاشتراك ، مرة واحدة على الأقل التسليم. على سبيل المثال يجب أن تتلقى كل خطوة من كل عملية أمرًا للعمل من الحافلة ، وأن تلقي هناك رسالة حول الإكمال الناجح ، حول بداية الخطوة التالية ، حتى يقرأها أيضًا من الحافلة ويتابع العملية. علاوة على ذلك ، لكل رسالة يمكن أن يكون هناك العديد من المشتركين.
يجب أن تحتوي الملحمة الراقصة أيضًا على خدمة للتحكم ، خدمة للساغاس ، ولكن أكثر من ذلك بكثير "خفيفة الوزن". يجب أن تعرف الخدمة عن العمليات التجارية المسجلة في النظام ، حول تكوين الخطوات المدرجة في كل عملية. يجب عليه أيضًا الاستماع إلى الحافلة ، ومراقبة تنفيذ كل عملية (كل مفتاح idempotency) ، وفقط إذا حدث خطأ ما ، إما إلقاء "تكرار" لخطوات محددة ، أو إلقاء "إلغاء" ، "تعويضات" للخطوات المتخذة.
الفروق الدقيقة
واحدة من أهم الفروق الدقيقة في الساجا التي تميزها عن المعاملات الكلاسيكية هي الابتعاد عن الخطية والتسلسل والالتزام لكل خطوة. الملحمة ليست بالضرورة سلسلة خطية من الأحداث ، يمكن أن تكون رسمًا بيانيًا موجهًا: يمكن لحدث تسجيل مستخدم جديد أن يولد عدة خطوات بالتوازي (إرسال رسائل نصية قصيرة ، تسجيل الدخول ، إنشاء كلمة مرور ، إرسال بريد إلكتروني) ، قد يكون بعضها اختياريًا. في التقريب الأول ، يبدو أنه في مثل هذه الملحمة "المتفرعة" مع الخطوات الاختيارية ، من الصعب تحديد اكتمال الملحمة (العملية) ، ولكن في الواقع ، كل شيء بسيط: تكتمل الملحمة (العملية) عند اكتمال جميع الخطوات المطلوبة ، بأي ترتيب.

الفروق الثانية ، التي هي أكثر شيوعًا لمسابقات الرقصات ، ولكنها ممكنة أيضًا للبرامج المنظمة ، هي اختيار نهج لتسجيل العمليات التجارية ، وأنواع من القصص في خدمة sagas. يصف مثال Atomicity عملية من أربع خطوات مطلوبة متتالية.
من سجل هذه العملية ، وضح كل الخطوات ، وضع التبعيات والخطوات الإلزامية؟ الجواب الواضح ، ولكن القديم ، هو أن عملية التسجيل يجب أن تتم بشكل مركزي في خدمة الترهل. لكن هذه الإجابة ليست متسقة للغاية مع بنية الخدمات الصغيرة. في بنية الخدمات الصغيرة ، يعد تسجيل العمليات من القاعدة إلى القمة أكثر واعدة وأكثر إنتاجية وأسرع. على سبيل المثال ليس لتدوين جميع الفروق الدقيقة في العملية في خدمة التبلد ، ولكن للسماح للخدمات الفردية "بالتوافق" في العمليات الحالية بمفردها ، مع الإشارة إلى طبيعتها الملزمة / الاختيارية والسابقين الإلزاميين.
على سبيل المثال يمكن أن تتكون عملية تسجيل مستخدم في خدمة تبلد مبدئيًا من ثلاث خطوات ، وبعد ذلك ، أثناء تطوير النظام ، سيتم احتواء سبع خطوات أخرى ، وسيتم كتابة خطوة واحدة ، وستكون هناك تسع منها. من الصعب اختبار مثل هذا المخطط "الأناركي" و "اللامركزي" ، لتنفيذ عملية صارمة ومنسقة ، ولكنه أكثر ملاءمة للفرق الرشيقة ، لتطور المنتج المستمر متعدد الاتجاهات.
في الواقع ، هنا. مع عرض تقديمي جاد ، أعتقد أنه من المفيد الانتهاء ، وإلا تبين أن المقالة كبيرة جدًا.
هنا رابط لعرض هذه المواد ، لقد قدمت تقريرًا عن هذا الموضوع في Highload Siberia 2018.
UPD - والفيديو من المؤتمر:
الخاتمة
في النهاية ، أود أن أحاول شرح كل ما سبق بلغة رمزية أكثر.
بعد كل شيء ، ما هي ملحمة منذ البداية؟ هذه المؤامرة ، هذه المغامرة من العصور الوسطى ... أو من لعبة العروش. يحدث حدث (معركة ، حفل زفاف ، وفاة شخص ما) ، أخبار هذا الذباب حول العالم من خلال الرسل ، من خلال الحمام الناقل ، من خلال التجار. عندما تصل الأخبار إلى المهتمين (في أسبوع ، في شهر ، في سنة) ، يتفاعلون: يرسلون الجيوش ، ويعلنون الحرب ، ويعدمون شخصًا ، وتطير الرسائل الجديدة.
لا توجد هيئة تنظيمية تراقب تسلسل الإجراءات. لا معاملات ، ولا تراجع ، بمعنى التراجع عن الإجراء ، كما لو لم يكن قط. كل شيء بطريقة الكبار ، كل عمل يحدث إلى الأبد. يمكن تعويضه ، لكنه بالتحديد عمل (قتل) وتعويض (دفع الرأس ، فيرا) ، وليس إلغاء الموت.
تستغرق الأحداث وقتًا طويلاً ، وتأتي من مصادر مختلفة ، وتحدث الإجراءات بالتوازي ، وليس بشكل متسلسل. وفي كثير من الأحيان ، يظهر المشاركون الجدد فجأة في المؤامرة ، والذين يقررون المشاركة (يصل التنين ؛)) ... ويموت بعض المشاركين القدامى فجأة.
مثل هذه الأشياء. يبدو وكأنه فوضى وفوضى ، لكن كل شيء يعمل ، التنسيق الداخلي للعالم لا ينتهك ، المؤامرة تتطور وتتسق ... على الرغم من أنه في بعض الأحيان لا يمكن التنبؤ بها.