مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

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

لدينا خدمة محملة بشكل كبير: 2,5 مليون مستخدم حول العالم ، أكثر من 50 ألف مستخدم نشط كل يوم. توجد الخوادم في Amazone في منطقة واحدة من أيرلندا: أكثر من 100 خادم مختلف قيد التشغيل باستمرار ، منها ما يقرب من 50 مزودًا بقواعد بيانات.

الواجهة الخلفية بأكملها عبارة عن تطبيق Java كبير مترابط ذو حالة واحدة يحافظ على اتصال مقبس ويب ثابت مع العميل. عندما يعمل العديد من المستخدمين على نفس اللوحة في نفس الوقت ، فإنهم جميعًا يرون التغييرات في الوقت الفعلي ، لأننا نكتب كل تغيير في قاعدة البيانات. لدينا حوالي 10 آلاف طلب في الثانية لقواعد البيانات الخاصة بنا. في ذروة الحمل في Redis ، نكتب 80-100 ألف طلب في الثانية.
مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

لماذا تحولنا من Redis إلى PostgreSQL

في البداية ، عملت خدمتنا مع Redis ، وهو متجر ذو قيمة رئيسية يخزن جميع البيانات في ذاكرة الوصول العشوائي للخادم.

إيجابيات Redis:

  1. سرعة استجابة عالية لأن يتم تخزين كل شيء في الذاكرة.
  2. سهولة النسخ الاحتياطي والتكرار.

سلبيات Redis بالنسبة لنا:

  1. لا توجد معاملات حقيقية. حاولنا محاكاتها على مستوى تطبيقنا. لسوء الحظ ، لم يعمل هذا دائمًا بشكل جيد ويتطلب كتابة كود معقد للغاية.
  2. كمية البيانات محدودة بحجم الذاكرة. مع زيادة كمية البيانات ، ستنمو الذاكرة ، وفي النهاية ، سنواجه خصائص المثيل المحدد ، والذي يتطلب في AWS إيقاف خدمتنا لتغيير نوع المثيل.
  3. من الضروري الحفاظ باستمرار على مستوى زمن انتقال منخفض ، لأن. لدينا عدد كبير جدًا من الطلبات. مستوى التأخير الأمثل بالنسبة لنا هو 17-20 مللي ثانية. عند مستوى 30-40 مللي ثانية ، نحصل على استجابات طويلة للطلبات من تطبيقنا وتدهور الخدمة. لسوء الحظ ، حدث هذا لنا في سبتمبر 2018 ، عندما تلقت إحدى الحالات مع Redis لسبب ما وقت استجابة أكبر مرتين من المعتاد. لحل المشكلة ، أوقفنا الخدمة في منتصف اليوم للصيانة غير المجدولة واستبدلنا مثيل Redis المشكل.
  4. من السهل الحصول على تضارب في البيانات حتى مع وجود أخطاء بسيطة في الكود ثم قضاء الكثير من الوقت في كتابة التعليمات البرمجية لتصحيح هذه البيانات.

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

لقد انتقلنا بالفعل إلى قاعدة بيانات جديدة لمدة 1,5 عام وقد نقلنا جزءًا صغيرًا فقط من البيانات ، لذلك نحن نعمل الآن في وقت واحد مع Redis و PostgreSQL. تمت كتابة المزيد من المعلومات حول مراحل نقل البيانات وتبديلها بين قواعد البيانات مقال زميلي.

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

تنفيذ PgBouncer

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

كان لدينا خياران لمدير الاتصال: Pgpool و PgBouncer. لكن الأول لا يدعم وضع المعاملات للعمل مع قاعدة البيانات ، لذلك اخترنا PgBouncer.

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

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

تجاوز فشل PgBouncer

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

بعد ذلك ، فكرنا بجدية في التسامح مع الخطأ لمجموعات PgBouncer و PostgreSQL ، لأن موقفًا مشابهًا يمكن أن يحدث مع أي مثيل في حساب AWS الخاص بنا.

لقد أنشأنا مخطط التسامح مع الخطأ PgBouncer على النحو التالي: تصل جميع خوادم التطبيقات إلى Network Load Balancer ، والذي يوجد خلفه نوعان من PgBouncers. ينظر كل PgBouncer إلى نفس خبير PostgreSQL لكل جزء. في حالة حدوث عطل مثيل AWS مرة أخرى ، تتم إعادة توجيه كل حركة المرور من خلال PgBouncer آخر. يتم توفير تجاوز فشل Network Load Balancer بواسطة AWS.

هذا النظام يجعل من السهل إضافة خوادم PgBouncer جديدة.
مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

أنشئ مجموعة تجاوز فشل PostgreSQL

عند حل هذه المشكلة ، اعتبرنا خيارات مختلفة: تجاوز الفشل المكتوب ذاتيًا ، repmgr ، AWS RDS ، Patroni.

نصوص مكتوبة ذاتيا

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

تتمثل مزايا هذا الأسلوب في البساطة القصوى ، لأنك تكتب البرامج النصية بنفسك وتفهم بالضبط كيفية عملها.

سلبيات:

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

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

Repmgr

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

