MongoDB إلى Postgres
ملاحظة: هذه التدوينة هي دمج بين MongoDB to Postgres (2024-03-06) و Sequelize vs. Prisma (2023-05-25). تمت إزالة المدونات الأصلية، وحلّت هذه التدوينة محلها لأن كليهما كان يحتوي أساسًا على المحتوى/المعلومات نفسها. بدأت عملية النقل في أوائل مارس 2023، وحدث التحول في منتصف نوفمبر 2023، وتم إيقاف جميع مثيلات نظام MongoDB القديم بالكامل في أوائل يناير 2024.
مقدمة
خلال فترة عملي في eBay، واجهت ما أصبح أكثر مشكلة تقنية تحديًا في مسيرتي المهنية: نقل نظام إدارة التخزين (STMS) من MongoDB إلى Postgres. لم يكن هذا مجرد تبديل بسيط لقواعد البيانات؛ بل كان تحولًا معماريًا كاملًا لنظام حيوي يستوعب أكثر من 1.5 مليون مقياس في الدقيقة عبر مراكز بيانات eBay، مع اشتراط عدم وجود أي توقف والحفاظ على جميع الوظائف الموجودة تقريبًا.
ما هو STMS؟
يُعد نظام إدارة التخزين (STMS) أداة داخلية حيوية لفريق البنية التحتية للخدمات والتخزين (SSI) في eBay. وهو يراقب الأجهزة ويديرها عبر مراكز بيانات eBay، مما يتيح للمهندسين:
- مراقبة المقاييس من عشرات المصفوفات، والمبدلات، والمضيفين، ومجموعات الأقراص، والعناقيد
- التعامل مع التنبيهات الخاصة بالمبدلات والمصفوفات
- إنجاز المهام المتقدمة مثل تخصيصات المضيفين
- الوصول إلى البيانات اللحظية لخدمات eBay الداخلية الأخرى
يضم STMS أكثر من 70 مصفوفة، و60 مبدلًا، و1100 مضيف، و900 مجموعة أقراص، و200 عنقود عبر 3 من مراكز بيانات eBay. ونظرًا لدوره الحيوي في بنية eBay التحتية، فإن أي توقف أو فقدان للوظائف سيؤثر مباشرةً في الخدمات الأساسية للشركة وعملياتها التجارية.
التحدي
لماذا كانت عملية النقل ضرورية
لم يكن قرار الانتقال من MongoDB إلى Postgres قرارًا يُتخذ باستخفاف. فعلى الرغم من أن MongoDB قد خدم STMS جيدًا في البداية، فإن التعقيد المتزايد لعلاقات بياناتنا والحاجة إلى قدرات استعلام أكثر تطورًا جعلا Postgres حلًا أفضل على المدى الطويل لحالة الاستخدام لدينا.
ما الذي جعل هذه المشكلة صعبة
انبثق تعقيد هذه العملية من عدة تحديات أساسية:
1. الاختلافات الأساسية بين قواعد البيانات MongoDB وPostgres قاعدتا بيانات مختلفتان جذريًا. MongoDB هي قاعدة بيانات قائمة على المستندات (NoSQL)، ما يعني أن البيانات تُخزن بصيغة JSON داخل مجموعات، مثل المستندات في خزانة ملفات. أما Postgres فهي قاعدة بيانات علائقية (SQL)، ما يعني أن البيانات تُخزن على هيئة صفوف داخل جداول، مثل جدول بيانات.
2. بنية قاعدة الشيفرة كان الطرف الخلفي الكامل لـ STMS مبنيًا لمعالجة البيانات وإدارتها على شكل ملفات JSON، باستخدام حزم متوافقة حصريًا مع MongoDB لعمليات قاعدة البيانات. وهذا يعني أن التغيير لم يكن مجرد تغيير قاعدة البيانات، بل إعادة هيكلة الطريقة التي يتعامل بها التطبيق بالكامل مع البيانات.
3. متطلب عدم وجود توقف نظرًا لمدى أهمية STMS كأداة داخلية، لم يكن بالإمكان حدوث أي توقف أثناء عملية النقل. كان على النظام الاستمرار في خدمة أكثر من 1.5 مليون مقياس في الدقيقة طوال العملية بأكملها.
4. الجدول الزمني الضيق والخبرة المحدودة كان لا بد من إكمال عملية النقل خلال بضعة أشهر، دون وجود خطة تنفيذ واضحة في البداية. لم يكن لديّ أنا أو زملائي خبرة في نقل قاعدة شيفرة قديمة كبيرة من قواعد بيانات NoSQL إلى SQL، وكانت خبرتي السابقة مع Postgres محدودة.
5. الحجم والتعقيد تضمنت عملية النقل تحويل 36 مجموعة MongoDB إلى 74 جدولًا في Postgres، مع الحاجة إلى دراسة دقيقة للعلاقات والفهرسة وتحسين الاستعلامات.
اختيار أداة ORM المناسبة: Sequelize مقابل Prisma
كان أحد أول القرارات الكبرى هو اختيار أداة ORM (تعيين الكائنات العلائقية). وبما أن قاعدة الشيفرة لدينا كانت مصممة بالفعل لاستخدام Mongoose مع MongoDB، فإن استخدام ORM كان سيوفر مسار انتقال أكثر سلاسة.
تحليل المتطلبات
بعد تحليل دقيق لاحتياجات المشروع، وضعت معايير أساسية لأي حل ORM:
- يجب أن تكون حزمة JavaScript (معظم شيفرتنا كانت مكتوبة بـ JavaScript)
- يجب أن تدعم Postgres ومعظم ميزاتها
- يجب أن تكون الأداء على الأقل بمستوى Mongoose أو أفضل
- يجب أن تكون مفتوحة المصدر ومصانة
المرشحان
بعد بحث موسع، حصرْتُ الخيارات في منافسين رئيسيين: Sequelize وPrisma. أنشأتُ بيئات اختبار شاملة باستخدام Docker لـ Postgres، وحولتُ أكبر مجموعة بيانات لدينا وأكثرها تعقيدًا من بنية المستندات إلى بنية الجداول.
منهجية الاختبار
لكل ORM، قست الأداء عبر عمليات حاسمة:
- الوقت اللازم لإنشاء مدخلة
- الوقت اللازم لتحديث مدخلة
- الوقت اللازم لتحديث المدخلات المتداخلة (العلاقات وأزواج JSON المفتاح/القيمة)
- الوقت اللازم لحذف مدخلة
- الوقت اللازم للاستعلام/جلب مدخلة
القرار: Sequelize
حوالي 15 مايو 2023، قررت أن Sequelize هو الـ ORM الأفضل لحالة الاستخدام لدينا. وهذه هي الأسباب:
مزايا Sequelize:
- مفتوح المصدر فعلًا وليس مدعومًا من شركة ناشئة ممولة
- يدعم معظم ميزات Postgres
- أداء أفضل، خاصةً مقارنةً بـ Prisma
- منظومة ناضجة مع أكثر من 10 سنوات من التطوير
- تمثيل مرن للنماذج/المخططات باستخدام فئات JavaScript
- دعم الاستعلامات المعقدة والدمج والتصفية بما في ذلك Regex
نتائج الأداء:
في اختباري، تفوق Sequelize بشكل ملحوظ على Prisma. بالنسبة إلى مدخلات مجموعة البيانات الكبيرة لدينا:
- Sequelize: نحو 2.26 ثانية لكل مدخلة
- Prisma: نحو 11.21 ثانية لكل مدخلة
كان Prisma أبطأ بنحو 5 مرات من Sequelize بالنسبة إلى حالة الاستخدام لدينا. بالإضافة إلى ذلك، استغرق حذف مدخلة واحدة من أكبر مجموعات البيانات لدينا من Prisma ما يقرب من 4 دقائق، وهو أمر غير مقبول لمتطلباتنا.
تحديات Sequelize:
- تمثيلات النماذج أكثر تعقيدًا وانتفاخًا (564 سطرًا مقابل 262 سطرًا في Mongoose)
- صياغة مربكة في بعض الحالات
- تعقيد ترحيل قاعدة البيانات
- توثيق أقل شمولًا مقارنةً بـ Prisma
مقارنة المزايا والعيوب بين Sequelize وPrisma
لإعطاء صورة أكمل عن سبب اختياري لـ Sequelize، أود مشاركة المزايا والعيوب التفصيلية التي جمعتها لكلا الـ ORM أثناء التقييم. كما نظرتُ إلى كيفية مقارنتهما من حيث تمثيل المخطط ودعم المجتمع حتى 15 مايو 2023. هذا التعمق ساعدني على ترسيخ اختياري، وأرجو أن يكون مفيدًا لأي شخص آخر يواجه قرارًا مشابهًا.
مزايا Sequelize:
- يحتوي على دالة sync() تنشئ الجداول وتعالجها تلقائيًا، مما يوفر الكثير من الجهد اليدوي.
- يمكنه التعامل مع عمليات الدمج المعقدة للبيانات المتداخلة، وهو أمر كان بالغ الأهمية لبنية STMS.
- يدعم نطاقًا واسعًا من خيارات التصفية، بما في ذلك Regex، ما يمنح مرونة في الاستعلامات.
- يتم تمثيل النماذج/المخططات بلغة JavaScript الخام باستخدام الفئات، وهي قابلة للتخصيص بدرجة كبيرة لتناسب الاحتياجات المحددة.
- يتعامل مع اتصالات قاعدة البيانات بسلاسة، بما في ذلك دعم اتصالات القراءة المتعددة.
- يدعم استعلامات SQL الخام عندما تحتاج إلى التعمق تحت الغطاء.
- إحصاءات المجتمع حتى 15 مايو 2023: على NPM، آخر تحديث قبل 14 يومًا مع 1,505,835 تنزيلًا أسبوعيًا؛ وعلى GitHub، آخر تحديث بالأمس مع 4.2k Forks و27.9k Stars. لقد كان مفتوح المصدر برخصة MIT لأكثر من 10 سنوات، لذا أنا واثق من أنه سيبقى كذلك.
عيوب Sequelize:
- قد يصبح تمثيل النماذج/المخططات معقدًا وممتلئًا للغاية. فعلى سبيل المثال، بينما كان تمثيل Mongoose لمجموعة البيانات الكبيرة لدينا نحو 262 سطرًا (بما في ذلك المسافات)، تضخم نفس النموذج في Sequelize إلى 564 سطرًا.
- قد تكون الصياغة مربكة ومعقدة في بعض السيناريوهات، مما أبطأني أحيانًا.
- ترحيل قاعدة البيانات أو تعديلها مرهق. وحتى مع قيام sequelize-cli بتوليد نصوص الترحيل، فإنه يظل متعبًا، رغم أنني لاحظت أن هذا نقطة ألم شائعة في معظم أدوات ORM.
- التوثيق ليس رائعًا، رغم أنه يتحسن. لحسن الحظ، فإن أدوات مثل ChatGPT لديها فهم جيد لـ Sequelize بسبب تاريخه الطويل، مما ساعد في سد الثغرات.
- ليس حساسًا للأنواع بقدر Prisma، مما قد يؤدي إلى مشكلات في بعض المشاريع.
- دعم TypeScript محدود، ورغم أن هذا لم يكن مشكلة بالنسبة إلى STMS، فقد يكون عاملًا حاسمًا للآخرين.
مزايا Prisma:
- يستخدم لغة مخطط خاصة به، مما يجعل إنشاء النماذج أنظف وأكثر إيجازًا. وللمقارنة، بينما استغرق Mongoose 262 سطرًا لمجموعة البيانات الكبيرة لدينا، أنجز Prisma ذلك في 221 سطرًا فقط.
- يأتي مع أداة CLI تبسط إنشاء قاعدة البيانات وترحيلها، وهي الأفضل التي رأيتها حتى الآن من ORM، حتى لو لم تكن مثالية.
- يدعم استعلامات SQL الخام، مما يوفر مرونة عند الحاجة.
- صياغة الشيفرة نظيفة وأسهل في الفهم مقارنةً بـ Sequelize، مما يجعل تعلمه أسهل.
- يولد تلقائيًا منشئي الاستعلامات لـ Node.js وTypeScript عبر العميل الخاص به، وهي لمسة لطيفة.
- لديه توثيق ممتاز ونظيف. ChatGPT ليس محدثًا بدرجة كافية بشأن Prisma، لكن الوثائق الرسمية غالبًا ما عوضت عن ذلك.
- إحصاءات المجتمع حتى 15 مايو 2023: على NPM، آخر تحديث قبل 6 أيام مع 1,344,705 تنزيلًا أسبوعيًا؛ وعلى GitHub، آخر تحديث قبل 3 ساعات مع 1.1k Forks و31.3k Stars.
عيوب Prisma:
- لا يدعم التصفية بـ Regex لـ Postgres، رغم أنه يقدم بدائل مثل “contains” و"includes" و"startsWith."
- كان الأداء مشكلة كبيرة في اختباراتي. إنشاء المدخلات لمجموعة البيانات الكبيرة لدينا استغرق من Prisma حوالي 11.21 ثانية لكل مدخلة مقابل 2.26 ثانية في Sequelize، أي أبطأ بنحو 5 مرات.
- حذف مدخلة واحدة من مجموعة البيانات الكبيرة استغرق ما يقرب من 4 دقائق، وهو أمر كان سببًا كافيًا للاستبعاد بالنسبة لاحتياجاتنا.
- حتى مع مقارنة عادلة على مجموعة بيانات ذات علاقة معقدة بثلاث طبقات، كان Sequelize أسرع بكثير في عمليات الحذف.
- يدعم Prisma شركة ناشئة حصلت على تمويل بقيمة 56.5 مليون دولار. وعلى الرغم من أن الشيفرة الأساسية للـ ORM مفتوحة المصدر تحت Apache-2.0، فإنني أتوجس من احتمال حدوث تغييرات في الترخيص لاحقًا، على غرار ما حدث مع MongoDB.
جعلتني هذه المقارنات التفصيلية أدرك أن Sequelize كان أكثر توافقًا مع احتياجات STMS، خاصةً من حيث الأداء والموثوقية طويلة الأجل. لكنني وجدت أن عرض الأمر بهذا الشكل قد يساعد الآخرين الذين يواجهون الاختيار نفسه في مشاريعهم.
عملية الترحيل
تحويل بنية البيانات
كان التحويل من بنية المستندات في MongoDB إلى البنية العلائقية في Postgres يتطلب تخطيطًا دقيقًا. كان عليّ:
- تحليل العلاقات: تحديد كيفية ارتباط مستندات MongoDB بعضها ببعض وتصميم علاقات مفاتيح خارجية مناسبة
- تطبيع البيانات: تقسيم المستندات المتداخلة إلى جداول منفصلة حيثما كان ذلك مناسبًا
- الحفاظ على ميزات JSON: استخدام أعمدة JSONB للبيانات غير المهيكلة حقًا التي كان ينبغي أن تظل مرنة
- تصميم الفهارس: إنشاء فهارس مناسبة لأداء الاستعلامات
الحلول المخصصة
تطلّب الترحيل تطوير عدة حلول مخصصة:
1. نصوص ترحيل البيانات أنشأت نصوصًا شاملة من أجل:
- استخراج البيانات من مجموعات MongoDB
- تحويل هياكل المستندات إلى صيغة علائقية
- استيراد البيانات إلى جداول Postgres مع العلاقات المناسبة
2. طبقة توافق واجهة برمجة التطبيقات للحفاظ على عدم وجود أي توقف، بنيت طبقة توافق يمكنها:
- توجيه الطلبات إلى MongoDB أو Postgres حسب حالة الترحيل
- ضمان اتساق البيانات خلال فترة الانتقال
- توفير آليات بديلة
3. وسيط برمجي مخصص طوّرت وسيطًا برمجيًا للتعامل مع الاختلافات في كيفية تعامل MongoDB وPostgres مع بعض العمليات، مع ضمان استمرار عمل نقاط نهاية واجهة برمجة التطبيقات الحالية دون تعديل.
التغلب على التحديات التقنية
التعامل مع العلاقات المعقدة
كان أحد أكبر التحديات هو تحويل المستندات المضمنة في MongoDB إلى علاقات Postgres. على سبيل المثال، قد يحتوي مستند واحد في MongoDB على:
- خصائص أساسية
- كائنات متداخلة تمثل كيانات مرتبطة
- مصفوفات من مستندات مضمنة
كان يجب تفكيك هذا بعناية إلى:
- جداول رئيسية للكيانات الأساسية
- جداول ربط للعلاقات متعددة-إلى-متعددة
- علاقات مفاتيح خارجية للارتباطات أحادية-إلى-متعددة
تحسين الاستعلامات
أنماط استعلام MongoDB لا تُترجم مباشرةً إلى SQL. كان عليّ:
- إعادة كتابة مسارات التجميع المعقدة على شكل عمليات ربط SQL
- تحسين الفهارس لأنماط الاستعلام الجديدة
- ضمان أن أداء الاستعلامات يساوي أو يتجاوز أداء MongoDB
سلامة البيانات
ضمان سلامة البيانات أثناء الترحيل تطلّب:
- نصوص تحقق شاملة
- إجراءات استرجاع
- مزامنة بيانات في الوقت الحقيقي خلال فترات الانتقال
النتائج والأثر
تمّ إكمال ترحيل STMS من MongoDB إلى Postgres بنجاح دون أي توقف مع الحفاظ على معظم الميزات والوظائف. تجاوزت النتائج التوقعات:
تحسينات الأداء:
- تحسن أداء الاستعلامات للاستعلامات العلائقية المعقدة
- اتساق وسلامة أفضل للبيانات
- استخدام أكثر كفاءة للتخزين
فوائد تشغيلية:
- قدرات محسنة للمراقبة وتصحيح الأخطاء
- تكامل أفضل مع أدوات eBay الحالية المعتمدة على SQL
- تحسين إجراءات النسخ الاحتياطي والاستعادة
أثر على الفريق:
- تعزيز معرفة الفريق بقواعد البيانات العلائقية
- إنشاء أنماط للترحيلات المستقبلية لقواعد البيانات
- إنشاء أدوات وعمليات قابلة لإعادة الاستخدام
المهارات التقنية المكتسبة
وسّع هذا المشروع خبرتي التقنية بشكل كبير:
تقنيات قواعد البيانات:
- فهم عميق لميزات Postgres والتحسين
- تحسين استعلامات SQL وضبط الأداء
- أنماط تصميم قواعد البيانات والتطبيع
- تكوينات قواعد البيانات الأساسية-الاحتياطية
أدوات التطوير:
- Sequelize ORM وبناء الاستعلامات
- استراتيجيات ترحيل قواعد البيانات
- منهجيات اختبار الأداء
- التحقق من البيانات وفحص السلامة
أنماط البنية المعمارية:
- استراتيجيات الترحيل دون توقف
- طبقات توافق واجهة برمجة التطبيقات
- أنماط تجريد قواعد البيانات
- أنظمة المراقبة والتنبيه
النمو الشخصي والمهني
كان مشروع الترحيل هذا تحويليًا في تطور مسيرتي المهنية. فقد دفعني إلى مجال غير مطروق، ما تطلّب:
مهارات القيادة:
- قيادة مشروع تقني معقد دون خبرة سابقة
- اتخاذ قرارات معمارية حاسمة تحت الضغط
- التنسيق مع فرق متعددة وأصحاب مصلحة متعددين
قدرات حل المشكلات:
- تقسيم المشكلات المعقدة إلى مكونات قابلة للإدارة
- تطوير حلول إبداعية لتحديات غير مسبوقة
- موازنة متطلبات وقيود متعددة ومتعارضة
التواصل والعمل الجماعي:
- شرح المفاهيم التقنية لأصحاب المصلحة غير التقنيين
- توثيق العمليات والقرارات للرجوع إليها مستقبلًا
- إرشاد أعضاء الفريق حول التقنيات والأنماط الجديدة
الدروس المستفادة
الدروس التقنية
- اختيار قاعدة البيانات مهم: يجب أن يعتمد الاختيار بين NoSQL وSQL على حالات الاستخدام المحددة والمتطلبات طويلة الأجل
- اختبار الأداء أمر بالغ الأهمية: المزايا النظرية لا تُترجم دائمًا إلى مكاسب أداء في الواقع
- تخطيط الترحيل: التخطيط الشامل والاختبار ضروريان للترحيلات المعقدة
- الاستثمار في الأدوات: بناء الأدوات المناسبة مقدمًا يوفر وقتًا كبيرًا ويقلل الأخطاء
دروس إدارة المشاريع
- التواصل مع أصحاب المصلحة: التحديثات المنتظمة والتواصل الواضح يمنعان سوء الفهم
- إدارة المخاطر: وجود خطط بديلة وإجراءات استرجاع أمر أساسي
- إدارة الجدول الزمني: تخصيص وقت احتياطي للتحديات غير المتوقعة ومنحنيات التعلم
- التوثيق: التوثيق الشامل يتيح نقل المعرفة والصيانة المستقبلية
الخاتمة
يقف ترحيل STMS من MongoDB إلى Postgres بوصفه أكثر مشكلة تقنية تحديًا ومكافأةً قمت بحلها في مسيرتي المهنية. لقد تطلب الأمر ليس فقط الخبرة التقنية، بل أيضًا القيادة والتخطيط والقدرة على التكيّف. وأثبت نجاح المشروع أنه مع التخطيط السليم والاختبار الشامل والالتزام بالتميز، يمكن التغلب حتى على أكثر التحديات التقنية تعقيدًا.
لقد غيّرت هذه التجربة نهجي جذريًا في هندسة البرمجيات، مع التأكيد على أهمية:
- فهم السياق الكامل والمتطلبات قبل اتخاذ القرارات التقنية
- استثمار الوقت في الأدوات المناسبة والاختبار
- الحفاظ على تواصل واضح طوال المشاريع المعقدة
- الاستعداد لتعلم تقنيات ونهج جديدة عند الحاجة
لم يقتصر نجاح الترحيل على تحسين قدرات STMS فحسب، بل أسس أيضًا أنماطًا وعمليات تستمر في إفادة مشاريع البنية التحتية في eBay. كما عزز إيماني بأن احتضان التحديات المجهولة والنجاح من خلالها هو المفتاح للنمو الشخصي والمهني معًا.
وبالنظر إلى الوراء، يمثل هذا المشروع نقطة تحول في مسيرتي المهنية، إذ نقلني من مطور ينفذ الحلول إلى مهندس قادر على تصميم وقيادة المبادرات التقنية المعقدة. إن الثقة والمهارات التي اكتسبتها من هذه التجربة ما زالت توجه أسلوبي في التعامل مع التحديات والفرص الجديدة في هندسة البرمجيات.