OpenResty الأسئلة الشائعة | أذونات العمليات المميزة، مرحلة التنفيذ، والمزيد

API7.ai

November 11, 2022

OpenResty (NGINX + Lua)

تحتوي هذه المقالة على ستة أسئلة متكررة:

1. صلاحيات العمليات المميزة

س: ما هي العملية المميزة؟ كيف يمكن للمستخدم غير المميز الحصول على صلاحيات root؟ هل يمكنك تقديم بعض السيناريوهات للعملية المميزة؟

ج: صلاحيات العملية المميزة هي نفس صلاحيات عملية master. إذا قمت ببدء OpenResty كمستخدم غير مميز، فإن عملية master ترث صلاحية المستخدم، مما يعني أن "العملية المميزة" ليس لديها أي صلاحيات الآن.

من السهل فهم أنه لا توجد صلاحيات root عندما يبدأ مستخدم عادي عملية.

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

يقوم أحد المطورين بتشغيل جميع مهام timer في العملية المميزة. لماذا يفعل ذلك؟ لأنه يوجد عملية مميزة واحدة فقط، وبهذه الطريقة، لا يبدأ timer بشكل متكرر.

المطور "ذكي" لأنه حقق الهدف دون استخدام worker.id. ومع ذلك، لا تنسَ أن ذلك خطير جدًا إذا كانت مهمة timer تعتمد على إدخال العميل.

2. التقسيم والتصحيح

س: بعد تشغيل ngx.say('hello')، هل سيقوم OpenResty بالرد على العميل مباشرة بعد تنفيذ المنطق المتبقي في المرحلة الحالية؟ بمعنى أنه لن يستمر في تشغيل المراحل اللاحقة.

ج: لا. يمكننا النظر إلى مرحلة التنفيذ:

صورة

يمكنك اختبار ngx.say في مرحلة content أولاً، ثم استخدام ngx.log في مرحلة log أو body filter لطباعة السجل.

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

لا توجد ميزات متقدمة لتصحيح الأكواد في OpenResty، مثل نقاط التوقف (هناك بعض الإضافات المدفوعة، لكنني لم أستخدمها)، ويمكنك فقط استخدام ngx.say و ngx.log لرؤية المخرجات. هذه هي الطريقة التي يعمل بها جميع المطورين الذين أعرفهم، بما في ذلك مؤلفو OpenResty والمساهمون فيها. لذلك، تحتاج إلى حالات اختبار قوية وسجلات تصحيح كضمان.

3. ممارسة ngx.exit

س: في المقالات السابقة، كان هناك وصف: رمز حالة HTTP في OpenResty يحتوي على ثابت خاص ngx.OK. بعد تشغيل ngx.exit(ngx.OK)، يخرج الطلب من المرحلة الحالية وينتقل إلى المرحلة التالية بدلاً من العودة إلى العميل مباشرة.

أتذكر أن ngx.OK لا ينبغي اعتباره رمز حالة HTTP، قيمته هي 0. فهمي هو:

  • بعد تشغيل ngx.exit(ngx.OK)، ngx.exit(ngx.ERROR) أو ngx.exit(ngx.DECLINED)، يخرج الطلب من المرحلة الحالية وينتقل إلى المرحلة التالية.
  • عندما يأخذ ngx.exit(ngx.HTTP_*) رموز حالة HTTP المختلفة لـ ngx.HTTP_* كمعامل، فإنه سيرد مباشرة على العميل.

لا أعرف إذا كان فهمي صحيحًا.

ج: بالنسبة لسؤالك الأول، ngx.ok ليس رمز حالة HTTP ولكنه ثابت في OpenResty بقيمة 0.

أما بالنسبة للسؤال الثاني، يمكن أن تكون الوثائق الرسمية لـ ngx.exit هي الإجابة الدقيقة:

  1. عندما يكون status >= 200 (أي ngx.HTTP_OK وما فوق)، فإنه سيوقف تنفيذ الطلب الحالي ويعيد رمز الحالة إلى nginx.

  2. عندما يكون status == 0 (أي ngx.OK)، فإنه سيخرج فقط من معالج المرحلة الحالية (أو معالج المحتوى إذا تم استخدام توجيه content_by_lua*) ويستمر في تشغيل المراحل اللاحقة (إن وجدت) للطلب الحالي.

ومع ذلك، لا تذكر الوثائق كيف يتعامل OpenResty مع ngx.exit(ngx.ERROR) و ngx.exit(ngx.DECLINED). يمكننا إجراء اختبار كما يلي:

