أفضل الممارسات ودليل استكشاف الأخطاء وإصلاحها لتطبيقات العقدة على Azure App Service Windows

في هذه المقالة، ستتعرف على أفضل الممارسات وخطوات استكشاف الأخطاء وإصلاحها لتطبيقات Windows Node.js التي تعمل على Azure App Service (مع iisnode).

تحذير

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

تكوين IISNODE

ملف المخطط هذا يعرض جميع الإعدادات التي يمكنك تكوينها لـ iisnode. بعض الإعدادات المفيدة لتطبيقك:

nodeProcessCountPerApplication

هذا الإعداد يتحكم في عدد عمليات العقد التي يتم تشغيلها لكل تطبيق IIS. القيمة الافتراضية هي 1. يمكنك تشغيل العديد من node.exes مثل عدد VCPU لجهازك الظاهري عن طريق تغيير القيمة إلى 0. القيمة الموصى بها هي 0 لمعظم التطبيقات حتى تتمكن من استخدام جميع وحدات المعالجة المركزية الظاهرية على جهازك. Node.exe عبارة عن تطبيق مترابط واحد بحيث يستهلك node.exe واحد بحد أقصى 1 وحدة معالجة مركزية ظاهرية. للحصول على أقصى أداء من تطبيق العقدة الخاص بك، عليك استخدام جميع وحدات المعالجة المركزية الظاهرية.

nodeProcessCommandLine

هذا الإعداد يتحكم في المسار إلى node.exe. هذه القيمة يمكن تعيينها للإشارة إلى إصدار node.exe الخاص بك.

maxConcurrentRequestsPerProcess

هذا الإعداد يتحكم في الحد الأقصى لعدد الطلبات المتزامنة المرسلة بواسطة iisnode إلى كل node.exe. في Azure App Service، القيمة الافتراضية هي Infinite. يمكنك تكوين القيمة استنادًا إلى عدد الطلبات التي يتلقاها التطبيق ومدى سرعة معالجة التطبيق لكل طلب.

maxNamedPipeConnectionRetry

هذا الإعداد يتحكم في الحد الأقصى لعدد مرات إعادة محاولة iisnode إجراء الاتصال على الأنبوب المسمى لإرسال الطلبات إلى node.exe. هذا الإعداد بالاشتراك مع namedPipeConnectionRetryDelay يحدد المهلة الإجمالية لكل طلب داخل iisnode. القيمة الافتراضية هي 200 في Azure App Service. Total Timeout in seconds = (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay) / 1000

namedPipeConnectionRetryDelay

هذا الإعداد يتحكم في مقدار الوقت (بالمللي ثانية) في انتظار iisnode بين كل إعادة محاولة لإرسال الطلب إلى node.exe عبر الأنبوب المسمى. تبلغ القيمة الافتراضية 250 مللي ثانية. Total Timeout in seconds = (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay) / 1000

بشكل افتراضي، إجمالي المهلة في iisnode على Azure App Service هو 200 * 250 مللي ثانية = 50 ثانية.

LogDirectory

هذا الإعداد يتحكم في الدليل حيث يسجل iisnode stdout/stderr. القيمة الافتراضية هي iisnode، وهي نسبة إلى دليل البرنامج النصي الرئيسي (الدليل حيث يوجد server.js الرئيسي)

debuggerExtensionDll

هذا الإعداد يتحكم في إصدار iisnode لمفتش العقدة الذي يستخدمه عند تصحيح أخطاء تطبيق العقدة. حاليًا، iisnode-inspector-0.7.3.dll iisnode-inspector.dll هما القيمتان الصالحتان الوحيدتان لهذا الإعداد. القيمة الافتراضية هي iisnode-inspector-0.7.3.dll. يستخدم إصدار iisnode-inspector-0.7.3.dll node-inspector-0.7.3 ويستخدم مآخذ الويب. قم بتمكين مآخذ الويب على تطبيق ويب Azure لاستخدام هذا الإصدار.

flushResponse

السلوك الافتراضي لـ IIS هو أنه يخزن بيانات الاستجابة مؤقتًا حتى 4 ميغابايت قبل المسح، أو حتى نهاية الاستجابة، أيهما يأتي أولًا. يقدم iisnode إعداد تكوين لتجاوز هذا السلوك: لمسح جزء من نص كيان الاستجابة بمجرد تلقي iisnode له من node.exe، تحتاج إلى تعيين السمة iisnode/@flushResponse في web.config إلى "true":

