كيف بنينا مجموعة PostgreSQL موثوقة على Patroni



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

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

إرث في العمارة توافر عالية


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

العودة إلى PostgreSQL. هذا هو واحد من أقدم مشاريع المصادر المفتوحة الشعبية ، التي تم إطلاق أول إصدار منها في السنة 95 من القرن الماضي. لفترة طويلة ، لم يفكر فريق المشروع في توفر عالية كمهمة تحتاج إلى معالجة من قبل النظام. لذلك ، أصبحت تقنية النسخ المتماثل لإنشاء نسخ البيانات متكاملة فقط في الإصدار 8.2 في عام 2006 ، ولكن تم إيداعها (سجل الشحن). في عام 2010 ، ظهر النسخ المتماثل المتدفق في الإصدار 9.0 ، وهو الأساس لإنشاء مجموعة واسعة من المجموعات. هذا ، في الواقع ، أمر مفاجئ للغاية بالنسبة للأشخاص الذين يتعرفون على PostgreSQL بعد Enterprise SQL أو NoSQL الحديثة - الحل القياسي من المجتمع هو مجرد اثنين من نسخة متماثلة رئيسية مع نسخ متماثل أو غير متزامن. في الوقت نفسه ، يتم تبديل المعالج يدويًا في الصرف ، ويُقترح أيضًا حل مشكلة تبديل العملاء بشكل مستقل.

كيف قررنا جعل PostgreSQL موثوقة وما اخترناه لهذا


ومع ذلك ، لن يصبح برنامج PostgreSQL شائعًا للغاية إذا لم يكن هناك عدد كبير من المشاريع والأدوات التي تساعد على بناء حل متسامح مع الأخطاء لا يتطلب اهتمامًا مستمرًا. منذ إطلاق DBaaS ، تتوفر خوادم PostgreSQL الفردية وأزواج النسخ المتماثلة الرئيسية مع النسخ المتماثل غير المتزامن في Mail.ru Cloud Solutions (MCS).

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

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

القاعدة الرياضية في هذه المسألة خطيرة جدا. من ناحية ، هناك نظرية CAP ، التي تفرض قيودًا نظرية على إمكانية إنشاء حلول HA ، من ناحية أخرى ، خوارزميات تحديد توافق الآراء المثبتة رياضيا ، مثل Paxos و Raft . على هذا الأساس ، هناك DCS شعبية (أنظمة التوافق اللامركزية) - Zookeeper ، etcd ، القنصل. لذلك ، إذا كان نظام اتخاذ القرار يعمل على بعض خوارزمياته الخاصة ، مكتوبًا بشكل مستقل ، فيجب أن تكون شديد الحذر بشأنه. بعد تحليل عدد كبير من الأنظمة ، استقرنا على Patroni - نظام مفتوح المصدر ، تم تطويره بشكل أساسي بواسطة Zalando.

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

Patroni


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

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

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

إن استخدام نسخ النسخ الاحتياطية للقراءة هذه له ما يبرره للإبلاغ عن المهام التحليلية أو إلغاء تحميل الخادم الرئيسي.

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

  • إعداد 3 خوادم أو أكثر ، وتكوين قواعد عنونة IP وجدار الحماية بينهما ؛
  • تثبيت حزم الخدمات وغيرها ، Patroni ، PostgreSQL ؛
  • تكوين الكتلة وغيرها ؛
  • تكوين خدمة المستفيد للعمل مع PostgreSQL.

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

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

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

يمكن توصيلهما من خلال واجهة برمجة تطبيقات MCS cloud ووحدة التحكم في الويب.

عرض


لاختبار إمكانيات نظام PostgreSQL في سحابة MCS ، دعونا نرى كيف يتصرف التطبيق المباشر في حالة وجود مشاكل في DBMS.

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