أوس رديز

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

تشمل العيوب عدم وجود تعديلات دقيقة. كمثال على الضبط الدقيق: تحتوي مثيلاتنا على قيود على اتصالات tcp ، والتي ، للأسف ، لا يمكن إجراؤها في RDS:

net.ipv4.tcp_keepalive_time=10
net.ipv4.tcp_keepalive_intvl=1
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_retries2=3

بالإضافة إلى ذلك ، تكلف AWS RDS تقريبًا ضعف سعر المثيل العادي ، والذي كان السبب الرئيسي للتخلي عن هذا الحل.

باتروني

هذا قالب Python لإدارة PostgreSQL مع توثيق جيد وتجاوز فشل تلقائي وكود المصدر على github.

إيجابيات باتروني:

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

سلبيات:

  • ليس من الواضح من الوثائق كيفية العمل مع PgBouncer بشكل صحيح. على الرغم من أنه من الصعب تسميتها ناقصًا ، لأن مهمة Patroni هي إدارة PostgreSQL ، وكيف أن الاتصالات مع Patroni ستنطلق هي مشكلتنا بالفعل ؛
  • هناك أمثلة قليلة على تنفيذ Patroni بكميات كبيرة ، في حين أن هناك العديد من الأمثلة على التنفيذ من البداية.

نتيجة لذلك ، اخترنا Patroni لإنشاء مجموعة تجاوز الفشل.

عملية تنفيذ Patroni

قبل Patroni ، كان لدينا 12 جزءًا من PostgreSQL بتكوين رئيسي واحد ونسخة متماثلة مع نسخ متماثل غير متزامن. وصلت خوادم التطبيقات إلى قواعد البيانات من خلال Network Load Balancer ، والتي كانت خلفهما مثيلين مع PgBouncer ، وخلفهما كانت جميع خوادم PostgreSQL.
مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

لتنفيذ Patroni ، احتجنا إلى تحديد تكوين مجموعة التخزين الموزعة. يعمل Patroni مع أنظمة تخزين التكوين الموزعة مثل etcd و Zookeeper و Consul. لدينا فقط مجموعة قنصل كاملة في السوق تعمل جنبًا إلى جنب مع Vault ولم نعد نستخدمها. سبب وجيه لبدء استخدام القنصل للغرض المقصود منه.

كيف يعمل باتروني مع القنصل

لدينا مجموعة قنصل ، والتي تتكون من ثلاث عقد ، ومجموعة باتروني ، والتي تتكون من قائد ونسخة متماثلة (في باتروني ، يُطلق على السيد قائد الكتلة ، ويطلق على العبيد النسخ المتماثلة). ترسل كل حالة من مجموعة Patroni باستمرار معلومات حول حالة المجموعة إلى القنصل. لذلك ، يمكنك دائمًا من القنصل معرفة التكوين الحالي لمجموعة Patroni ومن هو القائد في الوقت الحالي.

مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

لربط Patroni بالقنصل ، يكفي دراسة الوثائق الرسمية ، والتي تنص على أنك بحاجة إلى تحديد مضيف بتنسيق http أو https ، اعتمادًا على كيفية عملنا مع القنصل ، ونظام الاتصال ، اختياريًا:

host: the host:port for the Consul endpoint, in format: http(s)://host:port
scheme: (optional) http or https, defaults to http

يبدو الأمر بسيطًا ، ولكن هنا تبدأ المزالق. مع Consul ، نعمل عبر اتصال آمن عبر https وسيبدو تكوين الاتصال الخاص بنا كما يلي:

consul:
  host: https://server.production.consul:8080 
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

لكن هذا لا يعمل. عند بدء التشغيل ، لا يمكن لـ Patroni الاتصال بالقنصل ، لأنه يحاول المرور عبر http على أي حال.

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

consul:
  host: server.production.consul:8080
  scheme: https
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

نموذج القنصل

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

بحثًا عن حل ، وجدنا مقالًا (لا أتذكر العنوان للأسف) حيث كتب أن قالب القنصل ساعد كثيرًا في إقران PgBouncer و Patroni. دفعنا هذا إلى التحقيق في كيفية عمل Consul-template.

اتضح أن Consul-template يراقب باستمرار تكوين مجموعة PostgreSQL في القنصل. عندما يتغير القائد ، يقوم بتحديث تكوين PgBouncer ويرسل أمرًا لإعادة تحميله.

مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

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

هندسة معمارية جديدة مع باتروني

نتيجة لذلك ، حصلنا على مخطط العمل التالي:
مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

تصل جميع خوادم التطبيق إلى الموازن → هناك مثيلين من PgBouncer خلفه → في كل مثيل ، يتم تشغيل Consul-template ، والذي يراقب حالة كل مجموعة Patroni ويراقب مدى صلة تكوين PgBouncer ، الذي يرسل الطلبات إلى القائد الحالي من كل مجموعة.

الاختبار اليدوي

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

مجموعة تجاوز الفشل PostgreSQL + Patroni. تجربة التنفيذ

