لن تتحدث المقالة عن موظفين غير مسؤولين ، كما قد يقترح المرء من عنوان المقال. سنناقش خطرًا فنيًا حقيقيًا واحدًا قد ينتظرك إذا قمت بإنشاء أنظمة موزعة.
في نظام Enterprise واحد ، كان هناك مكون. جمع هذا المكون بيانات من المستخدمين حول منتج معين وتسجيله في بنك البيانات. وتألفت من ثلاثة أجزاء قياسية: واجهة المستخدم ، منطق الأعمال على الخادم والجداول في قاعدة البيانات.
كان المكون يعمل بشكل جيد ، ولم يمس أحد الكود منذ عدة سنوات.
ولكن مرة واحدة ، دون سبب ، بدأت أشياء غريبة تحدث للمكون.
عند العمل مع بعض المستخدمين ، بدأ أحد المكونات في منتصف الجلسة في رمي الأخطاء بشكل مفاجئ. حدث ذلك بشكل غير متكرر ، ولكن كالمعتاد ، في أكثر اللحظات غير مناسبة. وما هو غير مفهوم ، ظهرت الأخطاء الأولى في إصدار ثابت من النظام في الإنتاج. في الإصدار الذي لعدة أشهر لم يتم تغيير أي مكونات على الإطلاق.
بدأنا في تحليل الوضع ، وتحققنا من المكون تحت عبء ثقيل. انها تعمل بشكل جيد. تكرار اختبارات التكامل واسعة النطاق. في اختبارات التكامل ، عمل المكون لدينا بشكل جيد.
في كلمة واحدة ، الخطأ جاء غير واضح متى وغير واضح أين.
بدأوا في حفر أعمق. أظهر التحليل والمقارنة التفصيلية لملفات السجل أن سبب ظهور رسائل الخطأ المعروضة للمستخدم هو انتهاك القيد في المفتاح الأساسي في الجدول المذكور بالفعل في قاعدة البيانات.
قام المكون بكتابة بيانات إلى الجدول باستخدام Hibernate ، وأحيانًا Hibernate ، عند محاولة كتابة الصف التالي ، أبلغ عن انتهاك قيد.
لن أحمل القراء بمزيد من التفاصيل الفنية وأخبرك فورًا عن جوهر الخطأ. اتضح أنه ليس فقط مكون لدينا يكتب إلى الجدول أعلاه ، ولكن في بعض الأحيان (نادرا للغاية) بعض المكونات الأخرى. وهي تقوم بذلك بكل بساطة ، باستخدام عبارة SQL INSERT بسيطة. يعمل السبات افتراضيًا عند الكتابة كما يلي. لتحسين عملية الكتابة ، يستعلم عن فهرس المفتاح الأساسي التالي مرة واحدة في الفهرس ، ثم يكتب عدة مرات ببساطة زيادة قيمة المفتاح (10 مرات افتراضيًا). وإذا حدث ذلك ، بعد الطلب ، تعطل المكون الثاني في العملية وكتب البيانات إلى الجدول باستخدام قيمة المفتاح الأساسي التالية ، ثم أدت المحاولة التالية للكتابة من السبات إلى انتهاك القيد.
إذا كنت مهتمًا بالتفاصيل الفنية ، فراجعها أدناه.
التفاصيل الفنية.
رمز الفصل بدأ مثل هذا:
@Entity @Table(name="PRODUCT_XXX") public class ProductXXX { @Id @Basic(optional=false) @Column( name="PROD_ID", columnDefinition="integer not null", insertable=true, updatable=false) @SequenceGenerator( name="GEN_PROD_ID", sequenceName="SEQ_PROD_ID", allocationSize=10) @GeneratedValue( strategy=GenerationType.SEQUENCE, generator="GEN_PROD_ID") private long prodId;
مناقشة واحدة لمشكلة مماثلة على Stackoverflow:
https://stackoverflow.com/questions/12745751/hibernate-sequencegenerator-and-allocationsize وحدث ذلك أنه لعدة أشهر بعد تغيير المكون الثاني وتطبيق الإدخالات في الجدول فيه ، لم تتداخل عمليات كتابة المكونين الأول والثاني في الوقت المناسب. وبدأوا في التقاطع عندما تغير جدول العمل قليلاً في إحدى الوحدات التي تستخدم النظام.
حسنًا ، تمت اختبارات التكامل بسلاسة ، لأن الفواصل الزمنية لاختبار كلا المكونين داخل اختبارات التكامل لم تتقاطع أيضًا.
بطريقة ما ، يمكننا أن نقول أنه لم يكن هناك من يتحمل مسؤولية الخطأ.
أم أنها ليست كذلك؟
الملاحظات والأفكار
بعد اكتشاف السبب الحقيقي للخطأ ، تم تصحيحه.
لكن ليس بهذه النهاية السعيدة ، أود أن أنهي هذه المقالة ، لكنني أفكر في هذا الخطأ كممثل لفئة الأخطاء الواسعة التي اكتسبت شعبية بعد الانتقال من الأنظمة المتجانسة إلى الأنظمة الموزعة.
من وجهة نظر المكونات أو الخدمات الفردية في نظام Enterprise المبين ، تم تنفيذ كل شيء على ما يبدو. جميع المكونات ، أو الخدمات ، لها دورات حياة مستقلة. وعندما تنشأ الحاجة إلى الكتابة إلى الجدول في المكون الثاني ، بسبب عدم أهمية العملية ، تم اتخاذ قرار عملي لتنفيذ هذا مباشرة في هذا المكون بأبسط الطرق ، وعدم لمس المكون الأول العامل المستقر.
ولكن للأسف ، ما حدث غالبًا في الأنظمة الموزعة (وفي كثير من الأحيان أقل نسبيًا في الأنظمة المتجانسة) حدث: تم نشر مسؤولية تنفيذ العمليات على كائن معين بين الأنظمة الفرعية. بالتأكيد ، إذا تم تنفيذ عمليتي الكتابة في نفس الخدمة المصغرة ، فسيتم اختيار تقنية واحدة لتنفيذها. ثم الخطأ الموصوف لن يحدث.
ساعدت النظم الموزعة ، وخاصة مفهوم الخدمات المجهرية ، بشكل فعال في حل عدد من المشكلات الكامنة في الأنظمة المتجانسة. ومع ذلك ، من المفارقات أن فصل المسؤوليات عن الخدمات الفردية يثير التأثير المعاكس. مكونات الآن "العيش" مستقلة قدر الإمكان. ومن المحتم أن يكون هناك إغراء ، إجراء تغييرات كبيرة على أحد المكونات ، "لتثبيتها هنا" بقليل من الوظائف التي يمكن تنفيذها بشكل أفضل في مكون آخر. هذا يحقق بسرعة التأثير النهائي ، ويقلل من حجم الموافقات والاختبار. لذلك ، من التغيير إلى التغيير ، يتم تضخيم المكونات بميزات غير عادية بالنسبة لها ، يتم تكرار نفس الخوارزميات والوظائف الداخلية ، وينشأ تعدد المشكلات في حل المشكلات (وأحيانًا غير الحتمية). بمعنى آخر ، يتحلل النظام الموزع بمرور الوقت ، ولكن بشكل مختلف عن النظام المترابط.
تعد مسؤولية "تلطيخ" المكونات في الأنظمة الكبيرة التي تتكون من العديد من الخدمات إحدى المشكلات النموذجية والمؤلمة للأنظمة الموزعة الحديثة. الموقف أكثر تعقيدًا وإرباكًا من قِبل أنظمة التحسين الفرعية المشتركة مثل التخزين المؤقت والتنبؤ بالعمليات التالية (التنبؤ) ، بالإضافة إلى تزامن الخدمات ، إلخ.
مركزية الوصول إلى قاعدة البيانات ، على الأقل على مستوى مكتبة واحدة ، الشرط واضح تماما. ومع ذلك ، فإن العديد من الأنظمة الموزعة الحديثة نمت تاريخياً حول قواعد البيانات وتستخدم البيانات المخزنة فيها مباشرة (عبر SQL) بدلاً من خدمات الوصول.
"المساعدة" في نشر المسؤولية وأطر ORM والمكتبات مثل السبات. باستخدامهم ، يريد العديد من مطوري خدمات الوصول إلى قاعدة البيانات عن غير قصد إعطاء أكبر عدد ممكن من الكائنات كنتيجة للطلب. مثال نموذجي هو طلب بيانات المستخدم لعرضه في الترحيب أو في الحقل مع نتيجة المصادقة. بدلاً من إرجاع اسم المستخدم في شكل ثلاثة متغيرات نصية (first_name ، mid_name ، last_name) ، غالباً ما يُرجع هذا الطلب كائن مستخدم كامل العناصر مع عشرات من السمات والكائنات المتصلة ، مثل قائمة أدوار المستخدم المطلوب. يؤدي هذا بدوره إلى تعقيد منطق معالجة نتيجة الطلب وإنشاء التبعيات غير الضرورية للمعالج على نوع الكائن المرتجع و ... يثير انتشار المسؤولية بسبب إمكانية تنفيذ المنطق المرتبط بالكائن من الخارج المسؤول عن كائن الخدمة.
ماذا تفعل؟ (المراجع)
للأسف ، يتم أحيانًا فرض تشويه المسؤولية في بعض الحالات ، وحتى في بعض الأحيان لا مفر منه ومبرر.
ومع ذلك ، إن أمكن ، يجب أن تحاول الامتثال لمبدأ توزيع المسؤولية بين المكونات. عنصر واحد هو مسؤولية واحدة.
حسنًا ، إذا كان من المستحيل تركيز العمليات على كائنات معينة بشكل صارم في نظام واحد ، فيجب أن يتم تسجيل هذه التلطيخ بعناية فائقة في الوثائق ("المكون الفائق") على مستوى المنظومة باعتبارها الاعتماد المحدد للمكونات على عنصر البيانات ، أو كائن المجال ، أو على بعضها البعض.
سيكون من المثير للاهتمام معرفة رأيك في هذا الأمر ، وكذلك حالات من الممارسة تؤكد أو تدحض أطروحات هذه المقالة.
شكرا لك على قراءة المقال حتى النهاية.
التوضيح "الوسائط المتعددة Mikher" من قبل مؤلف المقال.