插件編排在 Apache APISIX 中的應用與實踐

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文作者琚致遠,Apache APISIX PMC,支流科技企業產品與大前端技術負責人。通過閱讀本文,您可以瞭解 Apache APISIX 與基本使用場景,以及在低代碼潮流下,Apache APISIX 是如何集成“拖拽”的插件編排能力的。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼是 Apache APISIX?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Apache APISIX 是一個生產可用的七層全流量處理平臺,可作爲 API 網關處理業務入口流量,具有極高性能、超低延遲的顯著特性。它內置了 50 多種插件,覆蓋身份驗證、安全防護、流量控制、Serverless、可觀測性等多個方面,可滿足企業客戶常見的使用場景。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如下方架構圖所示,Apache APISIX 分爲數據面(左側)與控制面(右側)兩部分:通過控制面下發配置到 ETCD,數據面藉助豐富的插件處理內外流量。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/98/98a40530d58f71da402d075aea3022b2.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Apache APISIX 暴露了一組接口,方便我們爲 API 綁定插件。如果我們希望爲 API 增加限速能力,只需爲 API 綁定 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"limit-req","attrs":{}}],"attrs":{}},{"type":"text","text":" 插件:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"shell"},"content":[{"type":"text","text":"curl -X PUT http://127.0.0.1:9080/apisix/admin/routes/1 -d '\n {\n   \"uri\": \"/get\",\n   \"methods\": [\"GET\"],\n   \"upstream\": {\n     \"type\": \"roundrobin\",\n     \"nodes\": {\n       \"httpbin.org:80\": 1\n     }\n   },\n   \"plugins\": {\n     \"limit-req\": {\n       \"rate\": 1,\n       \"burst\": 2,\n       \"rejected_code\": 503,\n       \"key\": \"remote_addr\"\n     }\n   }\n }’","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"調用成功後,當請求到達該 API 時將進行限速管控。該示例使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"limit-req","attrs":{}}],"attrs":{}},{"type":"text","text":" 實現 API 限速(特定功能),若針對“根據某個插件的處理結果,決定後續的請求處理邏輯”這種場景化需求,該怎麼做呢?當前,現有的插件機制無法滿足這種需求,這時便引申出插件編排的能力來解決這個問題。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼是插件編排?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"插件編排是低代碼的一種表現形式,它可以幫助企業降低使用成本、增加運維效率,是企業數字化轉型過程中不可或缺的能力。藉助低代碼 API 網關 Apache APISIX 中插件編排能力,我們可以輕鬆地將 50+ 插件通過“拖拽”的方式進行組合編排,被編排的插件也能夠共享上下文信息,最終實現場景化需求。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"擴展上述 API 限速的場景:請求使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"key-auth","attrs":{}}],"attrs":{}},{"type":"text","text":"插件進行身份認證,若認證通過,將由","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"kafka-logger","attrs":{}}],"attrs":{}},{"type":"text","text":" 插件接管並進行日誌記錄;若認證失敗(插件返回 401 狀態碼),將使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"limit-req","attrs":{}}],"attrs":{}},{"type":"text","text":" 插件進行限速。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"見如下操作視頻:","attrs":{}}]},{"type":"video","attrs":{"videoHTML":""}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"該視頻中,Web 界面列出了目前已有的插件與畫板,我們可以將插件拖拽到畫板上進行編排,並填寫插件綁定的數據,然後便完成了整個流程。在整個過程中:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":"","normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"操作可視化:/我們除了可以使用界面可視化創建 API 之外,還可以通過編排能力直觀、清晰地進行場景化設計;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"流程可複用:通過導入、導出畫板的 JSON 數據,可以便捷地複用編排生成的工程數據;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"組合新“插件”:將每一個場景視作一個插件,通過使用條件元件組合不同的插件,來實現插件創造“插件”。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"實現原理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼 Apache APISIX 是如何與低代碼能力結合的呢?這需要數據面 Apache APISIX 與控制面 Apache APISIX Dashboard 共同配合完成。整體流程如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/11/11bbd18d149ba529f35efabb791e38a0.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Apache APISIX","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Apache APISIX 中,我們在 Route 實體中新增了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"script","attrs":{}}],"attrs":{}},{"type":"text","text":" 執行邏輯(PR:","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/apache/apisix/pull/1982","title":null,"type":null},"content":[{"type":"text","text":"https://github.com/apache/apisix/pull/1982","attrs":{}}]},{"type":"text","text":"),可用於接收 Dashboard 生成的 Lua 函數並執行,它支持調用已有插件以複用代碼。另外,它也作用於 HTTP 請求的生命週期中的各個階段,如 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"access","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"header_filer","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"body_filter","attrs":{}}],"attrs":{}},{"type":"text","text":" 等,系統會在相應階段自動執行 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"script","attrs":{}}],"attrs":{}},{"type":"text","text":" 函數對應階段代碼,見如下 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"script","attrs":{}}],"attrs":{}},{"type":"text","text":" 示例:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"shell"},"content":[{"type":"text","text":"{\n  \"script\": \"local _M = {} \\n function _M.access(api_ctx) \\n ngx.log(ngx.INFO,\\\"hit access phase\\\") \\n end \\nreturn _M\"\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Apache APISIX Dashboard","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Dashboard 中,它包含了 Web 與 ManagerAPI 共兩個子組件:Web 用於提供可視化界面,方便我們配置 API 網關;ManagerAPI 用於提供 RESTful API,供 Web 或其它客戶端調用以便操作配置中心(默認爲 ETCD),進而間接地控制 Apache APISIX。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了生成合法、有效的 script 函數,ManagerAPI 選擇了 DAG 有向無環圖的數據結構進行底層設計,並自主研發了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dag-to-lua","attrs":{}}],"attrs":{}},{"type":"text","text":" 項目(GitHub:","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/api7/dag-to-lua","title":null,"type":null},"content":[{"type":"text","text":"https://github.com/api7/dag-to-lua","attrs":{}}]},{"type":"text","text":"):它將根節點作爲開始節點,根據判斷條件決定下一個流轉插件,這將有效避免邏輯死循環。如下爲 DAG 數據結構的示意圖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/88/8898e4a669ad9202db76694b3a7b00d5.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對應到 ManagerAPI 接收的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"script","attrs":{}}],"attrs":{}},{"type":"text","text":" 參數上,示例如下:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"{\n \"conf\": {\n   \"1-2-3\": {\n     \"name\": \"plugin-a\",\n     \"conf\": {\n       ...\n     }\n   },\n   \"4-5-6\": {\n     \"name\": \"plugin-b\",\n     \"conf\": {\n       ...\n     }\n   },\n   \"7-8-9\": {\n     \"name\": \"plugin-c\",\n     \"conf\": {\n       ...\n     }\n   }\n },\n \"rule\": {\n   \"root\": \"1-2-3\", // 起始節點 ID\n   \"1-2-3\": [\n     [\n       \"code == 200\",\n       \"4-5-6\"\n     ], [\n       \"\",\n       \"7-8-9\"\n     ]\n   ]\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"即客戶端將最終編排後的數據轉換爲上述格式後,ManagerAPI 會藉助 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dag-to-lua","attrs":{}}],"attrs":{}},{"type":"text","text":" 項目生成 Lua 函數,並交給 Apache APISIX 執行。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Web 側,經過挑選、對比與項目驗證,我們選擇了螞蟻金服開源的 X6 圖編輯引擎作爲插件編排 Web 部分的底層框架,除了完善、清晰的文檔外,一系列開箱即用的交互組件以及節點可定製化能力也是我們選擇它的原因。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5e/5e6800d6dc004c76ca9a14b9f15b3919.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在編排實現過程中,我們抽象出了通用元件與插件元件的概念:通用元件是指開始節點、結束節點與條件判斷節點,插件元件則是每一個可用的 Apache APISIX 插件,通過將這些元件拖拽到畫板中來完成插件編排的流程。如圖所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/64/6465a2ebc6412716dcb0b4d2ec46edea.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在拖拽過程中,我們需要限制一系列的邊界條件,這裏有幾個例子:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當插件未配置時,系統將出現「存在未配置的元件」的錯誤提示,可以直觀地看到哪個插件沒有配置數據:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3c/3c7f52df57c74043ce1947b63136b444.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當編輯某條 API 時,若該 API 已經綁定了插件數據,當使用插件編排模式時,系統在檢測後將出現警告信息,只有用戶明確確認希望使用編排模式時,系統才能繼續進行。這可以有效避免 API 數據被誤操作的情況。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e9/e930d6dff9b9d9b2f009b94c6f2362a3.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此外,還存在諸如開始元件只能有一個輸出、條件判斷元件只能有一個輸入等情況。試想:如果系統不加限制地讓用戶操作,不合理的插件組合既無意義,又會產生無法預料的錯誤,因此不斷豐富邊界條件,也是在設計插件編排時需要着重考慮的問題。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當我們完成編排後,將使用 X6 暴露的 API 生成流程圖的 JSON 數據,然後轉換爲系統需要的 DAG 數據,最終生成 Lua 函數。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"未來展望","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過拖拽的方式,可以使得使用人員更方便地組合插件來滿足不同的場景,以提升 API 網關可擴展能力與運維體驗。在實際使用過程中,存在如下可以繼續優化的問題:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":"","normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"目前元件的邊界判斷條件還不夠豐富,通過繼續完善這些條件,以減少不合理的編排組合;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"當前編排示例不多,提供更多的參考示例可方便開發者學習、供用戶使用;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"當前 Apache APISIX 使用了插件定義的 code 進行狀態返回(異常則返回狀態碼,請求終止),可以支持更多 HTTP Response 字段甚至修改插件定義來擴展插件編排能力,如下述插件定義:","attrs":{}}]}]}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"local _M = {\n version = 0.1,\n priority = 2500,\n type = 'auth',\n name = plugin_name,\n schema = schema,\n # 新增的 result 字段,可存儲插件運行結果,並傳遞到下個插件。\n result = {\n   code = {\n     type = \"int\"\n   }\n }\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"關於 Apache APISIX","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Apache APISIX 是一個動態、實時、高性能的開源 API 網關,提供負載均衡、動態上游、灰度發佈、服務熔斷、身份認證、可觀測性等豐富的流量管理功能。Apache APISIX 可以幫忙企業快速、安全的處理 API 和微服務流量,包括網關、Kubernetes Ingress 和服務網格等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"全球已有數百家企業使用 Apache APISIX 處理關鍵業務流量,涵蓋金融、互聯網、製造、零售、運營商等等,比如美國航空航天局(NASA)、歐盟的數字工廠、中國航信、中國移動、騰訊、華爲、微博、網易、貝殼找房、360、泰康、奈雪的茶等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"200 餘位貢獻者,一同締造了 Apache APISIX 這個世界上最活躍的開源網關項目。聰明的開發者們!快來加入這個活躍而多樣化的社區,一起來給這個世界帶來更多美好的東西吧!","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Apache APISIX 項目地址:","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/apache/apisix","title":null,"type":null},"content":[{"type":"text","text":"https://github.com/apache/apisix","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Apache APISIX 官網:","attrs":{}},{"type":"link","attrs":{"href":"http://apisix.apache.org/zh/","title":null,"type":null},"content":[{"type":"text","text":"http://apisix.apache.org/zh/","attrs":{}}]}]}]}],"attrs":{}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章