عاد الملصق في غضون 10-20 ثانية ، ثم بدأ مرة أخرى في التحرك بشكل طبيعي. هذا يعني أن مجموعة Patroni عملت بشكل صحيح: لقد غيرت القائد ، وأرسلت المعلومات إلى Сonsul ، والتقط نموذج القنصل على الفور هذه المعلومات ، واستبدل تكوين PgBouncer وأرسل الأمر لإعادة التحميل.

كيف تنجو من حمولة عالية وتحافظ على الحد الأدنى من وقت التوقف عن العمل؟

كل شيء يعمل على أكمل وجه! لكن هناك أسئلة جديدة: كيف ستعمل في ظل أحمال عالية؟ كيف يتم طرح كل شيء في الإنتاج بسرعة وأمان؟

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

تبدو كلتا المهمتين طموحتين ، لكن لدينا PostgreSQL 9.6. هل يمكننا الترقية على الفور إلى 11.2؟

قررنا القيام بذلك في خطوتين: قم أولاً بالترقية إلى 2 ، ثم قم بتشغيل Patroni.

تحديث PostgreSQL

لتحديث إصدار PostgreSQL بسرعة ، استخدم الخيار -k، حيث يتم إنشاء روابط صلبة على القرص ولا داعي لنسخ بياناتك. على أساس 300-400 جيجابايت ، يستغرق التحديث ثانية واحدة.

لدينا الكثير من الأجزاء ، لذا يجب إجراء التحديث تلقائيًا. للقيام بذلك ، كتبنا دليل Ansible الذي يتعامل مع عملية التحديث بأكملها لنا:

/usr/lib/postgresql/11/bin/pg_upgrade 
<b>--link </b>
--old-datadir='' --new-datadir='' 
 --old-bindir=''  --new-bindir='' 
 --old-options=' -c config_file=' 
 --new-options=' -c config_file='

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

قم بتشغيل Patroni

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

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

rm -rf /var/lib/postgresql/

هذا يجب أن يتم فقط على العبد!

عندما يتم توصيل نسخة متماثلة نظيفة ، يقوم Patroni بعمل قائد للقاعدة الأساسية ويستعيدها إلى النسخة المتماثلة ، ثم يلحق بالحالة الحالية وفقًا لسجلات wal.

من الصعوبات الأخرى التي واجهناها أن جميع مجموعات PostgreSQL يتم تسميتها main بشكل افتراضي. عندما لا تعرف كل مجموعة شيئًا عن الأخرى ، فهذا أمر طبيعي. ولكن عندما تريد استخدام Patroni ، فيجب أن يكون لكل المجموعات اسم فريد. الحل هو تغيير اسم الكتلة في تكوين PostgreSQL.

اختبار الحمل

لقد أطلقنا اختبارًا يحاكي تجربة المستخدم على اللوحات. عندما وصل الحمل إلى متوسط ​​قيمتنا اليومية ، كررنا نفس الاختبار تمامًا ، وقمنا بإيقاف تشغيل مثيل واحد مع قائد PostgreSQL. نجح تجاوز الفشل التلقائي كما توقعنا: قام Patroni بتغيير القائد ، وقام Consul-template بتحديث تكوين PgBouncer وأرسل أمرًا لإعادة التحميل. وفقًا لرسوماتنا البيانية في Grafana ، كان من الواضح أن هناك تأخيرات تتراوح من 20 إلى 30 ثانية وكمية صغيرة من الأخطاء من الخوادم المرتبطة بالاتصال بقاعدة البيانات. هذا وضع طبيعي ، فهذه القيم مقبولة لتجاوز الفشل وهي بالتأكيد أفضل من وقت تعطل الخدمة.

جلب Patroni إلى الإنتاج

ونتيجة لذلك ، توصلنا إلى الخطة التالية:

  • نشر نموذج Consul على خوادم PgBouncer وبدء التشغيل ؛
  • تحديثات PostgreSQL للإصدار 11.2 ؛
  • تغيير اسم الكتلة ؛
  • بدء مجموعة Patroni.

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

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

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

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

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

أعد تشغيل كتلة باتروني

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

ERROR: get_cluster
Traceback (most recent call last):
...
RetryFailedError: 'Exceeded retry deadline'
ERROR: Error communicating with DCS
<b>LOG: database system is shut down</b>

لم تتمكن مجموعة Patroni من استرداد المعلومات حول مجموعتها وإعادة التشغيل.

للعثور على حل ، اتصلنا بمؤلفي Patroni عبر مشكلة على github. اقترحوا تحسينات على ملفات التكوين الخاصة بنا:

consul:
 consul.checks: []
bootstrap:
 dcs:
   retry_timeout: 8

تمكنا من تكرار المشكلة في بيئة اختبار واختبرنا هذه الخيارات هناك ، لكن للأسف لم تنجح.

لا تزال المشكلة دون حل. نخطط لتجربة الحلول التالية:

  • استخدام وكيل القنصل في كل مثيل لمجموعة Patroni ؛
  • أصلح المشكلة في الكود.

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

لحسن الحظ ، لم نواجه أية أخطاء أخرى.

نتائج استخدام باتروني

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

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

ملخص صغير لاستخدام Patroni:

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

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

إضافة تعليق