ما هو LuaJIT؟ ولماذا تختار APISIX LuaJIT؟

Tao Yang

April 14, 2023

Products

هل أنت مستعد لرفع مستوى لعبة بوابة API الخاصة بك إلى المستوى التالي؟ إذن قد ترغب في الانتباه إلى Apache APISIX، وهي بوابة API سحابية الأصل أحدثت ضجة في مجتمع المطورين. والأكثر إثارة للاهتمام هو أن Apache APISIX تم بناؤها بشكل أساسي باستخدام LuaJIT، وهي لغة خفيفة الوزن وفعالة ليست معروفة مثل بعض اللغات الأخرى.

في هذه المقالة، سنلقي نظرة فاحصة على سبب اختيار Apache APISIX لـ LuaJIT بدلاً من اللغات والتقنيات الأكثر شيوعًا، وكيف يمكن لميزات LuaJIT الفريدة ومزاياها مساعدتك في بناء بوابات API سريعة للغاية يمكنها التعامل مع حتى أكثر أحمال العمل تطلبًا. لذا، إذا كنت تبحث عن تعزيز بوابة API الخاصة بك، تابع القراءة!

ما هي LuaJIT

التعريف

ببساطة، LuaJIT هو تنفيذ لمترجم Just-In-Time (JIT) للغة البرمجة Lua. لفهم أفضل، يمكن للقراء الذين ليسوا على دراية بـ LuaJIT تقسيمها إلى جزأين: Lua و JIT.

Lua

Lua هي لغة برمجة أنيقة وسهلة التعلم تتميز بإدارة الذاكرة التلقائية، والنطاق المعجمي الكامل، والإغلاقات، والمكررات، والتماثلات، والمكالمات الذيلية الصحيحة، ومعالجة البيانات العملية باستخدام المصفوفات الترابطية. لمزيد من القراءة حول بناء جملة Lua، نرحب بقراءة Getting Started With Lua لمزيد من المعلومات.

تم تصميم Lua ليكون من السهل دمجها مع C أو لغات البرمجة الأخرى المستخدمة على نطاق واسع، مما يسمح للمطورين بالاستفادة من نقاط القوة في تلك اللغات. توفر Lua ميزات ليست عادةً نقاط قوة في لغات مثل C، مثل التجريدات عالية المستوى بالنسبة للأجهزة، والهياكل الديناميكية، والاختبار البسيط. نواتها اللغوية الصغيرة واعتمادها على معيار ANSI C تجعلها قابلة للنقل بدرجة كبيرة عبر منصات مختلفة. نتيجة لذلك، Lua ليست فقط لغة برمجة نصية يمكن أن تعمل كبرنامج مستقل ولكن أيضًا لغة مدمجة يمكن دمجها في تطبيقات أخرى.

Apache APISIX هي مثال ممتاز لاستخدام كل من Lua و C على المستوى المنخفض

ومع ذلك، في هذا الوقت، كانت Lua لا تزال تواجه مشكلتين شائعتين في لغات البرمجة النصية التقليدية: الكفاءة المنخفضة والتعرض للكود. يمكن لتقنية JIT التي قدمتها LuaJIT أن تحل هاتين المشكلتين بشكل فعال.

JIT

JIT (التجميع في الوقت المناسب)، هو شكل من أشكال التجميع الديناميكي. التجميع الديناميكي ليس الشكل الوحيد للتجميع في علوم الكمبيوتر. على سبيل المثال، لغة C المستخدمة على نطاق واسع تستخدم شكلًا مختلفًا من التجميع، يُعرف باسم التجميع الثابت.

من المهم ملاحظة أنه بينما نستخدم غالبًا مصطلح التجميع المسبق (AOT) لوصف عكس التجميع الديناميكي المستخدم في C، فإن الاثنين ليسا متكافئين تمامًا. AOT يصف فقط سلوك تجميع لغة "عالية المستوى" إلى لغة "منخفضة المستوى" قبل تنفيذ البرنامج. اللغة الهدف للتجميع ليست بالضرورة كود الآلة المحدد لجهاز المضيف للبرنامج، ولكن يتم تعريفها بشكل تعسفي. على سبيل المثال، تجميع Java إلى C أو تجميع JavaScript إلى V8 سيُعتبر أيضًا كـ AOT. نظرًا لأن جميع التجميعات الثابتة يتم تنفيذها تقنيًا مسبقًا، في هذا السياق المحدد، يمكن اعتبار AOT كتجميع ثابت مقابل JIT.

