أخطاء نموذجية عند العمل مع PostgreSQL. الجزء 2

نواصل نشر مقاطع الفيديو ونصوص من أفضل التقارير من مؤتمر PGConf.Russia 2019 . في الجزء الأول من حديث إيفان فرولكوف ، كان الأمر يتعلق بالتسمية غير المتسقة ، والقيود ، وحول المكان الذي من الأفضل فيه تركيز المنطق - في قاعدة البيانات أو في التطبيق. في هذا الجزء ، ستجد تحليل الأخطاء في التحليل والوصول المتزامن والعمليات غير القابلة للإلغاء و CTE و JSON.



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



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

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

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



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



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



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

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



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

لذا: لا تصطدم بالخطأ الذي لا تعرف ماذا تفعل ؛ أخطاء اسم بعناية وبدقة. تصنيف الأخطاء.



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

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



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

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



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

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



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

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



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



مثال على الشريحة: يجب تنفيذ مثل هذه العملية على مرحلتين: كما لو كان تحذيرًا - "سنفعل شيئًا الآن" ؛ العملية نفسها.



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


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


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





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



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

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



- كيفية التحقق عندما يعمل العديد من المستخدمين مع سلسلة؟ ما هي الخيارات المتاحة؟

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

- أنت تقول إن القيود يجب أن تسمى الأسماء الجيدة حتى يتمكن المستخدم من فهم ما يحدث. لكن يوجد حد 60 حرف لكل اسم قيد. هذا في كثير من الأحيان لا يكفي. كيف تتعامل معها؟

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

- في التقرير ، أنت مفتون بحقيقة أننا بحاجة إلى القيام بشيء ما مع المحفوظات. ما الآلية التي تعتبر الأكثر صحة للأرشفة التي عفا عليها الزمن؟

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


التوقيت: يبدأ الجزء 2 من التقرير في الساعة 25:16

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

- بالضبط الإجراء؟ أم أنها صفقة كافية؟

- هذا هو الإجراء الذي يسمى في بعض المعاملات.

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

- ما زلت أرغب في العودة مرة أخرى إلى بيانات الأرشيف. تحدثت عنه
أرشفة خيارات التخزين بحيث تتوفر أيضًا بيانات من التطبيق. لقد حدث لي ببساطة إنشاء قاعدة بيانات أرشيف منفصلة. ما هي الخيارات الأخرى هناك؟

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

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

"بالطبع ، لماذا لا". أنا أفسح المجال للمتكلم التالي.

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


All Articles