Apache APISIX कैसे Wasm Functionality को सक्षम बनाता है

Xinxin Zhu

April 7, 2023

Products

वेब ब्राउज़र में उच्च-प्रदर्शन वाले एप्लिकेशन चलाने के लिए, Apache APISIX गेटवे स्तर पर Wasm का समर्थन करता है, जो एक बाइनरी इंस्ट्रक्शन फॉर्मेट है जो वेब पर कोड के कुशल और सुरक्षित निष्पादन को सक्षम बनाता है। परिणामस्वरूप, डेवलपर्स C/C++/Go/Rust जैसी उच्च-स्तरीय प्रोग्रामिंग भाषाओं का उपयोग कर सकते हैं और proxy-wasm स्पेसिफिकेशन का पालन करके Wasm प्लगइन्स बना सकते हैं। proxy-wasm स्पेसिफिकेशन अन्य सिस्टम्स के साथ संगतता और इंटरऑपरेबिलिटी सुनिश्चित करता है। आइए इस लेख में जाएं और अधिक विवरण जानें।

Wasm क्या है

WebAssembly (संक्षिप्त में Wasm) एक स्टैक-आधारित वर्चुअल मशीन के लिए एक बाइनरी इंस्ट्रक्शन फॉर्मेट है।

Wasm के उभरने से पहले, केवल Javascript को वेब ब्राउज़र में निष्पादित किया जा सकता था। हालांकि, Wasm के आगमन के साथ, C/C++/Golang जैसी उच्च-स्तरीय भाषाएं अब वेब ब्राउज़र में चलाई जा सकती हैं। Chrome, Firefox, और Safari जैसे प्रमुख ब्राउज़र अब सभी Wasm का समर्थन करते हैं। इसके अलावा, WASI (WebAssembly System Interface) प्रोजेक्ट द्वारा की गई प्रगति के कारण, सर्वर-साइड वातावरण भी Wasm इंस्ट्रक्शन के निष्पादन का समर्थन कर सकते हैं।

वर्तमान में, Apache APISIX गेटवे स्तर पर Wasm का समर्थन करता है। डेवलपर्स C/C++/Go/Rust जैसी उच्च-स्तरीय प्रोग्रामिंग भाषाओं का उपयोग कर सकते हैं और proxy-wasm स्पेसिफिकेशन का पालन करके Wasm प्लगइन्स बना सकते हैं।

wasm

APISIX Wasm प्लगइन्स का समर्थन क्यों करता है?

मूल Lua प्लगइन्स की तुलना में, Wasm प्लगइन्स कई फायदे प्रदान करते हैं:

  • स्केलेबिलिटी: Wasm का समर्थन करके, APISIX C++, Golang, और Rust जैसी उच्च-स्तरीय प्रोग्रामिंग भाषाओं में प्लगइन्स विकसित करने के लिए proxy-wasm द्वारा प्रदान किए गए SDK का उपयोग कर सकता है। इन भाषाओं में अक्सर समृद्ध इकोसिस्टम होते हैं, जो डेवलपर्स को अधिक सुविधाओं वाले प्लगइन्स को लागू करने की अनुमति देते हैं।

  • सुरक्षा: चूंकि APISIX और Wasm के बीच की इंटरैक्शन proxy-wasm द्वारा प्रदान किए गए Application Binary Interface (ABI) पर निर्भर करती है, यह पहुंच अधिक सुरक्षित है। Wasm प्लगइन्स केवल अनुरोधों में विशिष्ट संशोधन कर सकते हैं, यह सुनिश्चित करते हुए कि वे दुर्भावनापूर्ण कार्य नहीं कर सकते। इसके अलावा, चूंकि Wasm प्लगइन्स एक अलग VM में चलते हैं, यहां तक कि अगर प्लगइन क्रैश हो जाता है, तो यह मुख्य APISIX प्रक्रिया को प्रभावित नहीं करेगा।

APISIX Wasm का समर्थन कैसे करता है?

अब जब हम समझ गए हैं कि Wasm क्या है, तो आइए एक शीर्ष-डाउन दृष्टिकोण से देखें कि APISIX Wasm प्लगइन्स का समर्थन कैसे करता है।

apisix-wasm