بغض النظر عن هذه المصطلحات المعقدة، عند النظر في ناتج التجميع الثابت، قد تكتشف أن المشكلات التي تواجهها لغة Lua يمكن حلها أيضًا عن طريق التجميع الثابت. ومع ذلك، سيؤدي ذلك إلى فقدان الميزة التي توفرها Lua كلغة برمجة نصية: مرونة التحديثات الساخنة والتوافق الجيد مع المنصات. لذلك، حاليًا، معظم لغات البرمجة النصية، باستثناء تلك التي لديها متطلبات خاصة، تستخدم JIT لمحاولة تحسين أداء اللغة، مثل JavaScript على منصة Chromium باستخدام V8 و Ruby باستخدام YJIT.

يحاول JIT الجمع بين مزايا وعيوب التفسير الديناميكي لـ Lua والتجميع الثابت لـ C. أثناء تنفيذ لغة البرمجة النصية، يقوم JIT بتحليل أجزاء الكود التي يتم تنفيذها بشكل مستمر، وتجميعها أو إعادة تجميعها لتحسين كفاءة التنفيذ. في هذه المرحلة، الافتراض وراء JIT هو أن المكاسب في الأداء التي يتم الحصول عليها من هذه العملية ستتفوق على تكلفة تجميع أو إعادة تجميع الكود. من الناحية النظرية، نظرًا لأنه يمكن إعادة تجميعه ديناميكيًا، يمكن لـ JIT التحسين والتسريع لهندسة المنصة المحددة التي يعتمد عليها البرنامج قيد التشغيل، وفي بعض الحالات، إنتاج سرعات تنفيذ أسرع من التجميع الثابت.

ينقسم JIT إلى نوعين: Method JIT التقليدي و Trace JIT الذي يستخدمه LuaJIT حاليًا. Method JIT يترجم كل طريقة إلى كود الآلة، بينما Trace JIT، الأكثر تقدمًا، يفترض أن "للكود الذي يتم تنفيذه مرة أو مرتين فقط، التنفيذ المفسر أسرع من التنفيذ المترجم باستخدام JIT". بناءً على ذلك، يقوم Trace JIT بتحسين JIT التقليدي عن طريق تحديد أجزاء الكود التي يتم تنفيذها بشكل متكرر (أي الكود على المسار الساخن) ككود يحتاج إلى تتبع وتجميع هذا الجزء من الكود إلى كود الآلة للتنفيذ، كما هو موضح في الرسم البياني أدناه.

مبدأ LuaJIT

LuaJIT

LuaJIT (الإصدار 2.x) يحسن أداء JIT بشكل كبير من خلال دمج مترجم سريع مكتوب بلغة التجميع ومولد كود خلفي محسن يعتمد على Static Single Assignment (SSA). نتيجة لذلك، أصبح LuaJIT واحدًا من أسرع تنفيذات اللغات الديناميكية.

بالإضافة إلى ذلك، مقارنة بالربط المرهق بين Lua و C في Lua الأصلية للتفاعل مع C، قام LuaJIT أيضًا بتنفيذ FFI (واجهة الوظائف الأجنبية). تتيح لنا هذه التقنية استدعاء وظائف C الخارجية واستخدام هياكل بيانات C مباشرة من كود Lua دون معرفة عدد ونوع المعلمات. مع هذه الميزة، يمكننا استخدام FFI مباشرة لتنفيذ هياكل البيانات المطلوبة بدلاً من النوع الأصلي Table في Lua، مما يحسن أداء البرنامج في السيناريوهات الحساسة للأداء. تقنيات استخدام FFI لتحسين الأداء تتجاوز نطاق هذه المقالة، ويمكن العثور على معلومات أكثر تفصيلاً في المقالة Why Does lua-resty-core Perform Better?.

