
يشعر مطورو نظم إدارة قواعد البيانات ، بحكم الضرورة ، بالقلق من أن البيانات تندرج بأمان في التخزين الدائم. لذلك ، عندما اكتشف مجتمع PostgreSQL أن الطريقة التي يتعامل بها kernel مع أخطاء I / O يمكن أن تؤدي إلى فقد البيانات دون الإبلاغ عن أي أخطاء في مساحة المستخدم ، نشأ الكثير من الاستياء. المشكلة ، التي تتفاقم بسبب حقيقة أن PostgreSQL تنفذ I / O المخزنة مؤقتًا ، ليست فريدة من نوعها على نظام Linux ، ولن يكون من السهل حلها حتى هناك.
قام كريج رينجر أولاً
بإبلاغ القائمة البريدية للمتسللين بـ pgsql في أواخر مارس. باختصار ، يفترض PostgreSQL أن استدعاء
fsync()
ناجح يشير إلى أن جميع البيانات المسجلة منذ آخر مكالمة ناجحة تم نقلها بأمان إلى سعة تخزين ثابتة. عندما تفشل عمليات كتابة الإدخال / الإخراج المخزنة مؤقتًا بسبب خطأ في الأجهزة ، تتفاعل أنظمة الملفات بشكل مختلف ، لكن هذا السلوك عادةً ما يتضمن حذف البيانات على الصفحات المقابلة ووضع علامات عليها نظيفة. لذلك ، فإن قراءة الكتل التي تم كتابتها للتو سترجع على الأرجح شيئًا آخر ، لكن لا يتم تسجيل البيانات.
ماذا عن الإبلاغ عن الخطأ؟ قبل عام ، تضمنت قمة نظام ملفات Linux والتخزين وإدارة الذاكرة (LSFMM)
جلسة تقرير عن الأخطاء وصفت بأنها "فوضى" ؛ يمكن أن تضيع الأخطاء بسهولة ، لذلك لن يراها أي تطبيق على الإطلاق. حسّنت
بعض التصحيحات المدرجة في 4.13 الموقف إلى حد ما خلال دورة التطوير (وفي 4.16 كانت هناك بعض التغييرات لتحسينه) ، ومع ذلك ، هناك طرق لفقد إخطارات الخطأ ، كما هو موضح أدناه. إذا حدث هذا على خادم PostgreSQL ، فقد يؤدي ذلك إلى تلف قاعدة البيانات تلقائيًا.
كان مطورو PostgreSQL غير راضين.
وصف توم لين هذا بأنه "
تلف في الدماغ للنواة "
، بينما
وصفه روبرت هاس
بأنه "
غبي 100 ٪ ". في بداية المناقشة ، أدرك مطورو PostgreSQL بوضوح تام كيف ، في رأيهم ، يجب أن تعمل النواة: يجب تخزين الصفحات التي لا يمكن كتابتها في الذاكرة في حالة "قذرة" (للمحاولات اللاحقة) ، ويجب ترجمة واصف الملف المقابل إلى حالة خطأ دائمة حتى لا يتمكن خادم PostgreSQL من تخطي المشكلة.
أين حدث خطأ ما
ومع ذلك ، حتى قبل دخول مجتمع النواة في المناقشة ، أصبح من الواضح أن الوضع لم يكن بسيطًا كما يبدو.
قال توماس مونرو
إن Linux ليس فريدًا في هذا السلوك ؛ قد لا يُبلغ OpenBSD و NetBSD عن أخطاء الكتابة في مساحة المستخدم. وكما اتضح فيما بعد ، فإن الطريقة التي يتعامل بها PostgreSQL مع عمليات الإدخال / الإخراج المخزنة مؤقتًا تعقد الصورة بشكل كبير.
تم وصف هذه الآلية
بالتفصيل من قبل هاس. يعمل خادم PostgreSQL كمجموعة من العمليات ، والتي يمكن للكثير منها القيام بإدخال / إخراج على ملفات قاعدة البيانات. ومع ذلك ، تتم معالجة
fsync()
الاستدعاء
fsync()
في عملية واحدة (علامة "checkpointer عملية" checkpointer) ، وهي عبارة عن الحفاظ على تخزين القرص في حالة متسقة لاسترداد من الفشل. لا يقوم Checkpointer عادةً بإبقاء كافة الملفات ذات الصلة مفتوحة ، لذلك يجب فتح الملف قبل استدعاء
fsync()
. هذا هو المكان الذي تثار فيه المشكلة: حتى في kernels 4.13 والإصدارات الأحدث ، لن يرى checkpointer أي أخطاء حدثت قبل فتح الملف. إذا حدث شيء سيء قبل استدعاء checkpointer-a
open()
،
fsync()
المكالمة التالية إلى
fsync()
بالنجاح. هناك عدة طرق لإحداث خطأ I / O خارج
fsync()
؛ على سبيل المثال ، قد تصادف النواة أحدها أثناء القيام بإعادة كتابة الخلفية. قد يواجه شخص ما يتصل
sync()
خطأ في الإدخال / الإخراج و "يمتص" حالة الخطأ الناتجة.
وصف هاس هذا السلوك بأنه غير قادر على تلبية توقعات PostgreSQL:
كل ما تمتلكه أنت (أو أي شخص آخر) هو افتراض غير مثبت في الأساس
ما هي واصفات الملفات التي قد تكون ذات صلة بخطأ معين ، ولكن حدث ذلك أن PostgreSQL لم يطابقها مطلقًا. يمكنك الاستمرار في القول إن المشكلة تكمن في تخميناتنا ، لكن يبدو لي مخطئًا في افتراض أننا البرنامج الوحيد الذي قام بها على الإطلاق.
نتيجة لذلك ،
نقل Joshua Drake
المحادثة إلى قائمة التطوير لـ ext4 ، بما في ذلك جزء من مجتمع تطوير kernel.
وصف Dave Chinner هذا السلوك بسرعة
بأنه "
وصفة لكارثة ، خاصة في التعليمات البرمجية عبر النظام الأساسي ، حيث تتصرف كل منصة نظام تشغيل بشكل مختلف ولا تتطابق أبدًا مع ما كان متوقعًا ." بدلاً من ذلك ،
أوضح Ted Tso سبب تمييز الصفحات المتأثرة على أنها نظيفة بعد حدوث خطأ في الإدخال / الإخراج ؛ باختصار ، السبب الأكثر شيوعًا لأخطاء الإدخال / الإخراج هو عندما يخرج المستخدم محرك USB في الوقت الخطأ. إذا نسخت عملية ما الكثير من البيانات على هذا القرص ، فستكون النتيجة هي تراكم الصفحات المتسخة في الذاكرة ، ربما لدرجة أن النظام لا يملك ذاكرة كافية للقيام بمهام أخرى. وبالتالي ، لا يمكن حفظ هذه الصفحات وسيتم محوها إذا أراد المستخدم أن يظل النظام صالحًا للاستخدام بعد هذا الحدث.
قال كل من Chinner و Tso ، إلى جانب آخرين ، أن PostgreSQL لديها الحل الصحيح - التبديل إلى I / O (DIO) المباشر. باستخدام DIO يعطي مستوى أكبر من التحكم على Writeback و I / O بشكل عام؛ يتضمن ذلك الوصول إلى المعلومات حول عمليات الإدخال / الإخراج التي قد تكون فشلت.
اعترف Andres Freund ، مثله مثل عدد من مطوري PostgreSQL الآخرين ،
بأن DIO هو الحل الأفضل على المدى الطويل. لكنه أشار أيضًا إلى أنه لا ينبغي لأحد أن يتوقع من المطورين أن يغطوا بعمق في تنفيذ هذه المهمة. في الوقت نفسه ،
قال إن هناك برامج أخرى (ذكر dpkg) عرضة أيضًا لهذا السلوك.
نحو حل قصير الأجل
أثناء المناقشة ، تم
إيلاء اهتمام كبير لفكرة أن فشل الكتابة يجب أن يؤدي إلى حقيقة أن الصفحات المتأثرة سيتم تخزينها في الذاكرة في حالتها القذرة. لكن مطوري PostgreSQL ابتعدوا بسرعة عن هذه الفكرة ولم يطلبوها. ما يحتاجونه حقًا هو في نهاية المطاف طريقة يمكن الاعتماد عليها لمعرفة ما إذا حدث خطأ ما. مع وضع ذلك في الاعتبار ، يمكن لآليات التعامل مع الأخطاء في PostgreSQL المعتادة التعامل مع هذا ؛ ومع ذلك ، لا يمكن فعل الكثير في غيابه.
في مرحلة ما من المناقشة ،
ذكرت Tso أن Google لديها آلية معالجة الأخطاء في الإدخال / الإخراج الخاصة بها. تم توجيه النواة للإبلاغ عن أخطاء الإدخال / الإخراج من خلال مأخذ توصيل netlink ؛ عملية مخصصة يتلقى هذه الإخطارات ويستجيب وفقا لذلك. لكن هذه الآلية لم تفعل ذلك مطلقًا عند المدخل.
أشار Freind
إلى أن هذه الآلية ستكون "مثالية" لـ PostgreSQL ، لذلك قد تظهر في المجال العام في المستقبل القريب.
وفي الوقت نفسه ، كان جيف لايتون
يفكر في فكرة أخرى: تعيين علامة في الكتلة الفائقة لنظام الملفات عند حدوث خطأ في الإدخال / الإخراج.
syncfs()
مكالمة
syncfs()
بعد ذلك بمسح هذه العلامة وإرجاع خطأ إذا تم تعيينها. يمكن
syncfs()
PostgreSQL الاتصال بشكل دوري بـ
syncfs()
عن الأخطاء في نظام الملفات الذي يحتوي على قاعدة البيانات.
وافق فروند
على أن هذا يمكن أن يكون حلاً قابلاً للتطبيق للمشكلة.
بالطبع ، لن تظهر أي آلية من هذا القبيل إلا في حبات جديدة ؛ وفي الوقت نفسه ، تعمل عمليات تثبيت PostgreSQL عادة على حبيبات قديمة تدعمها توزيعات المؤسسة. في هذه الألبومات ، يبدو أنه لا توجد حتى تلك التحسينات التي تم تضمينها في 4.13. بالنسبة لهذه الأنظمة ، لا يمكن فعل الكثير لمساعدة PostgreSQL على اكتشاف أخطاء I / O. قد يكون كافياً لبدء البرنامج الخفي الذي يقوم بمسح سجل النظام والبحث عن رسائل خطأ الإدخال / الإخراج هناك. ليس هو الحل الأكثر أناقة ، ومما يزيد من تعقيده حقيقة أن برامج تشغيل البلوكات وأنظمة الملفات المختلفة ، كقاعدة عامة ، تبلغ عن الأخطاء بطرق مختلفة ، ولكن هذا قد يكون الخيار الأفضل المتاح.
من المحتمل أن تكون الخطوة التالية مناقشة في حدث LSFMM 2018 في 23 أبريل. إذا كنت محظوظًا ، سيكون هناك نوع من الحلول التي ستعمل مع الأطراف المعنية. ومع ذلك ، هناك شيء واحد لن يتغير وهو الحقيقة البسيطة المتمثلة في أن معالجة الأخطاء يصعب القيام بها بشكل صحيح.