ओपनरेस्टी में उपयोग किए जाने वाले NGINX का ज्ञान
API7.ai
September 17, 2022
पिछले पोस्ट के माध्यम से, आप OpenResty के बारे में सामान्य ज्ञान प्राप्त कर चुके हैं। निम्नलिखित कुछ लेखों में, मैं आपको OpenResty के दो मुख्य आधारों: NGINX और LuaJIT के बारे में बताऊंगा, और इन मूल बातों को समझकर आप OpenResty को बेहतर ढंग से सीख सकते हैं।
आज मैं NGINX से शुरू करूंगा, और यहां मैं केवल कुछ NGINX मूल बातों का परिचय दूंगा जो OpenResty में उपयोग किए जा सकते हैं, जो NGINX का एक छोटा सा हिस्सा है।
कॉन्फ़िगरेशन के संबंध में, OpenResty विकास में, हमें निम्नलिखित बिंदुओं पर ध्यान देना चाहिए।
nginx.confको जितना संभव हो उतना कम कॉन्फ़िगर करें।if,set,rewriteजैसे कई निर्देशों के संयोजन का उपयोग करने से बचें।- जब Lua कोड से समस्या का समाधान किया जा सकता है, तो NGINX कॉन्फ़िगरेशन, वेरिएबल्स और मॉड्यूल का उपयोग न करें।
ये तरीके पठनीयता, रखरखाव और विस्तार क्षमता को अधिकतम करेंगे। निम्नलिखित NGINX कॉन्फ़िगरेशन कोड के रूप में कॉन्फ़िगरेशन का एक खराब उदाहरण है।
location ~ ^/mobile/(web/app.htm) { set $type $1; set $orig_args $args; if ( $http_user_Agent ~ "(iPhone|iPad|Android)" ) { rewrite ^/mobile/(.*) http://touch.foo.com/mobile/$1 last; } proxy_pass http://foo.com/$type?$orig_args; }
यह वह है जिसे OpenResty के साथ विकसित करते समय हमें टालना चाहिए।
NGINX कॉन्फ़िगरेशन
NGINX अपने व्यवहार को कॉन्फ़िगरेशन फ़ाइलों के माध्यम से नियंत्रित करता है, जिसे एक सरल DSL के रूप में सोचा जा सकता है। NGINX प्रक्रिया शुरू होने पर कॉन्फ़िगरेशन को पढ़ता है और इसे मेमोरी में लोड करता है। यदि आप कॉन्फ़िगरेशन फ़ाइल को संशोधित करते हैं, तो आपको NGINX को पुनः आरंभ करना होगा या रीलोड करना होगा और NGINX द्वारा कॉन्फ़िगरेशन फ़ाइल को फिर से पढ़ने तक प्रतीक्षा करनी होगी ताकि नई कॉन्फ़िगरेशन प्रभावी हो सके। केवल NGINX का वाणिज्यिक संस्करण रनटाइम पर कुछ गतिशील क्षमता प्रदान करता है, जो API के रूप में होती है।
आइए निम्नलिखित कॉन्फ़िगरेशन से शुरू करें, जो बहुत सरल है।
worker_processes auto; pid logs/nginx.pid; error_log logs/error.log notice; worker_rlimit_nofile 65535; events { worker_connections 16384; } http { server { listen 80; listen 443 ssl; location / { proxy_pass https://foo.com; } } } stream { server { listen 53 udp; } }
हालांकि, यहां तक कि ये सरल कॉन्फ़िगरेशन भी कुछ मूलभूत अवधारणाओं को शामिल करते हैं।
सबसे पहले, प्रत्येक निर्देश का अपना संदर्भ होता है, जो NGINX कॉन्फ़िगरेशन फ़ाइल में इसका दायरा होता है।
सबसे ऊपरी स्तर main है, जिसमें कुछ निर्देश होते हैं जो विशिष्ट व्यवसाय से संबंधित नहीं होते हैं, जैसे worker_processes, pid, और error_log, जो सभी main संदर्भ का हिस्सा हैं। इसके अलावा, संदर्भों के बीच एक पदानुक्रमिक संबंध होता है। उदाहरण के लिए, location का संदर्भ server है, server का संदर्भ http है, और http का संदर्भ main है।
निर्देश गलत संदर्भ में नहीं चलाए जा सकते हैं। NGINX शुरू होने पर nginx.conf की वैधता की जांच करेगा। उदाहरण के लिए, यदि हम listen 80; को server संदर्भ से main संदर्भ में बदलते हैं और NGINX सेवा शुरू करते हैं, तो हम इस तरह की एक त्रुटि देखेंगे:
"listen" directive is not allowed here ......
दूसरा, NGINX न केवल HTTP अनुरोध और HTTPS ट्रैफ़िक को संभाल सकता है, बल्कि UDP और TCP ट्रैफ़िक को भी संभाल सकता है। L7 HTTP में है और L4 Stream में है। OpenResty में, lua-nginx-module और stream-lua-nginx-module इन दोनों के लिए क्रमशः जिम्मेदार हैं।
यहां एक बात ध्यान देने योग्य है कि OpenResty NGINX में सभी सुविधाओं का समर्थन नहीं करता है, और आपको OpenResty के संस्करण को देखना होगा। OpenResty का संस्करण NGINX के साथ मेल खाता है, जिससे इसे पहचानना आसान हो जाता है।
nginx.conf में शामिल कॉन्फ़िगरेशन निर्देश NGINX कोर मॉड्यूल ngx_core_module, ngx_http_core_module, और ngx_stream_core_module में हैं, जिन्हें आप विशिष्ट दस्तावेज़ देखने के लिए क्लिक कर सकते हैं।
MASTER-WORKER मोड
कॉन्फ़िगरेशन फ़ाइल को समझने के बाद, आइए NGINX के मल्टी-प्रोसेस मोड को देखें (जैसा कि नीचे दिए गए चित्र में दिखाया गया है)। जैसा कि आप देख सकते हैं, जब NGINX शुरू होता है, तो एक Master प्रक्रिया और कई Worker प्रक्रियाएं (या केवल एक Worker प्रक्रिया, यह इस बात पर निर्भर करता है कि आपने इसे कैसे कॉन्फ़िगर किया है) होगी।

सबसे पहले, Master प्रक्रिया, जैसा कि इसके नाम से पता चलता है, "प्रबंधक" की भूमिका निभाती है और क्लाइंट से अनुरोधों को संभालने के लिए जिम्मेदार नहीं है। यह Worker प्रक्रियाओं का प्रबंधन करती है, जिसमें प्रशासक से संकेत प्राप्त करना और Worker प्रक्रियाओं की स्थिति की निगरानी करना शामिल है। जब एक Worker प्रक्रिया असामान्य रूप से बाहर हो जाती है, तो Master प्रक्रिया एक नई Worker प्रक्रिया को पुनः आरंभ करेगी।
Worker प्रक्रियाएं "वास्तविक काम करने वाले कर्मचारी" हैं जो क्लाइंट से अनुरोधों को संभालती हैं। ये Master प्रक्रिया से फोर्क की जाती हैं और एक दूसरे से स्वतंत्र होती हैं। यह मल्टी-प्रोसेस मॉडल Apache के मल्टी-थ्रेडेड मॉडल की तुलना में बहुत अधिक उन्नत है, जिसमें क्रॉस-थ्रेड लॉकिंग नहीं होती है और डिबगिंग आसान होती है। यहां तक कि अगर एक प्रक्रिया क्रैश हो जाती है और बाहर हो जाती है, तो यह आमतौर पर अन्य Worker प्रक्रियाओं के काम को प्रभावित नहीं करती है।
OpenResty ने NGINX Master-Worker मॉडल में एक अद्वितीय विशेषाधिकार प्राप्त एजेंट जोड़ा है। यह प्रक्रिया किसी भी पोर्ट को सुनती नहीं है और NGINX Master प्रक्रिया के समान विशेषाधिकार रखती है, इसलिए यह कुछ उच्च विशेषाधिकार वाले कार्य कर सकती है, जैसे कि स्थानीय डिस्क फ़ाइलों पर कुछ लेखन संचालन।
यदि विशेषाधिकार प्राप्त प्रक्रिया NGINX बाइनरी हॉट अपग्रेड तंत्र के साथ काम करती है, तो OpenResty बाहरी प्रोग्राम पर निर्भर किए बिना पूरे बाइनरी को ऑन-द-फ्लाई अपग्रेड कर सकता है।
बाहरी प्रोग्राम पर निर्भरता को कम करना और समस्याओं को OpenResty प्रक्रिया के भीतर हल करने का प्रयास करना, तैनाती को सुविधाजनक बनाता है, संचालन और रखरखाव लागत को कम करता है, और प्रोग्राम त्रुटियों की संभावना को कम करता है। OpenResty में विशेषाधिकार प्राप्त प्रक्रिया और ngx.pipe इसी उद्देश्य के लिए हैं।
निष्पादन चरण
निष्पादन चरण भी NGINX की एक आवश्यक विशेषता है और OpenResty की विशिष्ट कार्यान्वयन से निकटता से जुड़े हुए हैं। NGINX में 11 निष्पादन चरण हैं, जिन्हें हम ngx_http_core_module.h के स्रोत कोड में देख सकते हैं:
typedef enum { NGX_HTTP_POST_READ_PHASE = 0, NGX_HTTP_SERVER_REWRITE_PHASE, NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE, NGX_HTTP_POST_REWRITE_PHASE, NGX_HTTP_PREACCESS_PHASE, NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, NGX_HTTP_PRECONTENT_PHASE, NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE } ngx_http_phases;
यदि आप इन 11 चरणों की भूमिका के बारे में अधिक जानना चाहते हैं, तो आप NGINX दस्तावेज़ीकरण पढ़ सकते हैं, इसलिए मैं यहां इस पर विस्तार से नहीं जाऊंगा।
संयोग से, OpenResty में भी NGINX चरण से संबंधित 11 *_by_lua निर्देश हैं, जैसा कि नीचे दिए गए चित्र में दिखाया गया है (lua-nginx-module दस्तावेज़ीकरण से)।

init_by_lua केवल तब निष्पादित होता है जब Master प्रक्रिया बनाई जाती है, और init_worker_by_lua केवल तब निष्पादित होता है जब प्रत्येक Worker प्रक्रिया बनाई जाती है। अन्य *_by_lua कमांड क्लाइंट अनुरोधों द्वारा ट्रिगर किए जाते हैं और बार-बार निष्पादित होते हैं।
इसलिए init_by_lua चरण के दौरान, हम Lua मॉड्यूल और सार्वजनिक केवल-पढ़ने योग्य डेटा को प्रीलोड कर सकते हैं ताकि OS की COW (कॉपी ऑन राइट) सुविधा का लाभ उठाकर मेमोरी बचाई जा सके।
अधिकांश ऑपरेशन content_by_lua के अंदर किए जा सकते हैं, लेकिन मैं इसे विभिन्न कार्यों के अनुसार विभाजित करने की सलाह दूंगा, जैसे निम्नलिखित।
set_by_lua: वेरिएबल्स सेट करना।rewrite_by_lua: फॉरवर्डिंग, रीडायरेक्शन, आदि।access_by_lua: पहुंच, अनुमतियां, आदि।content_by_lua: वापसी सामग्री उत्पन्न करना।header_filter_by_lua: प्रतिक्रिया हेडर फ़िल्टरिंग प्रसंस्करण।body_filter_by_lua: प्रतिक्रिया बॉडी फ़िल्टरिंग प्रसंस्करण।log_by_lua: लॉगिंग।
मैं आपको एक उदाहरण दिखाता हूं कि इसे इस तरह से विभाजित करने के लाभ क्या हैं। मान लीजिए कि बाहरी रूप से कई प्लेनटेक्स्ट API प्रदान किए जाते हैं, और अब हमें कस्टम एन्क्रिप्शन और डिक्रिप्शन लॉजिक जोड़ने की आवश्यकता है। तो, क्या हमें सभी API के कोड को बदलने की आवश्यकता है?
location /mixed { content_by_lua '...'; }
बिल्कुल नहीं। चरण सुविधा का उपयोग करके, हम access चरण में डिक्रिप्ट कर सकते हैं और body filter चरण में एन्क्रिप्ट कर सकते हैं, मूल content चरण में कोड में किसी भी बदलाव किए बिना।
location /mixed { access_by_lua '...'; content_by_lua '...'; body_filter_by_lua '...'; }
ऑन-द-फ्लाई NGINX बाइनरी अपग्रेड
अंत में, मैं संक्षेप में ऑन-द-फ्लाई NGINX बाइनरी अपग्रेड के बारे में बताऊंगा। हम जानते हैं कि NGINX कॉन्फ़िगरेशन फ़ाइल को संशोधित करने के बाद, इसे काम करने के लिए रीलोड करने की आवश्यकता होती है। लेकिन जब NGINX खुद को अपग्रेड करता है, तो यह ऑन-द-फ्लाई कर सकता है। यह गाड़ी को घोड़े से पहले रखने जैसा लग सकता है, लेकिन यह समझ में आता है क्योंकि NGINX पारंपरिक स्थिर लोड बैलेंसिंग, रिवर्स प्रॉक्सी और फ़ाइल कैशिंग से शुरू हुआ था।
हॉट अपग्रेड पुराने Master प्रक्रिया को USR2 और WINCH सिग्नल भेजकर किया जाता है। इन दो चरणों के लिए, पहला नया Master प्रक्रिया शुरू करता है; दूसरा Worker प्रक्रिया को धीरे-धीरे बंद करता है।
इन दो चरणों के बाद, नया Master और नया Worker शुरू हो जाते हैं। इस बिंदु पर, पुराना Master बाहर नहीं होता है। बाहर न होने का कारण सरल है: यदि आपको वापस जाने की आवश्यकता होती है, तो आप अभी भी पुराने Master को HUP सिग्नल भेज सकते हैं। बेशक, यदि आपने निर्धारित कर लिया है कि आपको वापस जाने की आवश्यकता नहीं है, तो आप पुराने Master को KILL सिग्नल भेजकर बाहर कर सकते हैं।
बस, और ऑन-द-फ्लाई NGINX बाइनरी अपग्रेड हो गया है।
यदि आप इसके बारे में अधिक विस्तृत जानकारी जानना चाहते हैं, तो आप आधिकारिक दस्तावेज़ीकरण देख सकते हैं और सीखना जारी रख सकते हैं।
सारांश
सामान्य तौर पर, OpenResty में आप जो उपयोग करते हैं वह NGINX की मूल बातें हैं, मुख्य रूप से कॉन्फ़िगरेशन, मास्टर-स्लेव प्रक्रियाएं, निष्पादन चरण, आदि से संबंधित हैं। अन्य चीजें जो Lua कोड से हल की जा सकती हैं, उन्हें कोड से हल करने का प्रयास करें, NGINX मॉड्यूल और कॉन्फ़िगरेशन का उपयोग करने के बजाय, यह OpenResty सीखते समय सोच में बदलाव है।
अंत में, मैंने आपके लिए एक खुला प्रश्न छोड़ा है: Nginx आधिकारिक तौर पर NJS का समर्थन करता है, जिसका अर्थ है कि आप NGINX लॉजिक को नियंत्रित करने के लिए JS लिख सकते हैं, OpenResty के समान। आप इसके बारे में क्या सोचते हैं? इस लेख को साझा करने के लिए आपका स्वागत है।