باختصار، قام LuaJIT بتنفيذ واحد من أسرع Trace JITs في لغات البرمجة النصية حتى الآن، باستخدام بناء جملة Lua. بالإضافة إلى ذلك، يوفر ميزات مثل FFI لمعالجة مشكلات الكفاءة المنخفضة والتعرض للكود في Lua، مما يجعل Lua لغة برمجة نصية ومدمجة عالية المرونة والأداء واستهلاك الذاكرة المنخفض للغاية.

المقارنة مع WASM واللغات الأخرى

مقارنة بـ Lua و LuaJIT، قد نكون أكثر دراية ببعض اللغات الأخرى، مثل JavaScript (Node.js)، Python، Golang، Java، إلخ. من خلال مقارنة Lua/LuaJIT مع هذه اللغات الشائعة، يمكننا الحصول على فهم أفضل لميزات LuaJIT الفريدة ومزاياها. فيما يلي بعض المقارنات الموجزة:

  • بناء جملة Lua مصمم لغير مهندسي البرمجيات. على غرار لغة R، Lua لديها أيضًا فهرس مصفوفة يبدأ من 1، وهو مناسب للأشخاص العاديين.
  • Lua مناسبة جدًا كلغة مدمجة. Lua نفسها لديها آلة افتراضية خفيفة الوزن، و LuaJIT تظل خفيفة الوزن حتى بعد إضافة الميزات والتحسينات المختلفة. نتيجة لذلك، لا يزيد حجم LuaJIT بشكل كبير عند دمجها مباشرة في برامج C، على عكس بيئات التشغيل الكبيرة مثل Node.js و Python. وبالتالي، Lua هي في الواقع الخيار الأكثر استخدامًا وشيوعًا بين جميع اللغات المدمجة.
  • Lua مناسبة أيضًا كلغة "لاصقة". مثل JavaScript (Node.js) و Python، يمكن لـ Lua أيضًا توصيل المكتبات والأكواد المختلفة بشكل جيد. ومع ذلك، يختلف قليلاً عن اللغات الأخرى، Lua لديها اقتران أعلى مع النظام البيئي الأساسي، لذلك قد لا يكون النظام البيئي لـ Lua عالميًا في مجالات مختلفة.

WASM (Web Assembly) هي تقنية متعددة المنصات ناشئة. تم تصميم هذه التقنية في البداية لتكملة JavaScript بدلاً من استبدالها، يمكنها تجميع لغات أخرى إلى bytecode WASM وتشغيل الكود كصندوق رمل آمن، مما يجعل المزيد والمزيد من البرامج تفكر في استخدام WASM كمنصة مدمجة أو "لاصقة". ومع ذلك، لا تزال Lua/LuaJIT لديها العديد من المزايا مقارنة بـ WASM الناشئة:

  • أداء WASM محدود ولا يمكن أن يصل إلى مستوى التجميع. في السيناريوهات العامة، WASM بالتأكيد أفضل من Lua من حيث الأداء، ولكن لا يزال هناك فجوة بين WASM و LuaJIT.
  • كفاءة نقل البيانات بين WASM وبرنامج المضيف منخفضة نسبيًا. من ناحية أخرى، يمكن لـ LuaJIT إجراء نقل بيانات فعال من خلال FFI.

لماذا اختارت Apache APISIX LuaJIT؟

على الرغم من وصف العديد من مزايا LuaJIT أعلاه، إلا أن Lua ليست لغة شائعة ولا خيارًا شائعًا لمعظم المطورين. إذن لماذا اختارت Apache APISIX، بوابة API سحابية تحت مؤسسة Apache، LuaJIT؟

كبوتة API سحابية الأصل، تتمتع Apache APISIX بخصائص ديناميكية، في الوقت الحقيقي، وأداء عالي، وتوفر وظائف إدارة حركة مرور غنية مثل موازنة الحمل، المصدر الديناميكي، الإصدار التجريبي، تخفيض الخدمة، المصادقة، المراقبة، إلخ. يمكننا استخدام Apache APISIX للتعامل مع حركة المرور التقليدية من الشمال إلى الجنوب، وكذلك حركة المرور بين الخدمات من الشرق إلى الغرب، ويمكنها أيضًا أن تعمل كوحدة تحكم Ingress لـ k8s.