from __future__ import print_function from datetime import datetime from random import randint from time import sleep import psycopg2 def main(): try: connection = psycopg2.connect(user = "admin", password = "P@ssw0rd", host = "89.208.87.38", port = "5432", database = "myproddb") cursor = connection.cursor() cursor.execute("SELECT version();") record = cursor.fetchone() print("Connection opened to", record[0]) cursor.execute( "INSERT INTO log VALUES ({});".format(randint(1, 10000))) connection.commit() cursor.execute("SELECT COUNT(event_id) from log;") record = cursor.fetchone() print("Logged a value, overall count: {}".format(record[0])) except Exception as error: print ("Error while connecting to PostgreSQL", error) finally: if connection: cursor.close() connection.close() print("Connection closed") if __name__ == '__main__': try: while True: try: print(datetime.now()) main() sleep(3) except Exception as e: print("Caught error:\n", e) sleep(1) except KeyboardInterrupt: print("exit") 

يحتاج التطبيق إلى PostgreSQL للعمل. إنشاء كتلة في سحابة MCS باستخدام API. في محطة طرفية عادية ، حيث يحتوي المتغير OS_TOKEN على رمز مميز للوصول إلى واجهة برمجة التطبيقات (يمكنك الحصول عليه باستخدام أمر قضية الرمز المفتوح openstack) ، نكتب الأوامر:

إنشاء كتلة:

 cat <<EF > pgc10.json {"cluster":{"name":"postgres10","allow_remote_access":true,"datastore":{"type":"postgresql","version":"10"},"databases":[{"name":"myproddb"}],"users":[{"databases":[{"name":"myproddb"}],"name":"admin","password":"P@ssw0rd"}],"instances":[{"key_name":"shared","availability_zone":"DP1","flavorRef":"d659fa16-c7fb-42cf-8a5e-9bcbe80a7538","nics":[{"net-id":"b91eafed-12b1-4a46-b000-3984c7e01599"}],"volume":{"size":50,"type":"DP1"}},{"key_name":"shared","availability_zone":"DP1","flavorRef":"d659fa16-c7fb-42cf-8a5e-9bcbe80a7538","nics":[{"net-id":"b91eafed-12b1-4a46-b000-3984c7e01599"}],"volume":{"size":50,"type":"DP1"}},{"key_name":"shared","availability_zone":"DP1","flavorRef":"d659fa16-c7fb-42cf-8a5e-9bcbe80a7538","nics":[{"net-id":"b91eafed-12b1-4a46-b000-3984c7e01599"}],"volume":{"size":50,"type":"DP1"}}]}} EOF curl -s -H "X-Auth-Token: $OS_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d @pgc10.json https://infra.mail.ru:8779/v1.0/ce2a41bbd1434013b85bdf0ba07c770f/clusters 



عندما تدخل المجموعة إلى الحالة ACTIVE ، ستتلقى جميع الحقول القيم الحالية - الكتلة جاهزة.

في واجهة المستخدم الرسومية:



دعنا نحاول الاتصال وإنشاء جدول:

 psql -h 89.208.87.38 -U admin -d myproddb Password for user admin: psql (11.1, server 10.7) Type "help" for help. myproddb=> CREATE TABLE log (event_id integer NOT NULL); CREATE TABLE myproddb=> INSERT INTO log VALUES (1),(2),(3); INSERT 0 3 myproddb=> SELECT * FROM log; event_id ---------- 1 2 3 (3 rows) myproddb=> 



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



التبديل الرئيسية المجدولة


سنختبر الآن تشغيل تطبيقنا أثناء التبديل المخطط للمعالج:



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



سقوط السيارة


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

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



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

 2019-03-29 10:45:56.071234 Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit Logged a value, overall count: 453 Connection closed 2019-03-29 10:45:59.205463 Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit Logged a value, overall count: 454 Connection closed 2019-03-29 10:46:02.661440 Error while connecting to PostgreSQL server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. Caught error: local variable 'connection' referenced before assignment ……………………………………………………….. -  -   2019-03-29 10:46:30.930445 Error while connecting to PostgreSQL server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. Caught error: local variable 'connection' referenced before assignment 2019-03-29 10:46:31.954399 Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit Logged a value, overall count: 455 Connection closed 2019-03-29 10:46:35.409800 Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit Logged a value, overall count: 456 Connection closed ^Cexit 

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

استنتاج


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

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


All Articles