NewSQL = NoSQL + حمض

NewSQL = NoSQL + حمض
حتى وقت قريب في Odnoklassniki ، تم تخزين حوالي 50 تيرابايت من البيانات التي تتم معالجتها في الوقت الفعلي في SQL Server. لمثل هذا الحجم ، يكاد يكون من المستحيل توفير وصول سريع وموثوق به وحتى يتسامح مع الأخطاء إلى مركز البيانات باستخدام SQL DBMS. عادة في مثل هذه الحالات يتم استخدام أحد متاجر NoSQL ، ولكن لا يمكن نقل كل شيء إلى NoSQL: تتطلب بعض الكيانات ضمانات معاملات ACID.

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

كيف يعمل وماذا حدث - اقرأ تحت القص.

اليوم ، جمهور Odnoklassniki الشهري أكثر من 70 مليون زائر فريد. نحن أدخل الخمسة الاوائل أكبر الشبكات الاجتماعية في العالم ، وفي أفضل عشرين موقعًا يقضي المستخدمون فيها معظم الوقت. تتعامل البنية التحتية "OK" مع أحمال عالية جدًا: أكثر من مليون طلب HTTP / ثانية لكل واجهة. توجد أجزاء من ساحة الخادم تزيد عن 8000 قطعة بالقرب من بعضها البعض - في أربعة مراكز بيانات في موسكو ، مما يجعل من الممكن توفير تأخير في الشبكة أقل من 1 مللي ثانية بينهما.

نحن نستخدم Cassandra منذ عام 2010 ، بدءًا من الإصدار 0.6. اليوم ، تعمل عشرات المجموعات. تعالج المجموعة الأسرع أكثر من 4 ملايين عملية في الثانية ، بينما تخزن المجموعة الأكبر 260 تيرابايت.

ومع ذلك ، فهذه كلها مجموعات NoSQL عادية تستخدم للتخزين ضعيف التنسيق بيانات. أردنا أيضًا استبدال وحدة التخزين الرئيسية المتسقة ، Microsoft SQL Server ، والتي تم استخدامها منذ تأسيس Odnoklassniki. يتألف التخزين من أكثر من 300 جهاز SQL Server Standard Edition ، والتي تحتوي على 50 تيرابايت من البيانات - كيانات الأعمال. يتم تعديل هذه البيانات كجزء من معاملات ACID وتتطلب اتساق عالي.

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

بفضل التجزئة وتسريع SQL:

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

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

مشاكل مع SQL

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

لكن المشكلة الرئيسية هي

التسامح مع الخطأ

يحتوي SQL Server الكلاسيكي على تسامح ضعيف مع الخطأ. لنفترض أن لديك خادم قاعدة بيانات واحد فقط ويفشل كل ثلاث سنوات. في هذا الوقت ، الموقع معطل لمدة 20 دقيقة ، هذا مقبول. إذا كان لديك 64 خادمًا ، فسيتم تعطيل الموقع مرة واحدة كل ثلاثة أسابيع. وإذا كان لديك 200 خادم ، فإن الموقع لا يعمل كل أسبوع. هذه مشكله.

ما الذي يمكن عمله لتحسين التسامح مع الخطأ في خادم SQL؟ تدعونا ويكيبيديا للبناء الكتلة المتاحة للغاية: حيث في حالة فشل أي من المكونات يوجد نسخة احتياطية.

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

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

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

كل هذه المشاكل تتطلب حلاً أساسياً وشرعنا في تحليلها التفصيلي. هنا نحتاج إلى التعرف على ما يفعله خادم SQL بشكل أساسي - المعاملات.

صفقة بسيطة

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

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

أو في الكود الكاذب:

TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(…);

if (photo.status == PUBLIC ) {
    album.incPublicPhotosCount();
}
album.update();

TX.commit();

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

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

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

المتطلبات الأخرى التي لا تقل أهمية هي:

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

قرارات قرارات

عند تحليل الحلول الممكنة ، توصلنا إلى خيارين محتملين للهندسة المعمارية:

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

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

كاساندرا و CQL

إذن ، ما المثير للاهتمام في كاساندرا ، ما هي الميزات التي تتمتع بها؟

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

CREATE TABLE photos (id bigint KEY, owner bigint,…);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET … WHERE id=?;

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

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

فائدة أخرى من Cassandra هي Batchlog ، وهي آلية تضمن أن التغييرات التي تجريها إما مطبقة بالكامل أو لا تطبق بالكامل على الحزمة. هذا يسمح لنا بحل A في ACID - الذرية خارج الصندوق.

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

ما فاتنا في كاساندرا

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

مخروط

لذلك وُلد نظام DBMS الجديد مخروط، تتكون من ثلاثة أنواع من عقد الخادم:

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

NewSQL = NoSQL + حمض

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

الزبائن

NewSQL = NoSQL + حمض

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

C * منسق معاملات واحد

المنسق هو ما نفذناه لـ C * One من البداية. وهي مسؤولة عن إدارة المعاملات والأقفال وترتيب تطبيق المعاملات.

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

أقفال

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

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

نظرًا لأنه في حالتنا ، يتم بالفعل توزيع البيانات بين مجموعات المعاملات المحلية في SQL ، فقد تقرر تعيين مجموعات من المعاملات المحلية للمنسقين: يقوم أحد المنسقين بتنفيذ جميع المعاملات برمز من 0 إلى 9 ، والثاني - باستخدام رمز مميز من من 10 إلى 19 وما إلى ذلك. نتيجة لذلك ، تصبح كل حالة من حالات المنسق هي سيد مجموعة المعاملات.

ثم يمكن تنفيذ الأقفال كخريطة HashMap مبتذلة في ذاكرة المنسق.

رفض المنسقين

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

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

NewSQL = NoSQL + حمض

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

يتم إرسال رسائل Heartbeat بتردد عالٍ ، حوالي 20 مرة في الثانية ، مع فترة تبلغ 50 مللي ثانية. في Java ، من الصعب ضمان استجابة التطبيق في غضون 50 مللي ثانية بسبب أوقات التوقف القابلة للمقارنة التي تسببها أداة تجميع البيانات المهملة. تمكنا من تحقيق وقت الاستجابة هذا باستخدام أداة تجميع البيانات المهملة G1 ، والتي تتيح لك تحديد هدف لمدة توقفات GC المؤقتة. ومع ذلك ، في بعض الأحيان ، نادرًا جدًا ، تتجاوز فترات التوقف المؤقت للمجمع 50 مللي ثانية ، مما قد يؤدي إلى اكتشاف فشل خاطئ. لتجنب ذلك ، لا يقوم المنسق بالإبلاغ عن فشل العقدة البعيدة عند فقدان أول رسالة نبضات منها ، فقط في حالة فقد العديد منها في صف واحد. لذلك تمكنا من الكشف عن فشل العقدة المنسقة في 200 مللي ثانية.

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

حجز

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

NewSQL = NoSQL + حمض

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

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

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

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

كيف تعمل الصفقة

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

NewSQL = NoSQL + حمض

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

NewSQL = NoSQL + حمض

عندما يطلب العميل بياناته المعدلة كجزء من معاملة نشطة ، يتصرف المنسق على النحو التالي:

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

وبالتالي ، يمكن للعميل قراءة التغييرات الخاصة به ، ولا يرى العملاء الآخرون هذه التغييرات ، لأنها مخزنة فقط في ذاكرة المنسق ، فهي ليست بعد في عقد Cassandra.

NewSQL = NoSQL + حمض

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

NewSQL = NoSQL + حمض

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

نتيجة للتحسينات الموضحة أعلاه ، قمنا بتنفيذ مبادئ ACID:

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

القراءة بالفهارس

لنأخذ جدولًا بسيطًا:

CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
…)

يحتوي على معرف (مفتاح أساسي) ومالك وتاريخ تعديل. تحتاج إلى تقديم طلب بسيط للغاية - حدد البيانات الخاصة بالمالك مع تاريخ التغيير "لليوم الأخير".

SELECT *
WHERE owner=?
AND modified>?

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

الفهارس في C * One

يوجد جدول أولي بالصور يكون فيه معرّف التسجيل مفتاحًا أساسيًا.

NewSQL = NoSQL + حمض

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

NewSQL = NoSQL + حمض

الآن يمكن إعادة كتابة طلب البحث عن "المالك في آخر XNUMX ساعة" على أنه اختيار من جدول آخر:

SELECT * FROM i1_test
WHERE owner=?
AND modified>?

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

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

ماذا حدث

لقد طورنا C * One منذ ثلاث سنوات وقمنا بتشغيله تجاريًا.

ماذا انتهى بنا؟ لنقم بتقييم هذا على مثال نظام فرعي لمعالجة الصور وتخزينها ، وهو أحد أهم أنواع البيانات في الشبكات الاجتماعية. لا يتعلق الأمر بجثث الصور نفسها ، بل يتعلق بجميع أنواع المعلومات الفوقية. يوجد الآن في Odnoklassniki حوالي 20 مليار من هذه السجلات ، يعالج النظام 80 ألف طلب قراءة في الثانية ، ما يصل إلى 8 آلاف معاملة ACID في الثانية تتعلق بتعديل البيانات.

عندما استخدمنا SQL مع عامل النسخ المتماثل = 1 (ولكن في RAID 10) ، تم تخزين المعلومات الوصفية للصورة على مجموعة متاحة للغاية من 32 جهاز Microsoft SQL Server (بالإضافة إلى 11 قطعة غيار). كما تم تخصيص 10 خوادم لتخزين النسخ الاحتياطية. إجمالي 50 سيارة باهظة الثمن. في نفس الوقت ، كان النظام يعمل في الحمولة المقدرة ، بدون هامش.

بعد الترحيل إلى نظام جديد ، حصلنا على عامل النسخ = 3 - نسخة في كل مركز بيانات. يتكون النظام من 63 عقدة تخزين كاساندرا و 6 أجهزة تنسيق ، ليصبح المجموع 69 خادمًا. لكن هذه الأجهزة أرخص بكثير ، حيث يبلغ إجمالي تكلفة نظام SQL حوالي 30٪. في هذه الحالة ، يتم الاحتفاظ بالحمل عند مستوى 30٪.

مع إدخال C * One ، انخفض زمن الانتقال أيضًا: في SQL ، استغرقت عملية الكتابة حوالي 4,5 مللي ثانية. في C * One - حوالي 1,6 مللي ثانية. مدة المعاملة في المتوسط ​​أقل من 40 مللي ثانية ، ويكتمل الالتزام في 2 مللي ثانية ، ومدة القراءة والكتابة 2 مللي ثانية في المتوسط. النسبة المئوية 99 هي 3-3,1 مللي ثانية فقط ، وانخفض عدد المهلات بمقدار 100 مرة - كل ذلك بسبب الاستخدام الواسع النطاق للمضاربة.

حتى الآن ، تم إيقاف تشغيل معظم عقد SQL Server ، ولم يتم تطوير المنتجات الجديدة إلا باستخدام C * One. قمنا بتكييف C * One للعمل في السحابة الخاصة بنا سحابة واحدة، مما جعل من الممكن تسريع نشر مجموعات جديدة ، وتبسيط التكوين وأتمتة العملية. بدون شفرة المصدر ، سيكون هذا أكثر صعوبة ومبتكرة.

نعمل الآن على نقل مخازننا الأخرى إلى السحابة - لكن هذه قصة مختلفة تمامًا.

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

إضافة تعليق