APISIX Wasm प्लगइन्स

APISIX डेवलपर्स को C/C++, Go, और Rust जैसी लोकप्रिय उच्च-स्तरीय प्रोग्रामिंग भाषाओं का उपयोग करके प्लगइन्स बनाने की अनुमति देता है। इन प्लगइन्स को संबंधित SDK का उपयोग करके और proxy-wasm स्पेसिफिकेशन का पालन करके बनाया जा सकता है।

proxy-wasm L4/L7 प्रॉक्सी के बीच ABIs के लिए एक स्पेसिफिकेशन है, जिसे Envoy द्वारा पेश किया गया है। यह स्पेसिफिकेशन मेमोरी प्रबंधन, L4 प्रॉक्सी, और L7 प्रॉक्सी एक्सटेंशन सहित ABIs को परिभाषित करता है। उदाहरण के लिए, HTTP(L7) में, proxy-wasm स्पेसिफिकेशन proxy_on_http_request_headers, proxy_on_http_request_body, proxy_on_http_request_trailers, और proxy_on_http_response_headers जैसी ABIs को परिभाषित करता है, जो मॉड्यूल को विभिन्न चरणों में अनुरोध सामग्री को पुनः प्राप्त करने और संशोधित करने की अनुमति देता है।

उदाहरण के लिए, हम Golang और proxy-wasm-go-sdk का उपयोग करके इस प्लगइन को विकसित करेंगे:

proxy-wasm-go-sdk proxy-wasm स्पेसिफिकेशन के लिए एक SDK है जो डेवलपर्स को Golang का उपयोग करके proxy-wasm प्लगइन्स को आसानी से बनाने में मदद करता है। हालांकि, यह ध्यान रखना महत्वपूर्ण है कि मूल Golang के WASI समर्थन में कुछ समस्याओं के कारण, यह SDK TinyGo पर आधारित है। अधिक जानकारी के लिए, आप यहां क्लिक कर सकते हैं विवरण देखने के लिए।

इस प्लगइन का मुख्य कार्य एक HTTP संशोधन अनुरोध के HTTP प्रतिक्रिया स्थिति कोड और प्रतिक्रिया बॉडी को संशोधित करना है, जैसा कि APISIX लिंक से संदर्भित है।