كل ذلك مبني على مكدس تقنيات NGINX و LuaJIT الذي اختارته Apache APISIX.

مزايا الجمع بين LuaJIT و NGINX

NGINX هو خادم ويب عالي الأداء معروف يعمل كخادم HTTP، وكيل TCP/UDP وعكسي.

ومع ذلك، في الممارسة العملية، نجد أنه من المزعج أنه في كل مرة نقوم فيها بتعديل ملف تكوين NGINX، نحتاج إلى استخدام الأمر nginx -s reload لإعادة تحميل تكوين NGINX.

علاوة على ذلك، الاستخدام المتكرر لهذا الأمر لإعادة تحميل التكوين قد يسبب عدم استقرار الاتصال ويزيد من احتمالية فقدان الأعمال. في بعض الحالات، قد تتسبب آلية إعادة تحميل تكوين NGINX أيضًا في استغراق العمليات القديمة وقتًا طويلاً ليتم استردادها، مما يؤثر على العمليات التجارية العادية. للحصول على تحليل أكثر شمولاً لهذا الموضوع، نوصي بقراءة المقالة Why NGINX's reload is not a hot reload?. لن نستعرض هذا الموضوع بمزيد من التفصيل هنا.

أحد أهداف Apache APISIX هو حل مشكلة التكوين الديناميكي لـ NGINX. مرونة LuaJIT العالية، أدائها العالي، واستهلاك الذاكرة المنخفض للغاية يجعل هذا ممكنًا. على سبيل المثال، في أبسط الحالات، تقوم Apache APISIX بتكوين موقع واحد فقط كنقطة دخول رئيسية في ملف تكوين NGINX، ويتم توزيع المسارات اللاحقة بواسطة وحدة توزيع المسارات في APISIX، مما يحقق تكوينًا ديناميكيًا للمسارات.

لتحقيق أداء عالي، تستخدم Apache APISIX خوارزمية مطابقة المسارات القائمة على شجرة البادئات المكتوبة بلغة C، وعلى هذا الأساس، توفر واجهة لـ Lua باستخدام FFI المقدمة من LuaJIT. مرونة Lua تمكن أيضًا وحدة توزيع المسارات في Apache APISIX من دعم مطابقة المسارات الفرعية لنفس البادئة بسهولة من خلال تعبيرات محددة وغيرها من الطرق. في النهاية، عن طريق استبدال وظيفة توزيع المسارات الأصلية لـ NGINX، تحقق وظيفة التكوين الديناميكي بأداء عالي ومرونة. للحصول على التفاصيل الكاملة لتنفيذ هذه الميزة، يمكنك الرجوع إلى lua-resty-radixtree و route.lua.

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

علاوة على ذلك، بالإضافة إلى تطوير الإضافات والميزات الأخرى باستخدام LuaJIT، تدعم Apache APISIX أيضًا تطوير الإضافات باستخدام لغات مختلفة مثل Java، Go، Node، Python، و WASM. هذا يقلل بشكل كبير من عتبة التطوير المخصص لـ Apache APISIX، مما يؤدي إلى نظام بيئي غني للإضافات ومجتمع مفتوح المصدر نشط.

مبدأ الإضافات والنظام البيئي لـ Apache APISIX

الخلاصة

LuaJIT هو تنفيذ لـ Lua، مترجم Just-In-Time.

كبوتة API مفتوحة المصدر ديناميكية، في الوقت الحقيقي، وأداء عالي، توفر Apache APISIX وظائف إدارة حركة مرور غنية مثل موازنة الحمل، المصدر الديناميكي، الإصدار التجريبي، كسر الدائرة، المصادقة، والمراقبة، بناءً على الأداء العالي والمرونة العالية التي توفرها NGINX و LuaJIT.

حاليًا، أصدرت Apache APISIX إصدارًا جديدًا، 3.x، والذي يتضمن المزيد من التكاملات مع مشاريع مفتوحة المصدر ومزودي السحابة، دعم gRPC الأصلي، خيارات إضافية لتطوير الإضافات، ودعم شبكة الخدمات. انضم إلى مجتمع Apache APISIX لمعرفة المزيد عن تطبيق LuaJIT في بوابات API السحابية الأصلية.

Tags: