تطبيقات Node.js

Node.js، نبنيه ونشغّله بجانب PHP لديك.

نبني بـ Node واجهات برمجية، ومواقع تُعرض من الخادم، وخدمات فورية، وعمّالًا في الخلفية، ونشغّلها على الخوادم نفسها التي تعمل عليها مواقع PHP لديك، خلف Nginx واحد.

يعمل على ويُبنى بـ
  • Node.js
  • Express
  • npm
  • NGINX
  • MySQL
  • PostgreSQL
  • Redis

ما نبنيه بـ Node

خمسة أنواع من العمل، وكل منها هنا لأن Node يناسبه.

  1. 01

    Express

    واجهات برمجية وخوادم خلفية صغيرة ومباشرة: مسارات قليلة، وطبقات وسيطة واضحة، ولا شيء مخفي.

    واجهات برمجية وخوادم خلفية
  2. 02

    NestJS

    خدمات أكبر مبنية على وحدات وحقن التبعيات وعقود محددة الأنواع بلغة TypeScript، لشيفرة سينمّيها فريق على مدى سنوات.

    خدمات منظّمة
  3. 03

    Next.js · Nuxt

    عرض من جهة الخادم لـ React وVue: تصل الصفحات جاهزة لمحركات البحث ولظهور أول سريع، ثم تعمل كتطبيق.

    مواقع تُعرض من الخادم
  4. 04

    Socket.IO · WebSockets

    محادثات وإشعارات ولوحات متابعة حية وتتبّع، تتحدّث لحظة حدوث أي تغيير عبر اتصال واحد مفتوح.

    الوقت الفعلي
  5. 05

    العمّال والطوابير

    مهام في الخلفية ومهام مجدولة ومستهلكو طوابير على Redis، تُبقي العمل البطيء خارج الطلب.

    العمل في الخلفية

لماذا يُجيد Node الانتظار

تشغّل عملية Node شيفرة JavaScript على خيط واحد، وتترك الانتظار - للقرص والشبكة وقاعدة البيانات - للنظام. وبهذا تُبقي عملية واحدة اتصالات كثيرة مفتوحة في آن واحد.

حلقة أحداث Node.js، بصورة مبسّطة
  1. تعمل شيفرتك على مكدّس الاستدعاءات، دالة واحدة في كل مرة.
  2. يغادر العمل البطيء الخيط: فالملفات وDNS والتجزئة تذهب إلى مجمّع libuv، ويراقب نظام التشغيل المقابس الشبكية.
  3. عند انتهاء العمل، تنتظر دالة رد النداء الخاصة به في طابور المهام.
  4. قبل المهمة التالية، تُنفَّذ كل دوال الوعود الموجودة في طابور المهام الدقيقة.
  5. تدور الحلقة عبر مراحلها وتأخذ المهمة التالية.

PHP وNode على خادم واحد

يستقبل Nginx كل طلب ويوجّه كل مسار إلى العملية المسؤولة عنه. يتشارك موقع PHP وخدمة Node لديك الجهاز وقاعدة البيانات والشهادة - لا ذاكرة كلٍّ منهما.

مثال على خادم واحد يشغّل الاثنين

أيهما لأي عمل

نبني بالاثنين، لذا تأتي الإجابة من طبيعة العمل لا من العادة.

اختر PHP عندما

  • يكون الموقع في معظمه صفحات ونماذج ولوحة إدارة: متاجر ومواقع محتوى وأنظمة أعمال.
  • تريد WordPress أو WooCommerce أو Laravel وكل ما بُني لها مسبقًا.
  • يكون كل طلب مستقلًا بذاته وينتهي بسرعة.
  • يكون من سيتولون صيانته يعرفون PHP بالفعل.

اختر Node عندما

  • تبقى الاتصالات مفتوحة: محادثات ولوحات متابعة حية وإشعارات وتتبّع.
  • تُعرض صفحات React أو Vue من جهة الخادم باستخدام Next.js أو Nuxt.
  • تقضي الخدمة معظم وقتها في انتظار واجهات برمجية أخرى وتمرير البيانات كتدفّق.
  • تفيد فريقك لغةٌ واحدة في المتصفح وعلى الخادم.

وكثيرًا ما تكون الإجابة: الاثنان معًا

يحتفظ PHP بالموقع والمتجر ولوحة الإدارة، وتتولى خدمة Node صغيرة بجانبه الجزء الفوري. ويقرأ كلاهما من قاعدة البيانات نفسها ويعملان خلف Nginx نفسه.

إصدارات بلا انقطاع

يبدأ الإصدار الجديد بجانب القديم، ويثبت سلامته، ثم يستلم الحركة بعد ذلك فقط. وتُنهي العمليات القديمة الطلبات التي بين يديها قبل أن تتوقف.

  • الزوار المخدومون
  • الإصدار الحالي
  • الإصدار الجديد
  1. 01

    الجلب والتثبيت

    git pull && npm ci

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

  2. 02

    البناء

    npm run build

    تُترجَم شيفرة TypeScript والملفات الثابتة قبل إعادة تشغيل أي شيء.

  3. 03

    التشغيل بجانب القديم

    pm2 reload app

    يبدأ الإصدار الجديد بجانب الإصدار الذي لا يزال يخدم الزوار.

  4. 04

    الانتظار حتى الجاهزية

    wait_ready: true

    يجب أن يجتاز فحص السلامة قبل أن يستقبل أي زائر.

  5. 05

    استلام الحركة

    cluster → new workers

    تتجه الاتصالات الجديدة إلى الإصدار الجديد.

  6. 06

    تصريف القديم

    SIGINT → server.close()

    تُنهي العمليات القديمة الطلبات التي بين يديها، ثم تتوقف.

إذا لم يجتز الإصدار الجديد فحص السلامة، فلن يستلم أي حركة: يواصل الإصدار القديم الخدمة ببساطة.

الخادم من حول الشيفرة

كل ما يُبقي خدمة Node قائمة مكتوب على الخادم، في ملفات نتولى صيانتها ويمكنك قراءتها.

  • /etc/nginx/sites-enabled/app.conf

    الوكيل العكسي

    التشفير عبر TLS، والضغط، وتخزين الملفات الثابتة مؤقتًا، وترقية اتصالات WebSocket، أمام كل عملية.

  • /srv/app/ecosystem.config.js

    مدير العمليات

    يُبقي PM2 العملية حيّة، ويعيد تشغيلها إذا تعطلت، ويستخدم كل أنوية المعالج في وضع العنقود. وحيث تكفي عملية واحدة، تؤدي وحدة systemd المهمة نفسها.

  • /srv/app/.env (0600)

    البيئة والأسرار

    تُحفظ المفاتيح وكلمات المرور خارج الشيفرة وخارج git، ولا يقرؤها إلا مستخدم التطبيق نفسه.

  • /srv/app/package-lock.json

    تدقيق الاعتماديات

    فحص npm audit مع كل إصدار؛ وتُقرأ الترقيات وتُختبر قبل أن تصل إلى بيئة الإنتاج.

  • /srv/app/.nvmrc

    الترقية بين إصدارات Node LTS

    يعمل التطبيق على إصدار ذي دعم طويل الأمد، وننقله إلى الإصدار التالي قبل أن ينتهي دعم الإصدار القديم.

  • /var/log/app/

    السجلات والمراقبة

    سجلات منظّمة تُدوَّر بانتظام، مع تنبيه عند إعادة تشغيل العملية أو ارتفاع استهلاك الذاكرة أو تزايد الأخطاء.

أربعة أرقام وراء كل خدمة Node

كل رقم مأخوذ من توثيق Node.js أو libuv أو WebSocket، لا من قياساتنا نحن، فيمكنك التحقق منه عند مصدره.

  • 30شهرًا

    من الإصلاحات لكل إصدار Node.js من فئة LTS: 12 شهرًا من الدعم النشط ثم 18 شهرًا من الصيانة.

    المصدر: مجموعة عمل إصدارات Node.js

  • 4خيوط

    في مجمّع libuv افتراضيًا، للملفات وDNS والتجزئة. ويمكن رفع حجم المجمّع بإعداد واحد حتى 1024.

    المصدر: توثيق libuv

  • 101رمز الحالة

    هو رد الخادم على طلب التحويل إلى WebSocket: Switching Protocols.

    المصدر: RFC 6455

  • 443منفذ

    هو المنفذ الذي يتصل به WebSocket الآمن افتراضيًا، وهو نفسه منفذ HTTPS، فيحمل مدخل Nginx الواحد الاثنين معًا.

    المصدر: RFC 6455

ما تستطيع خدمة Node فعله في لمحة

القدرات في أربع مجموعات: ما تقدّمه، وما تحيله إلى غيرها، وأين تحفظ بياناتها، وكيف تبقى شغّالة.

البناء والتقديم

  • واجهات HTTP وREST

    Express وحده، أو NestJS الذي يعمل فوق Express افتراضيًا ويمكنه استخدام Fastify بدلًا منه.

  • TypeScript

    عقود محددة الأنواع بين الوحدات، يُتحقق منها عند بناء الشيفرة، قبل إعادة تشغيل أي شيء.

  • العرض من الخادم

    يعرض Next.js وNuxt الصفحات على الخادم، فيحصل محرك البحث والزائر لأول مرة على HTML جاهز.

  • الوقت الفعلي

    يبدأ Socket.IO عبر HTTP العادي ثم يرتقي إلى WebSocket، فيتصل حتى حيث يمنع وسيط WebSocket، ويعيد الاتصال من تلقاء نفسه.

إحالة العمل الثقيل

  • خيوط العمل (Worker threads)

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

  • طوابير على Redis

    تُوضع المهام البطيئة في طابور وتُنجز في الخلفية بعيدًا عن طلب الزائر.

  • مهام مجدولة

    مهام تعمل في أوقات محددة بدل انتظار زائر يشغّلها.

  • وضع الكتلة (Cluster)

    يشغّل PM2 عاملًا لكل نواة، فتستفيد الخدمة المزدحمة من الجهاز كله بدل خيط واحد منه.

البيانات قريبة

  • MySQL وPostgreSQL

    يمكن لخدمة Node وموقع PHP قراءة قاعدة البيانات نفسها.

  • Redis

    الجلسات والتخزين المؤقت والطوابير في الذاكرة، ومشتركة بين البيئتين.

  • الملفات الثابتة

    يقدّم Nginx ملفات CSS والصور والتنزيلات مباشرة من القرص، فلا تتولى Node إلا ما يحتاج إلى شيفرة.

  • خطة نسخ احتياطي واحدة

    خطة نسخ احتياطي واحدة تغطي موقع PHP وخدمة Node معًا.

الاستمرار والتحديث

  • إعادة التشغيل عند العطل

    يعيد PM2، أو وحدة systemd حيث تكفي عملية واحدة، تشغيل العملية التي تعطلت.

  • إعادة التحميل دون انقطاع

    يجتاز الإصدار الجديد فحص السلامة قبل أن يستلم أي حركة.

  • سجلات وتنبيهات

    سجلات منظّمة تُدوَّر دوريًا، وتنبيه عند إعادة تشغيل العملية أو ارتفاع الذاكرة أو زيادة الأخطاء.

  • إصدارات LTS والتدقيق

    إصدار Node بدعم طويل الأمد، وتشغيل npm audit مع كل إصدار، وأسرار محفوظة خارج الشيفرة.

أخبرنا بما يجب أن يؤديه تطبيق Node لديك

خدمة جديدة، أو موقع Next.js، أو تطبيق يعمل في مكان ما ويحتاج إلى بيئة لائقة. ننظر فيه ونقدّم عرض السعر بعد محادثة قصيرة.

ميكيبيرد في ثواني