Encore.ts VS NestJS
هذه المرة قمنا بقياس أداء Encore.ts وFastify وNestJS وExpress لمعرفة أداء كل إطار عمل عندما يتعلق الأمر بأوقات بدء التشغيل البارد.
يسجل برنامج القياس 10 نقاط نهاية API، كل منها بمخطط بسيط، ويقوم بإعداد التحقق من صحة المخطط. للتحقق من صحة المخطط، استخدمنا Zod حيثما أمكن. في حالة Fastify، استخدمنا Ajv كمكتبة التحقق من صحة المخطط المدعومة رسميًا.
قمنا بقياس الوقت من وقت بدء تنفيذ كود JavaScript حتى يصبح الخادم جاهزًا لقبول الطلبات الواردة. لكل قياس، أخذنا أفضل نتيجة من خمس عمليات تشغيل.
كفى من الحديث، دعنا نتعمق في الأرقام!
وقت البدء البارد (مللي ثانية)
8.3 مللي ثانية
Encore
v1.40.2
41.8 مللي ثانية
Express
v4.19.2
142.3 مللي ثانية
Fastify
v4.27.0
143.7 مللي ثانية
NestJS
v10.3.2
الأقل هو الأفضل
(راجع كود المعيار على GitHub.)
كما ترى، يحقق Encore.ts أوقات بدء بارد سريعة بشكل ملحوظ، أسرع بأكثر من 5 مرات من Express وأسرع بأكثر من 17 مرة من NestJS.
كيف حدث هذا؟ من خلال اختباراتنا، حددنا مصدرين رئيسيين للأداء، وكلاهما مرتبط بكيفية عمل Encore.ts تحت الغطاء.
ولكن قبل أن نصل إلى هناك، دعنا نتحدث عن ماهية البدء البارد حقًا، ولماذا هو مهم.
ما هو البدء البارد؟
في سياق عدم وجود خادم، يكون البدء البارد عندما تحتاج المنصة الأساسية أولاً إلى تشغيل مثيل جديد من الخادم الخاص بك من أجل تقديم طلب وارد. (يمكن أن يشير أيضًا إلى المرة الأولى التي يتم فيها تشغيل مثيل جديد من الخادم الخاص بك للتعامل مع طلب، على سبيل المثال بعد النشر.)
نظرًا لأن الطلب معلق فعليًا حتى تبدأ العملية وتكون جاهزة للتعامل مع الطلب، فإن تقليل أوقات بدء التشغيل البارد يمكن أن يكون له تأثير كبير على زمن الوصول الطويل لتطبيقك.
هذا مهم بشكل خاص للأنظمة الموزعة حيث لديك وظائف متعددة بدون خادم، حيث من المرجح أن تواجه بدء تشغيل بارد في جزء من النظام عند التعامل مع طلب.
تشريح بدء التشغيل البارد
يعتمد ما يحدث بالضبط أثناء بدء التشغيل البارد إلى حد ما على المنصة التي تنشر عليها (Kubernetes، Lambda، Cloud Run، إلخ). ولكن بشكل عام، تبدو العملية على هذا النحو:
تقوم المنصة بتنزيل صورة الكود/الحاوية للوظيفة الخالية من الخوادم
تقوم المنصة بتشغيل مثيل جديد من الوظيفة/الحاوية الخالية من الخوادم
تقوم الحاوية/الوظيفة بتهيئة نفسها (استيراد وحدات JavaScript، تشغيل كود التهيئة، إلخ.)
بعد خطوات التهيئة هذه، تكتمل عملية التشغيل البارد، وتبدأ الوظيفة الخالية من الخوادم في معالجة الطلب الوارد.
الخطوتان الأوليتان خارجتان عن سيطرتنا إلى حد كبير (بخلاف التأكد من تحسين حجم الكود/الحاوية)، لذا دعنا نركز انتباهنا على الخطوة الثالثة.
في الواقع، دعنا نحلل الخطوة الثالثة بشكل أكبر، وبافتراض أننا نقوم بتشغيل Node.js:
تبدأ عملية العقدة وتبدأ في تهيئة محرك JavaScript V8
يتم تحليل ملف نقطة الدخول وتحميله ويبدأ في تنفيذ كود التطبيق
عندما ينفذ كود JavaScript عبارات الاستيراد والطلب، يتم تحميل المزيد من الملفات وتحليلها وتنفيذها. (كرر ذلك عدة مرات بالنسبة للتطبيقات التي تحتوي على الكثير من التبعيات.)
أخيرًا، بعد تحميل جميع التبعيات وتنفيذ جميع أكواد التهيئة، تصبح وظيفة الحاوية/بدون خادم جاهزة للتعامل مع الطلبات الواردة.
تحسين البدايات الباردة
يمنحنا التفصيل أعلاه أهدافًا واضحة للتحسين، ويحسن Encore.ts بشكل كبير جميع الخطوات التي يتحكم فيها.
التحسين 1: وقت تشغيل Rust
يتم تنفيذ Encore.ts في Rust وتحميله في Node.JS كوحدة نمطية أصلية. وهذا له العديد من الفوائد للبدايات الباردة:
أقل من JavaScript للتحليل والتنفيذ. نظرًا لأن JavaScript هي لغة مفسرة، فيجب قراءة جميع أكواد JavaScript من القرص وتحليلها وتنفيذها. Encore.ts، كوحدة نمطية أصلية مجمعة مسبقًا، يتم تحميلها بسرعة كبيرة ولا تحتاج إلى تحليلها أو تنفيذها بواسطة محرك JavaScript (V8).
لا توجد تبعيات NPM. نظرًا لأن Encore.ts ينفذ جميع وظائفه باستخدام Rust، فهو لا يعتمد على NPM على الإطلاق، مما يقلل بشكل أكبر من كمية JavaScript التي يجب تنفيذها أثناء التشغيل البارد.
مجمَّع مسبقًا ومُحسَّن. يعتمد JavaScript بشكل كبير على التجميع في الوقت المناسب (JIT)، حيث يتم تحسين الكود الذي يتم تنفيذه بشكل متكرر بواسطة محرك JavaScript. وهذا منطقي للغاية بالنسبة للغة مفسرة، ولكنه يعني أيضًا أن التنفيذ يكون أبطأ كثيرًا في المرة الأولى التي يتم فيها تشغيل جزء من الكود، مما يؤثر على التشغيل البارد بشكل كبير. نظرًا لأن Encore.ts مُنفذ في Rust، فهو مُجمَّع مسبقًا ومُحسَّن بشكل كبير للمنصة التي يعمل عليها، مما يعني أنه سريع منذ المرة الأولى التي يتم فيها تنفيذه.
التحسين 2: صور Docker الفعّالة
يبني Encore.ts افتراضيًا صور Docker مصغرة، من خلال تضمين JavaScript المحول فقط والتبعيات الضرورية لتشغيل التطبيق. وهذا يقلل من أحجام الحزمة، مما يقلل بدوره من الوقت المستغرق لتنزيل الحاوية وبدء تشغيلها.
بالإضافة إلى ذلك، أضافت العديد من منصات الحوسبة دعمًا لبث صور Docker، مما يعني أن المنصة يمكنها بدء تشغيل الحاوية قبل تنزيل الصورة بالكامل. يحتوي Encore.ts على دعم مدمج لذلك، ويعطي الأولوية تلقائيًا لأجزاء الصورة المطلوبة لتقليل عمليات البدء الباردة.
الخلاصة
من خلال الجمع بين وقت تشغيل Rust وصور Docker المحسّنة، يتمكن Encore.ts من تحقيق أوقات بدء باردة رائعة، والتي يمكن أن يكون لها تأثير كبير على زمن الوصول الطويل لتطبيقك.
إذا كان الأداء مهمًا لمشروعك، فقد تكون فكرة جيدة تجربة Encore.ts. إنه مفتوح المصدر بالكامل ويمكن استخدامه بشكل مستقل عن منصة Encore السحابية الاختيارية.