location /lua {
    rewrite_by_lua "ngx.exit(ngx.ERROR)";
    echo hello;
}

عند زيارة هذا location، يمكنك أن ترى أن رمز استجابة HTTP فارغ، ونص الاستجابة فارغ أيضًا، ولا ينتقل إلى مرحلة التنفيذ التالية.

كلما تعمقت أكثر في عملية تعلم OpenResty، ستجد في مرحلة ما أن الوثائق أو حالات الاختبار لا يمكنها الإجابة على أسئلتك. في هذه المرحلة، تحتاج إلى بناء حالات اختبار خاصة بك للتحقق من أفكارك. يمكنك القيام بذلك يدويًا، أو يمكنك إضافة الاختبارات إلى مجموعة حالات الاختبار التي تم بناؤها بواسطة test::nginx.

4. المتغيرات وحالة السباق

س: كما ذكر سابقًا، نطاق متغير ngx.var هو بين وحدات nginx C و lua-nginx-module.

  1. لا أفهم هذا تمامًا. من منظور الطلب، هل يعني ذلك طلبًا واحدًا في عملية عامل؟

  2. فهمي هو أنه عندما نقوم بمعالجة المتغيرات داخل وحدة. إذا كانت هناك عملية حظر بين عمليتين، فقد توجد حالة سباق. لذا إذا لم تكن هناك عملية حظر بين عمليتين، وحدث أن العملية الحالية دخلت في قائمة الانتظار عندما انتهى وقت CPU، هل يمكن أن توجد حالة سباق؟

ج: لننظر إلى هذه الأسئلة.

أولاً، بالنسبة لمتغير ngx.var، فهمك صحيح. دورة حياة ngx.var هي نفس دورة الطلب، وتختفي عند انتهاء الطلب. ولكن ميزتها هي أن البيانات يمكن أن تنتقل في وحدات C وأكواد Lua، وهو ما لا يمكن تحقيقه بطرق أخرى.

ثانيًا، طالما كانت هناك عملية yield بين عمليتين، فقد توجد حالة سباق وليس عملية حظر. لا توجد حالة سباق عندما تكون هناك عملية حظر. بمعنى آخر، طالما أنك لا تعطي المبادرة لحلقة أحداث NGINX، فلن توجد حالة سباق.

5. shared dict لا يحتاج إلى قفل

س: إذا قام عدة عمال بتخزين البيانات بشكل متزامن، هل من الضروري إضافة أقفال؟

على سبيل المثال:

resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs
local lock= ngx.xxxx.lock
lock.lock()
 dogs:set("Jim", 8)
lock.unlock()
 local v = dogs:get("Jim")
 ngx.say(v)
 '

ج: لا تحتاج إلى إضافة قفل هنا لأنه سواء كانت عملية get أو set، فإن عملية shared dict هي عملية ذرية. OpenResty قد أخذت بالفعل في الاعتبار هذا النوع من المعالجة الشبيهة بالقفل.

6. عمليات الوقت في OpenResty

س: باستخدام ngx.now() للحصول على الوقت، هل يحدث ذلك في مرحلة استعادة وظيفة resume؟

ج: تم تصميم NGINX مع وضع الأداء في المقام الأول ويقوم بتخزين الوقت مؤقتًا. يمكننا التحقق من ذلك من خلال الكود المصدري لـ ngx.now:

static int
ngx_http_lua_ngx_now(lua_State *L)
{
    ngx_time_t              *tp;

    tp = ngx_timeofday();

    lua_pushnumber(L, (lua_Number) (tp->sec + tp->msec / 1000.0L));

    return 1;
}

كما ترى، وراء وظيفة ngx.now() التي تحصل على الوقت الحالي هي وظيفة ngx_timeofday في NGINX. وظيفة ngx_timeofday هي تعريف ماكرو:

#define ngx_timeofday()      (ngx_time_t *) ngx_cached_time

هنا سيتم تحديث قيمة ngx_cached_time فقط في وظيفة ngx_time_update.

لذا، يتحول السؤال إلى "متى يتم استدعاء وظيفة ngx_time_update؟" إذا قمت بتتبعها في الكود المصدري لـ NGINX، ستجد أن استدعاءات ngx_time_update تحدث في حلقة الأحداث، وبالتالي يتم حل هذه المشكلة.

الخلاصة

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

أخيرًا، آمل أن يساعدك التواصل والرد على الأسئلة في تحويل ما تتعلمه إلى ما تحصل عليه. أنت أيضًا مرحب بك بنشر هذه المقالة، وسنتواصل معًا ونحسن معًا.