... func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int) types.OnPluginStartStatus { data, err := proxywasm.GetPluginConfiguration() if err != nil { proxywasm.LogErrorf("error reading plugin configuration: %v", err) return types.OnPluginStartStatusFailed } var p fastjson.Parser v, err := p.ParseBytes(data) if err != nil { proxywasm.LogErrorf("error decoding plugin configuration: %v", err) return types.OnPluginStartStatusFailed } ctx.Body = v.GetStringBytes("body") ctx.HttpStatus = uint32(v.GetUint("http_status")) if v.Exists("percentage") { ctx.Percentage = v.GetInt("percentage") } else { ctx.Percentage = 100 } // schema check if ctx.HttpStatus < 200 { proxywasm.LogError("bad http_status") return types.OnPluginStartStatusFailed } if ctx.Percentage < 0 || ctx.Percentage > 100 { proxywasm.LogError("bad percentage") return types.OnPluginStartStatusFailed } return types.OnPluginStartStatusOK } func (ctx *httpLifecycle) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action { plugin := ctx.parent if !sampleHit(plugin.Percentage) { return types.ActionContinue } err := proxywasm.SendHttpResponse(plugin.HttpStatus, nil, plugin.Body, -1) if err != nil { proxywasm.LogErrorf("failed to send local response: %v", err) return types.ActionContinue } return types.ActionPause } ...

इसके बाद, हम TinyGo का उपयोग करके उपरोक्त Golang कोड को संकलित करते हैं और एक .wasm फ़ाइल उत्पन्न करते हैं।

tinygo build -o wasm_fault_injection.go.wasm -scheduler=none -target=wasi ./main.go

संकलन पूरा होने के बाद, हमें fault_injection.go.wasm फ़ाइल प्राप्त होती है।

यदि आप wasm फ़ाइल की सामग्री में रुचि रखते हैं, तो आप wasm-tool का उपयोग करके wasm फ़ाइल की विशिष्ट सामग्री देख सकते हैं। wasm-tools dump hello.go.wasm

APISIX के config.yaml फ़ाइल में wasm_fault_injection.go.wasm को कॉन्फ़िगर करें और प्लगइन का नाम wasm_fault_injection रखें।

apisix: ... wasm: plugins: - name: wasm_fault_injection priority: 7997 file: wasm_fault_injection.go.wasm

इसके बाद, हम APISIX शुरू करते हैं और Wasm प्लगइन को संदर्भित करने वाला एक रूट बनाते हैं:

curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{ "uri":"/*", "upstream":{ "type":"roundrobin", "timeout":{ "connect":1, "read":1, "send":1 }, "nodes":{ "httpbin.org:80":1 } }, "plugins":{ "wasm_fault_injection":{ "conf":"{\"http_status\":200, \"body\":\"Hello WebAssembly!\n\"}" } }, "name":"wasm_fault_injection" }'

एक्सेस टेस्ट करने के बाद, हमने पाया कि प्रतिक्रिया बॉडी को "Hello WebAssembly" में संशोधित कर दिया गया है, जो इंगित करता है कि Wasm प्लगइन अब प्रभावी है।

curl 127.0.0.1:9080/get -v * Trying 127.0.0.1:9080... * Connected to 127.0.0.1 (127.0.0.1) port 9080 (#0) > GET /get HTTP/1.1 > Host: 127.0.0.1:9080 > User-Agent: curl/7.81.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Thu, 09 Feb 2023 07:46:50 GMT < Content-Type: text/plain; charset=utf-8 < Transfer-Encoding: chunked < Connection: keep-alive < Server: APISIX/3.1.0 < Hello WebAssembly!

Wasm-nginx-module

Apache APISIX द्वारा Wasm प्लगइन्स का उपयोग करने के तरीके को समझने के बाद, आइए गहराई से जानें कि "Wasm प्लगइन्स में अनुरोध सामग्री को कैसे एक्सेस और संशोधित किया जा सकता है?"

चूंकि APISIX अंतर्निहित फ्रेमवर्क के रूप में OpenResty का उपयोग करता है, Wasm प्लगइन्स में अनुरोध सामग्री को एक्सेस और संशोधित करने के लिए, हमें OpenResty या NGINX द्वारा प्रदान किए गए APIs के साथ इंटरैक्ट करने की आवश्यकता होती है। यह वही है जो wasm-nginx-module करता है।

wasm-nginx-module एक NGINX मॉड्यूल है जो Wasm का समर्थन करता है और API7 द्वारा विकसित किया गया है। यह मॉड्यूल NGINX पर आधारित proxy-wasm-abi को लागू करने का प्रयास करता है और Lua API को एनकैप्सुलेट करता है, जो हमें Lua स्तर पर proxy-wasm-abi कॉल को पूरा करने की अनुमति देता है। अधिक जानकारी के लिए, कृपया wasm-nginx-module देखें।

उदाहरण के लिए, जब APISIX access चरण में चलता है, तो यह wasm-nginx-module द्वारा प्रदान की गई Lua मेथड on_http_request_headers को कॉल करता है।

-- apisix/wasm.lua ... local ok, err = wasm.on_http_request_headers(plugin_ctx) if not ok then core.log.error(name, ": failed to run wasm plugin: ", err) return 503 end end ...

बाद में इस मेथड में, wasm-nginx-module द्वारा प्रदान की गई ngx_http_wasm_on_http मेथड को कॉल किया जाएगा।

ngx_int_t ngx_http_wasm_on_http(ngx_http_wasm_plugin_ctx_t *hwp_ctx, ngx_http_request_t *r, ngx_http_wasm_phase_t type, const u_char *body, size_t size, int end_of_body) { ... ctx = ngx_http_wasm_get_module_ctx(r); if (type == HTTP_REQUEST_HEADERS) { cb_name = &proxy_on_request_headers; } else if (type == HTTP_REQUEST_BODY) { cb_name = &proxy_on_request_body; } else if (type == HTTP_RESPONSE_HEADERS) { cb_name = &proxy_on_response_headers; } else { cb_name = &proxy_on_response_body; } if (type == HTTP_REQUEST_HEADERS || type == HTTP_RESPONSE_HEADERS) { if (hwp_ctx->hw_plugin->abi_version == PROXY_WASM_ABI_VER_010) { rc = ngx_wasm_vm->call(hwp_ctx->hw_plugin->plugin, cb_name, true, NGX_WASM_PARAM_I32_I32, http_ctx->id, 0); } else { rc = ngx_wasm_vm->call(hwp_ctx->hw_plugin->plugin, cb_name, true, NGX_WASM_PARAM_I32_I32_I32, http_ctx->id, 0, 1); } } else { rc = ngx_wasm_vm->call(hwp_ctx->hw_plugin->plugin, cb_name, true, NGX_WASM_PARAM_I32_I32_I32, http_ctx->id, size, end_of_body); } ... }

wasm-nginx-module में, हम विभिन्न चरणों के आधार पर cb_name सेट करते हैं, जैसे कि HTTP_REQUEST_HEADERS proxy_on_request_headers से मेल खाता है, और फिर VM में मेथड को ngx_wasm_vm->call के माध्यम से कॉल करते हैं, जो इस लेख में पहले उल्लिखित wasm प्लगइन की OnHttpRequestHeaders मेथड है।

इसके साथ, APISIX द्वारा wasm प्लगइन को कॉल करने और Golang को चलाने की पूरी कॉलिंग चेन पूरी होती है। कॉलिंग चेन इस प्रकार है:

Wasm VM

Wasm VM एक वर्चुअल मशीन है जिसका उपयोग Wasm कोड को निष्पादित करने के लिए किया जाता है। wasm-nginx-module Wasm कोड को निष्पादित करने के लिए दो प्रकार की वर्चुअल मशीन, "wasmtime" और "wasmedge" को लागू करता है। APISIX में, "wasmtime" Wasm कोड चलाने के लिए डिफ़ॉल्ट है।

Wasmtime WebAssembly और WASI के लिए एक तेज़ और सुरक्षित रनटाइम है, जिसे Bytecode Alliance द्वारा ओपन-सोर्स किया गया है। यह वेब वातावरण के बाहर WebAssembly कोड चला सकता है और इसे कमांड-लाइन टूल के रूप में या अन्य प्रोग्राम्स में एक लाइब्रेरी के रूप में एम्बेड किया जा सकता है। Wasmedge एक हल्का, उच्च-प्रदर्शन और स्केलेबल WebAssembly (Wasm) वर्चुअल मशीन है जो एज कंप्यूटिंग के लिए अनुकूलित है। इसका उपयोग क्लाउड-नेटिव, एज, और विकेंद्रीकृत एप्लिकेशन्स के लिए किया जा सकता है।

सबसे पहले, Wasm VM में, हम .wasm फ़ाइल को मेमोरी में लोड करने के लिए load मेथड का उपयोग करते हैं। इसके बाद, हम इन फ़ंक्शन्स को कॉल करने के लिए VM की call मेथड का उपयोग कर सकते हैं। VM WASI इंटरफ़ेस कार्यान्वयन पर आधारित है, जो Wasm कोड को न केवल ब्राउज़र-साइड पर चलाने की अनुमति देता है बल्कि सर्वर-साइड पर चलाने का भी समर्थन करता है।

सारांश

हमने समझ लिया है कि Wasm क्या है और APISIX Wasm प्लगइन्स का समर्थन कैसे करता है। Wasm प्लगइन्स के लिए समर्थन प्रदान करके, APISIX न केवल C++, Rust, Golang, और AssemblyScript जैसी कई भाषाओं में प्लगइन विकास के लिए अपनी क्षमताओं को बढ़ाता है, बल्कि WebAssembly के व्यापक इकोसिस्टम और उपयोग के मामलों से भी लाभ उठाता है, जो ब्राउज़र से परे क्लाउड-नेटिव वातावरण तक विस्तारित हो रहा है।

परिणामस्वरूप, APISIX API गेटवे साइड पर अधिक उन्नत सुविधाएं प्रदान करने के लिए Wasm का लाभ उठा सकता है, जिससे यह व्यापक उपयोग के परिदृश्यों को संबोधित कर सकता है।

Tags: