2019 年 8 月 31 日,OpenResty 社區聯合又拍雲,舉辦 OpenResty × Open Talk 全國巡回沙龍·成都站,APISIX 作者溫銘在活動上做了《 API 網關的選型和持續集成 》的分享。
OpenResty x Open Talk 全國巡回沙龍是由 OpenResty 中國社區、又拍雲發起,邀請業內資深的 OpenResty 技術專家,分享 OpenResty 實戰經驗,增進 OpenResty 使用者的交流與學習,推動 OpenResty 開源項目的發展。
溫銘,深圳支流科技聯合創始人,開源微服務 API 網關 APISIX PMC,OpenResty軟件基金會發起人,《OpenResty 從入門到實戰》專欄作者,創業之前在互聯網安全公司工作了 10 年,主要從事服務端的開發和架構,負責開發過木馬雲查殺、反釣魚系統和企業安全產品。曾在奇虎 360 擔任架構師,開源委員會發起人、委員。
以下是分享全文:
我和院生在做的一個開源的 API 網關項目叫 APISIX,今天介紹這個項目涉及到 OpenResty 的技術和選型,主要包括三個方面:
- 第一, API 網關是什么,它有什么作用;
- 第二,如何去做 API 網關,如何做選型;
- 第三,APISIX 是一個開源項目,介紹我們在只有兩個人的情況下是怎么去做測試和持續集成,里面會涉及 OpenResty 的一些通用的東西,值得大家借鑒。
API 網關的作用
什么是 API 網關
以 Kong 為例,左圖沒有 API 網關,但是后面掛了很多服務,如果每個服務都要實現包括認證、統計、安全校驗等功能,會有很多重復的工作。API 網關的作用就是把這些公共的東西抽取出來,如右圖,下面的這幾個服務,每個服務都只關心自身業務相關的東西,和業務無關的東西全部都丟到API 網關上,即 API 網關就是把公共的東西如統計、安全、限流、限速、緩存等提取出來做了一個中間層。
API 網關的傳統功能
- 讓 API 請求更安全、更高效的得到處理。傳統的 API 網關有一些基本的功能直到現在都適用的,管理不管南北向的還是東西向的 API 流量可以能夠快速、安全地得到處理,這個是 API 網關最原始的目的。
- 覆蓋 Nginx 的所有功能。API 的網關覆蓋了 Nginx 的所有功能,包括反向代理、負載均衡以及基本的緩存、安全的認證、限流限速等。
- 支持 Nginx 等 Web 服務器實現不了的功能。如動態上游、動態 SSL 證書、動態限流限速,以及主動/被動健康檢查、服務熔斷等,這些動態的能力都是傳統的 Nginx、Apache 這類Web 服務器支持不了的。
- 全生命周期管理。在 API 網關領域,最大的玩家是谷歌,谷歌在 2016 年收購了一家上市公司 Apigee,它現在把整個功能集成在谷歌雲上。API 網關除了我們熟悉的反向代理、負載均衡、限流限速的插件外,它還包括了 API 的設計、文檔以及測試等,這一整套都屬於 API 網關的功能,我們叫做 API 的全生命周期管理,從項目設計到測試上線,所有的東西都在整個 API 網關的功能范疇內。
雲原生下的新功能
為什么現在包括 Kong、APISIX 還要把傳統的東西再做一遍呢?這是因為在雲原生和微服務體系下,用戶和技術架構有了一些新的變化:
技術架構新變化
- 需要對接雲原生里面像 Prometheus、Zipkin、Skywalking 等重要組件;
- gRPC 代理和協議轉換(REST<=>gRPC):HTTP 這種協議在微服務里面用的越來越少,很多人開始用 gRPC,那在從 HTTP 到 gRPC 協議的轉換,這種功能也是需要的,包括 gRPC 的代理;
- 身份認證方式改變:在傳統的 Nginx 里面,一般是流量進來后根據路由的規則去做反向代理、負載均衡,很少對發流量的客戶端的身份做認證。但是在雲原生里面就不一樣,因為很多是在微服務里的流量,這里面需要做嚴格的身份認證,包括加密、OpenID 之類的身份認證。這塊就是一些新的功能,可以把自己企業里面需要做身份認證相關的東西放到第三方的外部認證的廠商去做;
- Serverless 也是最近幾年非常火的一個概念,比如希望在邊緣節點上面動態地把一個函數跑起來或者把一個函數給停掉,或者動態地去改里面的內容,你可以把你的 API 網關部署在邊緣節點上,具備了這種 FaaS 的功能,你的邊緣節點就會更加地靈活。APISIX 里面最近就支持了 Serverless,可以讓你的一個 Lua 的函數動態地在邊緣結點跑起來;
- 無狀態、隨意擴容和縮容:API 網關在十多年前性能要求沒有那么高,因為當時互聯網的流量更多地是從瀏覽器到服務端,沒有手機和物聯網的設備,也沒有微服務、內網這些流量。但是現在的流量很大,包括 4G、5G下面有很多的手機、IoT 設備去訪問服務端,流量特別地大。此時,就需要一個性能更高的 API 網關去做支撐。雲原生的一個重要的標准是所有的服務都可以通過容器的方式隨意地去擴容和縮容,對 Kubernetes 友好;
- 支持多雲和混合雲:現在上雲已經是一個趨勢,但是我們一般不太會把服務只放在一個雲上,比如騰訊雲、谷歌雲、阿里雲各放一部分,私有雲再放一部分,根據它們的安全和價格做調整,私有的一些數據安全性更高的放在私有雲上,資源比如和 CDN 相關的哪個便宜就放哪個雲上,做動態的切換,那么此時就需要有一個和廠商無關的 API 網關放在前面做分發。
應用
舉兩個例子,介紹下新的 API 網關是做什么的。
- 替換 Nginx 的所有功能處理南北向的流量
它和 Nginx 比好處很明顯,是完全動態來實現的,不管是 Kong 或 APISIX,動態的都是最基本的點。在 Nginx 里面修改任何一個配置文件,都需要 reload 之后才能生效的。我們設想一個場景,用 Nginx 做最前面的路由,做負載均衡,突發的流量來了,此時需要快速地增加很多上游服務器,就要不停地修改 Nginx 配置文件,然后 reload,等突發流量過了之后再把上游的服務摘掉,那么這時候還要再改 Nginx 文件並 reload 。這個代價是很大的,但是你如果用 Kong、APISIX 這種 Web 服務器,就不會有這樣的問題,通過 API 可以很輕松地實時修改整個集群里面所有機器上游的配置、動態證書的配置,當然性能會比 Nginx 稍微低一點,但是這個低也是可以接受的,因為它帶來了很大的靈活性。現在很多的廠商都是在做這樣的替換,不僅互聯網公司,還有一些傳統企業都在把 Nginx 慢慢地拿掉。
- 零信任網關
近兩年安全領域里很火的概念就是零信任,即zero trust。在傳統的安全領域里面,我們認為邊界防護非常重要,所以會用防火牆對進來的流量做一層校驗,這個校驗其實是命中規則的校驗,如果是黑的就把它拒絕掉。那么這個時候就會有一個問題:如果一些規則更新不及時,它就可以穿越防火牆,以前的安全更多是基於邊界的防護,過了邊界內網是可以暢通無阻的。
但是零信任網關可以徹底解決這個問題,它認為所有的流量都是不安全的,以前的邊界防護是非黑即白。現在的零信任安全網關則是非白即黑,你不是白的,那么你就是黑的,所以它是完全基於身份來認證的。一個 API 的請求過來會到身份認證的服務器,第三方的身份認證廠商比如 Author0、OKTA 的身份認證服務器認證你的身份,身份認證過了,請求才可以通過,不然就直接拒絕掉,這是是安全領域的一個趨勢。
企業用戶的需求
- 不鎖定,可回退
所有企業用戶的最大需求都是:不要鎖定用戶。API 網關是整個流量的入口,不能把用戶鎖定在里面。比如你用了阿里雲的 API 網關,其實你就已經被它鎖定了,因為它是流量的入口,你沒有辦法分發到其它雲廠商上。此外還需要可回退,我使用了這個API 網關,比如原來是 Nginx,我可以很輕松地回退過去,這也是我們在做 APISIX 會考慮到的。可能用戶覺得用了一段時間不爽,想退回 Nginx,我們也可以支持這種能力。
- 保持核心的穩定
APISIX 雖然每個月的迭代非常快,每個月有 200 多個 commit,有 10 個左右大的功能,但是 APISIX 里面有一個叫 core 的目錄變化是很少的,我們會保持它的核心是穩定的。功能迭代可以很快,但是核心很穩定。
- 支持企業個性需求的開發
無論是國內還是國外的企業,都沒有辦法拿產品去適應所有的需求。如果你適應了所有的需求,那么你就做成了一個巨無霸,會是個很大很雜的產品,它的性能、可擴展性就會降的很低。所以我們就有插件,如果你需要有個性化的東西,就去定制自己的插件,需要什么功能就把這個插件放上去,不需要就把它拿掉。我可以保證最下面核心層是很穩定的,上面那層可以根據用戶需求定制。
如何做網關的選型
行業現狀了解
- 參考 Gartner 報告
這個是我們選型的思路,我們做選型並不是先從技術上去做,而是先看整個行業,Gartner 的報告可以作為參考。如上圖所示,谷歌、IBM、RedHat 等頭部玩家吃掉全球大部分 API 市場,雖然技術圈都知道 Kong,但它其實處於遠見者的地位,此外Kong 作為新興的玩家還是第一個將自身 API 網關開源出來的。
- 參考 CNCF 全景圖
Gartner 的報告更偏商業化,可以在此基礎之上參考開源社區中雲原生軟件基金會CNCF 維護的全景圖,很多開源和閉源項目都被其分層、分功能地羅列出來。全景圖中雲原生領域有十幾款軟件是做 API 網關選型時可以選擇的,其中有一半是大廠的產品,如 3SCALE 是Red Hat 的產品,剩下的 Kong、APISIX、TYK 等是開源項目,如果要做 API 選型可以在其中做選擇。
產品選型比較
在參考 Gartner 報告和 CNCF 全景圖之后,我們比較了主流的 API 網關,決定不用已有的 API 網關而是要自己做一個。
- apigee
apigee 是最大的玩家,其優勢在於全生命周期,即從 API 設計、開發、文檔、測試以及上線等全部是谷歌全家桶。但 apigee 是閉源項目,無法進行定制化開發,而且是被谷歌雲鎖定的。
- Kong
Kong 解決了 apigee 的痛點,既不會鎖定也支持自定義開發,但 Kong 是 2015 年開發的,當時是把數據都放在Postgres 比較重的關系性數據庫里,代碼繁雜,性能存在問題。Kong 的優勢在於產品思路好,方向看得准。
- APISIX
APISIX 借鑒 Kong 的思路,選型時完全基於 etcd,將所有的數據都放在 etcd 里面,完成 Kong 在postgres 上做的大量重復代碼,例如消息分發、高可用和可擴展性都是基於 etcd 進行,操作更加簡單。APISIX 的不足在於開源時間短,從 2019 年 6 月 6 號開源到現在尚未經受大用戶的檢驗,但優勢明顯:二次開發難度比 Kong 小很多。以限流限速功能開發舉例, 在 APISIX 的文件里增加六七十行代碼就能完成,但 Kong 則需要修改五六個文件、兩三百行代碼。
如何做網關的技術選型?
API 網關的核心組件:
- 路由,路由可以認為是 Nginx 里面的各個 location,怎么把 location 分發到上游服務將各個插件加載起來是路由的一個功能。選擇時需要思考的是做遍歷還是做一個樹?二者需要的時間和復雜程度是不一樣的,我們選擇像 Kong 一樣做遍歷。
- 插件,插件是 API 網關的核心功能,有了插件就可以很輕松地開發屬於自己的代碼,而不用等開源社區增加相關功能。在做插件時需要思考要不要做成熱加載,熱加載的意義在於新增插件或者修改某一個插件時,不需要重啟整個服務就能生效。我們希望做到修改或新增插件時,可以通過 API 的調用馬上生效。
- schema 的校驗,schema 的校驗指的是用戶請求進來后需要校驗上傳的字段、類型等是否合法,如果自己寫插件,其參數、輸入值是否合法,這相當於是對 API 的描述,使得個人和前端的配合十分便利。
- **存儲, **放在關系型數據庫還是鍵值數據庫,亦或是放在 etcd 里等同於是在做技術選型,需要把這些都選好后才能像搭積木一樣搭建起來。
選型原則:做雲原生友好的、高性能的、開源的 API 網關
- 要對開發者友好。使用 API 網關的是開發者,我們希望不管是開發者看代碼、學代碼還是修改插件都能很輕松,不用像我和院生當時看 Kong 的代碼那樣痛苦。
- 追求性能。雖說 OpenResty 的性能高,但是真正動手寫的時候會發現寫出來的代碼性能不高,因為在 OpenResty 里面代碼都是很容易寫,但是很難保證寫出一個極致的代碼,它里面有非常多的坑,這是大部分人很難去注意到的。
APISIX 的選型
- 路由:最開始選擇 lua-resty-r3,最近新增路由 FFI;
- 插件:靈感來自 Kong,但架構和設計完全不一樣,大幅簡化編寫難度,熱加載;
- schema:借用騰訊開源的 rapidjson,在 rapidjson 實現 json schema,用 json schema標准做校驗;
- 存儲:選用 etcd,當時沒有 Lua-resty-etcd 庫,需要從頭 lua 幫助 etcd 進行訪問。
APISIX 獨有的功能
- 超強性能,性能是主打標簽,內部測試發現 APISIX 的性能是 Kong 的 10 倍;
- 插件熱更新,修改或增加插件,不用重啟服務,所有的更新都是熱的;
- 路由可以實現插件化,如果不喜歡 r3 的復雜路由,可以使用前綴匹配的路由;
- 支持版本變更控制,如果發布新版本出錯可以輕松回退老版本;
- 以身份為基礎的零信任,新合並的 future 可以支持外部身份認證,此時很容易實現零信任,可以接入所有外部身份認證廠商的服務。使用時只需簡單調配部分參數,就可以將身份認證功能直接加入 API 中。Kong 的商業版也支持此功能,但 APISIX 直接開源。
測試、持續集成的最佳實踐
測試
大公司都有專門的 QA 團隊做測試,開發部門只需要寫完代碼簡單自測后提交給 QA 團隊。但開源項目沒有 QA 團隊,甚至連開發團隊都是兼職,此時就必須用自動化的測試,即測試驅動開發的方式才能玩轉開源項目。
OpenResty 的開源項目將近 70 個,其商業公司有將近 100 個閉源的項目,總共將近 200 個項目不到 10 個人維護。如果手工測試,那就什么都做不了,所以要想辦法實現解決這個問題。
- 開發即測試
剛開始較慢,因為開發完一個新功能需要一塊提交對應的測試案例,否則PR 不會被合並。例如給 OpenResty 貢獻一個功能卻沒有提交對應的測試案例,或者提交了測試案例但不全,不管功能寫的有多好,此PR 一定不會被合並,因為破壞了整個開源項目的原則,測試需要是自動化跑起來的。
APISIX 多引入一個條件,即代碼的覆蓋率不能低於70%,現在已經改為不能低於 80%。如果你的改動引入新代碼,也增加了測試案例,但是降低了原有測試案例的覆蓋率,那也不能被接受合並。
- 單元測試完全基於 test:nginx
測試案例完全基於 test:nginx ,可以認為 test:Nginx 是一個小語言或者一個DSL,文檔較少,學習門檻比較高,我和院生對它比較熟悉才完全基於此進行測試。
- 代碼風格檢測:luackeck 和 lua-relang
Luackeck 非常好用,可以用於 Lua 和 OpenResty,提供有幾個參數進行選擇,還可以使用春哥寫的 lua-relang。我們是兩個程序都跑起來做代碼風格檢測,以確保不管是新的提交者還是我們自己的代碼風格的一致性。
- 代碼覆蓋率檢測:luacov
代碼覆蓋率檢測使用luacov,這是標准 lua 的一個功能,可以將代碼覆蓋率跑起來。
合並 PR 是在上述測試即 test:nginx 測試、代碼風格測試、代碼覆蓋率測試都跑過的前提下進行,每月 6 號發行新版本時進行性能測試,比較新老版本之間性能的差異。一般會跑火焰圖,同時定期做fuzzing 測試,混亂輸入如 uri、args 等做壓力測試。畢竟 APISIX 是一個 API 網關,作為流量的入口要保證足夠的穩定。
持續集成
測試不能依賴於人,否則總有一天會跑不下去。那么如何讓單元測試、性能測試、代碼風格檢測等測試不依賴於人穩定地運行呢?
- 強依賴 GitHub:issue、Milestone、code review、PR approved。GitHub 的 code review 非常好用,它可以評論每一行代碼,如果它覺得這行代碼必須要改動,而實際沒有修改,是沒有辦法合並 approved。
- 強依賴 travis CI:單元測試、代碼風格檢測、多平台測試(ubuntu 和 mac)、前端打包、自動提交。travis 是 GitHub 的持續集成插件,APISIX 並沒有用自己的服務器資源去跑測試,而是跑在雲端的,現在自帶APISIX 的前端,其打包、提交都是自動化進行。因為我們要從vue 的代碼編譯為 html,這一切都是通過 travis 來做的。
- http://coveralls.io,將代碼覆蓋率的結果上傳到http://coveralls.io 網站,以可視化的方式呈現所有和代碼覆蓋率相關的東西,例如哪一行代碼沒有被檢測到,和上一個版本有什么變化等,使得代碼覆蓋率檢測自動化進行。前文曾提到要始終保證 APISIX 的核心穩定,這就需要保證core 目錄里所有文件代碼覆蓋率能夠達到 100%,即核心板塊的每一行代碼都被測試到。
總結
- 資源少不一定是壞事。不管是開源項目還是商業公司,只有在資源少的時候,才會思考如何借助外部的力量或者是想出一些鬼點子解決問題;
- APISIX 的選型、測試和 CI 都是找“取巧”和自動化的方式,借助巧用外部力量的方式去做,沒有造輪子;
- APISIX 的選型、測試和 CI 三者非常重要,比性能重要。雖然我們主打性能,但更值得大家琢磨的不只是代碼,而是選型怎么測試和 CI 的,大家可以將其運用到業務中,即使不用 OpenResty 和 APISIX,還是可以學習開源項目是怎么做的;
- GitHub 和 SaaS 能提供的服務,絕對不會自己去造,克制住自己造輪子的沖動。
查看演講PPT及視頻:
本文由博客一文多發平台 OpenWrite 發布!