<configuration>
    <system.webServer>
        <!-- ... -->
        <iisnode flushResponse="true" />
    </system.webServer>
</configuration>

تمكين مسح كل جزء من نص كيان الاستجابة يضيف حمل الأداء الذي يقلل من معدل نقل النظام بنسبة ~5٪ (اعتبارًا من v0.1.13). من الأفضل تحديد نطاق هذا الإعداد فقط إلى نقاط النهاية التي تتطلب تدفق الاستجابة (على سبيل المثال، استخدام <location> العنصر في web.config)

بالإضافة إلى ذلك، بالنسبة لتطبيقات الدفق، يجب عليك أيضًا تعيين responseBufferLimit لمعالج iisnode الخاص بك إلى 0.

<handlers>
    <add name="iisnode" path="app.js" verb="\*" modules="iisnode" responseBufferLimit="0"/>
</handlers>

watchedFiles

قائمة مفصولة بفواصل منقوطة من الملفات التي تتم مراقبتها للتغييرات. أي تغيير في ملف يؤدي إلى إعادة تدوير التطبيق. كل إدخال يتكون من اسم دليل اختياري بالإضافة إلى اسم ملف مطلوب، والذي يرتبط بالدليل حيث توجد نقطة إدخال التطبيق الرئيسية. يسمح بالبطاقات البرية في جزء اسم الملف فقط. القيمة الافتراضية هي *.js;iisnode.yml

recycleSignalEnabled

القيمة الافتراضية هي false. إذا تم تمكينه، يمكن لتطبيق العقدة الاتصال بأنبوب اتصال يسمى (متغير البيئة IISNODE_CONTROL_PIPE) وإرسال رسالة "المحذوفات". هذا يؤدي إلى إعادة تدوير w3wp بأمان.

idlePageOutTimePeriod

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

تحذير

توخي الحذر عند تمكين إعدادات التكوين التالية على تطبيقات الإنتاج. يستحسن عدم تمكينها على تطبيقات الإنتاج المباشر.

debugHeaderEnabled

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

loggingEnabled

هذا الإعداد يتحكم في تسجيل stdout وstderr بواسطة iisnode. يلتقط Iisnode stdout/stderr من عمليات العقدة التي يقوم بتشغيلها ويكتبها إلى الدليل المحدد في إعداد "logDirectory". بمجرد تمكين ذلك، يكتب تطبيقك السجلات إلى نظام الملفات، وقد تكون هناك آثار على الأداء اعتمادًا على مقدار التسجيل الذي قام به التطبيق.

devErrorsEnabled

القيمة الافتراضية هي false. عند التعيين إلى true، يعرض iisnode رمز حالة HTTP ورمز الخطأ Win32 على المستعرض. التعليمة البرمجية win32 مفيدة في تصحيح أنواع معينة من المشكلات.

debuggingEnabled (عدم التمكين على موقع الإنتاج المباشر)

هذا الإعداد يتحكم في ميزة تصحيح الأخطاء. Iisnode يتم دمجه مع node-inspector. يمكنك تمكين تصحيح أخطاء تطبيق العقدة من خلال تمكين هذا الإعداد. عند تمكين هذا الإعداد، ينشئ iisnode ملفات node-inspector في دليل "debuggerVirtualDir" في طلب التصحيح الأول إلى تطبيق العقدة. يمكنك تحميل node-inspector عن طريق إرسال طلب إلى http://yoursite/server.js/debug. يمكنك التحكم في مقطع عنوان موقع الويب لتصحيح الأخطاء باستخدام إعداد "debuggerPathSegment". بشكل افتراضي، debuggerPathSegment='debug'. على سبيل المثال، يمكنك تعيين debuggerPathSegment إلى GUID بحيث يكون اكتشافه أكثر صعوبة من قبل الآخرين.

اقرأ تطبيقات Debug Node.js على Windows مزيد للحصول على من التفاصيل حول تصحيح الأخطاء.

السيناريوهات والتوصيات/ استكشاف الأخطاء وإصلاحها

يقوم تطبيق العقدة الخاص بي بإجراء مكالمات صادرة زائدة

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

تضمن الوحدة النمطية agentkeepalive إعادة استخدام مآخذ التوصيل على Azure webapp VM. يؤدي إنشاء مأخذ توصيل جديد على كل طلب صادر إلى إضافة حمل إلى تطبيقك. يضمن إعادة استخدام تطبيقك للمآخذ للطلبات الصادرة ألا يتجاوز تطبيقك maxSockets التي يتم تخصيصها لكل جهاز ظاهري. التوصية على Azure App Service هي تعيين قيمة agentKeepAlive maxSockets إلى إجمالي (4 مثيلات من node.exe * 32 maxSockets/instance) 128 مآخذ توصيل لكل جهاز ظاهري.

مثال على تكوين AgentKeepALive:

let keepaliveAgent = new Agent({
    maxSockets: 32,
    maxFreeSockets: 10,
    timeout: 60000,
    freeSocketTimeout: 300000
});

هام

هذا المثال يفترض أن لديك 4 node.exe قيد التشغيل على جهازك الظاهري. إذا كان لديك عدد مختلف من node.exe قيد التشغيل على الجهاز الظاهري، يجب تعديل إعداد maxSockets وفقًا لذلك.

يستهلك تطبيق العقدة الكثير من وحدة المعالجة المركزية

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

جمع معلومات حول تطبيق العقدة على Azure App Service باستخدام V8-Profiler

على سبيل المثال، لنفترض أن لديك تطبيق hello world تريد جمع معلومات عنه كما يلي:

const http = require('http');
function WriteConsoleLog() {
    for(let i=0;i<99999;++i) {
        console.log('hello world');
    }
}

function HandleRequest() {
    WriteConsoleLog();
}

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    HandleRequest();
    res.end('Hello world!');
}).listen(process.env.PORT);

انتقل إلى موقع وحدة تحكم تتبع الأخطاء https://yoursite.scm.azurewebsites.net/DebugConsole

انتقل إلى دليل الموقع/wwwroot. ترى موجه أوامر كما هو موضح في المثال التالي:

لقطة شاشة تظهر دليل موقع/wwwroot وموجه الأوامر.

تشغيل الأمر npm install v8-profiler.

هذا الأمر يقوم بتثبيت محلل جمع المعلومات v8 ضمن دليل node_modules وجميع تبعياته. الآن، قم بتحرير server.js الخاص بك لملف تعريف تطبيقك.

const http = require('http');
const profiler = require('v8-profiler');
const fs = require('fs');

function WriteConsoleLog() {
    for(let i=0;i<99999;++i) {
        console.log('hello world');
    }
}

function HandleRequest() {
    profiler.startProfiling('HandleRequest');
    WriteConsoleLog();
    fs.writeFileSync('profile.cpuprofile', JSON.stringify(profiler.stopProfiling('HandleRequest')));
}

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    HandleRequest();
    res.end('Hello world!');
}).listen(process.env.PORT);

تقوم التعليمات البرمجية السابقة بملفات تعريف الدالة WriteConsoleLog ثم تكتب إخراج ملف التعريف إلى ملف 'profile.cpuprofile' ضمن موقعك wwwroot. أرسل طلبًا إلى تطبيقك. ترى ملف 'profile.cpuprofile' الذي تم إنشاؤه ضمن الموقع wwwroot.

لقطة شاشة تظهر ملف profile.cpuprofile.

قم بتنزيل هذا الملف وافتحه باستخدام أدوات Chrome F12. اضغط على F12 على Chrome، ثم اختر علامة التبويب ملفات التعريف. اختر الزر تحميل. حدد ملف profile.cpuprofile الذي قمت بتنزيله. انقر فوق ملف التعريف الذي قمت بتحميله للتو.

لقطة شاشة تظهر ملف profile.cpuprofile الذي قمت بتحميله.

يمكنك أن ترى أن 95٪ من الوقت تم استهلاكه بواسطة الدالة WriteConsoleLog. كما يظهر لك الإخراج أرقام أسطر دقيقة وملفات المصدر التي تسببت في المشكلة.

يستهلك تطبيق العقدة الكثير من الذاكرة

إذا كان تطبيقك يستهلك الكثير من الذاكرة، فسترى إشعارًا من Azure App Service على مدخلك حول استهلاك الذاكرة العالي. يمكنك إعداد أجهزة العرض لمشاهدة مقاييس معينة. عند التحقق من استخدام الذاكرة على لوحة معلومات مدخل Microsoft Azure، تأكد من التحقق من قيم MAX للذاكرة حتى لا تفوتك قيم الذروة.

الكشف عن التسرب وكومة الذاكرة المؤقتة لـ Node.js

يمكنك استخدام node-memwatch لمساعدتك في تحديد تسرب الذاكرة. يمكنك تثبيت memwatch تمامًا مثل محلل ملفات التعريف v8 وتحرير التعليمات البرمجية الخاصة بك لالتقاط كومات الذاكرة وفكها لتحديد تسرب الذاكرة في تطبيقك.

node.exe الخاص بي يقتل عشوائيًا

هناك بعض الأسباب التي تجعل node.exe يتم إيقاف تشغيلها عشوائيًا:

  1. يطرح تطبيقك استثناءات غير محددة - تحقق من ملف d:\home\LogFiles\Application\logging-errors.txt للحصول على تفاصيل حول الاستثناء الذي تم طرحه. هذا الملف يحتوي على تتبع المكدس للمساعدة في تصحيح تطبيقك وإصلاحه.
  2. يستهلك تطبيقك الكثير من الذاكرة، مما يؤثر على العمليات الأخرى من البدء. إذا كانت ذاكرة الجهاز الظاهري الإجمالية قريبة من 100٪، فقد يقتل مدير العملية ذاكرة node.exe. مدير العمليات يقتل بعض العمليات للسماح للعمليات الأخرى بالحصول على فرصة للقيام ببعض العمل. لإصلاح هذه المشكلة، أنشئ ملف تعريف لتطبيقك لتسرب الذاكرة. إذا كان تطبيقك يتطلب كميات كبيرة من الذاكرة، فقم بالتحجيم إلى جهاز ظاهري أكبر (مما يزيد من ذاكرة الوصول العشوائي المتوفرة للجهاز الظاهري).

لا يبدأ تطبيق العقدة الخاص بي

إذا كان تطبيقك يرجع 500 خطأ عند بدء تشغيله، فقد يكون هناك بعض الأسباب:

  1. Node.exe غير موجود في الموقع الصحيح. تحقق من إعداد nodeProcessCommandLine.
  2. ملف البرنامج النصي الرئيسي غير موجود في الموقع الصحيح. تحقق من web.config وتأكد من تطابق اسم ملف البرنامج النصي الرئيسي في قسم المعالجات مع ملف البرنامج النصي الرئيسي.
  3. تكوين Web.config غير صحيح - تحقق من أسماء/ قيم الإعدادات.
  4. البدء البارد - يستغرق التطبيق وقتًا طويلاً للبدء. إذا استغرق تطبيقك وقتًا أطول من (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay)/ 1000 ثانية، فترجع iisnode خطأ 500. قم بزيادة قيم هذه الإعدادات لمطابقة وقت بدء تطبيقك لمنع iisnode من المهلة وإرجاع الخطأ 500.

تعطل تطبيق العقدة

يطرح تطبيقك استثناءات غير محددة - تحقق من ملف d:\\home\\LogFiles\\Application\\logging-errors.txt للحصول على تفاصيل الاستثناء الذي تم طرحه. هذا الملف يحتوي على تتبع المكدس للمساعدة في تشخيص تطبيقك وإصلاحه.

يستغرق تطبيق العقدة الخاص بي وقتًا طويلاً لبدء التشغيل (بدء التشغيل البارد)

السبب الشائع لأوقات بدء التطبيق الطويلة هو وجود عدد كبير من الملفات في node_modules. يحاول التطبيق تحميل معظم هذه الملفات عند البدء. بشكل افتراضي، نظرًا لأنه يتم تخزين ملفاتك على مشاركة الشبكة على Azure App Service، يمكن أن يستغرق تحميل العديد من الملفات وقتًا. بعض الحلول لجعل هذه العملية أسرع هي:

  1. حاول تحميل node_modules الخاص بك كسول وعدم تحميل جميع الوحدات النمطية في بداية التطبيق. إلى وحدات التحميل البطيئة، يجب إجراء الاستدعاء لطلب ('الوحدة النمطية') عندما تحتاج بالفعل إلى الوحدة داخل الدالة قبل التنفيذ الأول للتعليمات البرمجية للوحدة النمطية.
  2. Azure App Service تقدم ميزة تسمى ذاكرة التخزين المؤقت المحلية. هذه الميزة تنسخ المحتوى الخاص بك من مشاركة الشبكة إلى القرص المحلي على الجهاز الظاهري. نظرًا لأن الملفات محلية، فإن وقت تحميل node_modules أسرع بكثير.

حالة IISNODE http والإحصاء الفرعي

يسرد cnodeconstants الملف المصدر كافة مجموعات الحالة/الحالة الفرعية المحتملة التي يمكن أن ترجعها iisnode بسبب خطأ.

تمكين FREB لتطبيقك لمشاهدة رمز الخطأ win32 (تأكد من تمكين FREB فقط على المواقع غير الإنتاجية لأسباب تتعلق بالأداء).

حالة HTTP حالة Http الفرعية السبب المحتمل؟
500 1000 حدثت بعض المشاكل أثناء إرسال الطلب إلى IISNODE – تحقق مما إذا كان قد تم بدء node.exe. قد يكون Node.exe قد تعطل عند البدء. تحقق من تكوين web.config بحثًا عن الأخطاء.
500 1001 - Win32Error 0x2 - التطبيق لا يستجيب إلى عنوان موقع الويب. تحقق من قواعد إعادة كتابة عنوان موقع الويب أو تحقق مما إذا كان تطبيقك السريع يحتوي على المسارات الصحيحة المعرفة. - Win32Error 0x6d – الأنابيب المسماة مشغولة – Node.exe لا يقبل الطلبات لأن الأنبوب مشغول. تحقق من الاستخدام العالي لوحدة المعالجة المركزية. - أخطاء أخرى – تحقق مما إذا كان node.exe قد تعطل.
500 1002 Node.exe تعطل – تحقق من d:\home\LogFiles\logging-errors.txt لتتبع المكدس.
500 1003 مشكلة تكوين الأنبوب - تكوين الأنابيب المسمى غير صحيح.
500 1004-1018 حدثت بعض الأخطاء أثناء إرسال الطلب أو معالجة الاستجابة إلى/ من node.exe. تحقق مما إذا كان node.exe قد تعطل. تحقق من d:\home\LogFiles\logging-errors.txt لتتبع المكدس.
503 1000 لا توجد ذاكرة كافية لتخصيص المزيد من اتصالات الأنابيب المسماة. تحقق من سبب استهلاك تطبيقك الكثير من الذاكرة. تحقق من قيمة إعداد maxConcurrentRequestsPerProcess. إذا لم يكن لانهائيًا ولديك العديد من الطلبات، فقم بزيادة هذه القيمة لمنع هذا الخطأ.
503 1001 تعذر إرسال الطلب إلى node.exe لأن التطبيق يقوم بإعادة التدوير. بعد إعادة استخدام التطبيق، يجب تقديم الطلبات بشكل طبيعي.
503 1002 تحقق من رمز الخطأ win32 للسبب الفعلي - تعذر إرسال الطلب إلى node.exe.
503 1003 الأنابيب المسماة مشغولة جدًا - تحقق مما إذا كان node.exe يستهلك وحدة المعالجة المركزية بشكل مفرط

يحتوي NODE.exe على إعداد يسمى NODE_PENDING_PIPE_INSTANCES. في Azure App Service، يتم تعيين هذه القيمة إلى 5000. بمعنى أنه يمكن node.exe قبول 5000 طلب في كل مرة على الأنابيب المسماة. يجب أن تكون هذه القيمة جيدة بما يكفي لمعظم تطبيقات العقد التي تعمل على Azure App Service. يجب ألا ترى 503.1003 على Azure App Service بسبب القيمة العالية لـ NODE_PENDING_PIPE_INSTANCES

المزيد من الموارد

اتبع هذه الارتباطات لمعرفة المزيد حول تطبيقات Node.js على Azure App Service.