選擇Kong作為你的API網(wǎng)關(guān)
Kong(https://github.com/Kong/kong)是一個(gè)云原生,高效,可擴(kuò)展的分布式 API 網(wǎng)關(guān)。自 2015 年在 github 開源后,廣泛受到關(guān)注,目前已收獲 1.68w+ 的 star,其核心價(jià)值在于高性能和可擴(kuò)展性。
為什么需要 API 網(wǎng)關(guān)

在微服務(wù)架構(gòu)之下,服務(wù)被拆的非常零散,降低了耦合度的同時(shí)也給服務(wù)的統(tǒng)一管理增加了難度。如上圖左所示,在舊的服務(wù)治理體系之下,鑒權(quán),限流,日志,監(jiān)控等通用功能需要在每個(gè)服務(wù)中單獨(dú)實(shí)現(xiàn),這使得系統(tǒng)維護(hù)者沒有一個(gè)全局的視圖來統(tǒng)一管理這些功能。API 網(wǎng)關(guān)致力于解決的問題便是為微服務(wù)納管這些通用的功能,在此基礎(chǔ)上提高系統(tǒng)的可擴(kuò)展性。如右圖所示,微服務(wù)搭配上 API 網(wǎng)關(guān),可以使得服務(wù)本身更專注于自己的領(lǐng)域,很好地對(duì)服務(wù)調(diào)用者和服務(wù)提供者做了隔離。
為什么是 Kong
SpringCloud 玩家肯定都聽說過 Zuul 這個(gè)路由組件,包括 Zuul2 和 Springcloud Gateway 等框架,在國內(nèi)的知名度都不低。沒錯(cuò),我稱呼這些為組件 Or 框架,而 Kong 則更襯的上產(chǎn)品這個(gè)詞。在此我們可以簡(jiǎn)單對(duì)比下 Zuul 和 Kong。
舉例而言,如果選擇使用 Zuul,當(dāng)需要為應(yīng)用添加限流功能,由于 Zuul 只提供了基本的路由功能,開發(fā)者需要自己研發(fā) Zuul Filter,可能你覺得一個(gè)功能還并不麻煩,但如果在此基礎(chǔ)上對(duì) Zuul 提出更多的要求,很遺憾,Zuul 使用者需要自行承擔(dān)這些復(fù)雜性。而對(duì)于 Kong 來說,限流功能就是一個(gè)插件,只需要簡(jiǎn)單的配置,即可開箱即用。
Kong 的插件機(jī)制是其高可擴(kuò)展性的根源,Kong 可以很方便地為路由和服務(wù)提供各種插件,網(wǎng)關(guān)所需要的基本特性,Kong 都如數(shù)支持:
-
云原生: 與平臺(tái)無關(guān),Kong可以從裸機(jī)運(yùn)行到Kubernetes
-
動(dòng)態(tài)路由:Kong 的背后是 OpenResty+Lua,所以從 OpenResty 繼承了動(dòng)態(tài)路由的特性
-
熔斷
-
健康檢查
-
日志: 可以記錄通過 Kong 的 HTTP,TCP,UDP 請(qǐng)求和響應(yīng)。
-
鑒權(quán): 權(quán)限控制,IP 黑白名單,同樣是 OpenResty 的特性
-
SSL: Setup a Specific SSL Certificate for an underlying service or API.
-
監(jiān)控: Kong 提供了實(shí)時(shí)監(jiān)控插件
-
認(rèn)證: 如數(shù)支持 HMAC, JWT, Basic, OAuth2.0 等常用協(xié)議
-
限流
-
REST API: 通過 Rest API 進(jìn)行配置管理,從繁瑣的配置文件中解放
-
可用性: 天然支持分布式
-
高性能: 背靠非阻塞通信的 nginx,性能自不用說
-
插件機(jī)制: 提供眾多開箱即用的插件,且有易于擴(kuò)展的自定義插件接口,用戶可以使用 Lua 自行開發(fā)插件
上面這些特性中,反復(fù)提及了 Kong 背后的 OpenResty,實(shí)際上,使用 Kong 之后,Nginx 可以完全摒棄,Kong 的功能是 Nginx 的父集。
而 Zuul 除了基礎(chǔ)的路由特性以及其本身和 SpringCloud 結(jié)合較為緊密之外,并無任何優(yōu)勢(shì)。
Kong 的架構(gòu)

從技術(shù)的角度講,Kong 可以認(rèn)為是一個(gè) OpenResty 應(yīng)用程序。OpenResty 運(yùn)行在 Nginx 之上,使用 Lua 擴(kuò)展了 Nginx。Lua 是一種非常容易使用的腳本語言,可以讓你在 Nginx 中編寫一些邏輯操作。之前我們提到過一個(gè)概念 Kong = OpenResty + Nginx + Lua,但想要從全局視角了解 Kong 的工作原理,還是直接看源碼比較直接。我們定位到本地的 Kong 文件夾,按照上圖中的目錄層級(jí)來識(shí)識(shí) Kong 的廬山真面目。
-
Kong 文件下包含了全部源碼和必要組件,分析他們,我們便得到了 Kong 的架構(gòu)。0.13.x 是目前 Kong 的最新版本。
-
從 2 號(hào)塊中可以看到 nginx.conf ,這其實(shí)便是一個(gè)標(biāo)準(zhǔn)的 Nginx 目錄結(jié)構(gòu),這也揭示了 Kong 其實(shí)就是運(yùn)行在 Nginx 的基礎(chǔ)之上,而進(jìn)行的二次封裝。由 share 文件夾向下展開下一次分析。
-
share 文件夾中包含了 OpenResty 的相關(guān)內(nèi)容,其實(shí)背后就是一堆 Lua 腳本,例如 lapis 包含了數(shù)據(jù)庫操作,Nginx 生命周期,緩存控制等必要的 Lua 腳本,logging 包含了日志相關(guān)的 Lua 腳本,resty 包含了 dns,健康檢查等相關(guān)功能的 Lua 腳本…而其中的 kong 目錄值得我們重點(diǎn)分析,他包含了 Kong 的核心對(duì)象。
-
api 和 core 文件夾,封裝了 Kong 對(duì) service,route,upstream,target 等核心對(duì)象的操作代碼(這四個(gè)核心對(duì)象將會(huì)在下面的小節(jié)重點(diǎn)介紹),而 plugins 文件夾則是 Kong 高可擴(kuò)展性的根源,存放了 kong 的諸多擴(kuò)展功能。
-
plugins 文件夾包含了上一節(jié)提到的 Kong 的諸多插件功能,如權(quán)限控制插件,跨域插件,jwt 插件,oauth2 插件…如果需要自定義插件,則需要將代碼置于此處。
從上述文件夾瀏覽下來,大概可以看到它和 Nginx 的相似之處,并在此基礎(chǔ)之上借助于 Lua 對(duì)自身的功能進(jìn)行了拓展,除了 nginx.conf 中的配置,和相對(duì)固定的文件層級(jí),Kong 還需要連接一個(gè)數(shù)據(jù)庫來管理路由配置,服務(wù)配置,upstream 配置等信息,是的,由于 Kong 支持動(dòng)態(tài)路由的特性,所以幾乎所有動(dòng)態(tài)的配置都不是配置在文件中,而是借助于 Postgres 或者 Cassandra 進(jìn)行管理。

Kong 對(duì)外暴露了 Restful API,最終的配置便是落地在了數(shù)據(jù)庫之中。
Kong 的管理方式
通過文件夾結(jié)構(gòu)的分析,以及數(shù)據(jù)庫中的表結(jié)構(gòu),我們已經(jīng)對(duì) Kong 的整體架構(gòu)有了一個(gè)基本的認(rèn)識(shí),但肯定還存在一個(gè)疑問:我會(huì)配置 Nginx 來控制路由,但這個(gè) Kong 應(yīng)當(dāng)怎么配置才能達(dá)到相同的目的呢?莫急,下面來看看 Kong 如何管理配置。
Kong 簡(jiǎn)單易用的背后,便是因?yàn)槠渌械牟僮鞫际腔?HTTP Restful API 來進(jìn)行的。

其中 8000/8443 分別是 Http 和 Https 的轉(zhuǎn)發(fā)端口,等價(jià)于 Nginx 默認(rèn)的 80 端口,而 8001 端口便是默認(rèn)的管理端口,我們可以通過 HTTP Restful API 來動(dòng)態(tài)管理 Kong 的配置。
一個(gè)典型的 Nginx 配置
upstream helloUpstream { server localhost:3000 weight=100; } server { listen 80; location /hello { proxy_pass http://helloUpstream; } }
如上這個(gè)簡(jiǎn)單的 Nginx 配置,便可以轉(zhuǎn)換為如下的 Http 請(qǐng)求。
對(duì)應(yīng)的 Kong 配置
# 配置 upstream curl -X POST http://localhost:8001/upstreams --data "name=helloUpstream" # 配置 target curl -X POST http://localhost:8001/upstreams/hello/targets --data "target=localhost:3000" --data "weight=100" # 配置 service curl -X POST http://localhost:8001/services --data "name=hello" --data "host=helloUpstream" # 配置 route curl -X POST http://localhost:8001/routes --data "paths[]=/hello" --data "service.id=8695cc65-16c1-43b1-95a1-5d30d0a50409"
這一切都是動(dòng)態(tài)的,無需手動(dòng) reload nginx.conf。
我們?yōu)?Kong 新增路由信息時(shí)涉及到了 upstream,target,service,route 等概念,他們便是 Kong 最最核心的四個(gè)對(duì)象。(你可能在其他 Kong 的文章中見到了 api 這個(gè)對(duì)象,在最新版本 0.13 中已經(jīng)被棄用,api 已經(jīng)由 service 和 route 替代)
從上面的配置以及他們的字面含義大概能夠推測(cè)出他們的職責(zé),upstream 是對(duì)上游服務(wù)器的抽象;target 代表了一個(gè)物理服務(wù),是 ip + port 的抽象;service 是抽象層面的服務(wù),他可以直接映射到一個(gè)物理服務(wù)(host 指向 ip + port),也可以指向一個(gè) upstream 來做到負(fù)載均衡;route 是路由的抽象,他負(fù)責(zé)將實(shí)際的 request 映射到 service。
他們的關(guān)系如下
upstream 和 target :1 對(duì) n
service 和 upstream :1 對(duì) 1 或 1 對(duì) 0 (service 也可以直接指向具體的 target,相當(dāng)于不做負(fù)載均衡)
service 和 route:1 對(duì) n
高可擴(kuò)展性的背后—插件機(jī)制
Kong 的另一大特色便是其插件機(jī)制,這也是我認(rèn)為的 Kong 最優(yōu)雅的一個(gè)設(shè)計(jì)。
文章開始時(shí)我們便提到一點(diǎn),微服務(wù)架構(gòu)中,網(wǎng)關(guān)應(yīng)當(dāng)承擔(dān)所有服務(wù)共同需要的那部分功能,這一節(jié)我們便來介紹下,Kong 如何添加 jwt 插件,限流插件。
插件(Plugins)裝在哪兒?對(duì)于部分插件,可能是全局的,影響范圍是整個(gè) Kong 服務(wù);大多數(shù)插件都是裝在 service 或者 route 之上。這使得插件的影響范圍非常靈活,我們可能只需要對(duì)核心接口進(jìn)行限流控制,只需要對(duì)部分接口進(jìn)行權(quán)限控制,這時(shí)候,對(duì)特定的 service 和 route 進(jìn)行定向的配置即可。
為 hello 服務(wù)添加50次/秒的限流
curl -X POST http://localhost:8001/services/hello/plugins \ --data "name=rate-limiting" \ --data "config.second=50"
為 hello 服務(wù)添加 jwt 插件
curl -X POST http://localhost:8001/services/login/plugins \ --data "name=jwt"
同理,插件也可以安裝在 route 之上
curl -X POST http://localhost:8001/routes/{routeId}/plugins \ --data "name=rate-limiting" \ --data "config.second=50" curl -X POST http://localhost:8001/routes/{routeId}/plugins \ --data "name=jwt"
在官方文檔中,我們可以獲取全部的插件 https://konghq.com/plugins/,部分插件需要收費(fèi)的企業(yè)版才可使用。

總結(jié)
Kong 是目前市場(chǎng)上相對(duì)較為成熟的開源 API 網(wǎng)關(guān)產(chǎn)品,無論是性能,擴(kuò)展性,還是功能特性,都決定了它是一款優(yōu)秀的產(chǎn)品,對(duì) OpenResty 和 Lua 感興趣的同學(xué),Kong 也是一個(gè)優(yōu)秀的學(xué)習(xí)參考對(duì)象。基于 OpenResty,可以在現(xiàn)有 Kong 的基礎(chǔ)上進(jìn)行一些擴(kuò)展,從而實(shí)現(xiàn)更復(fù)雜的特性,比如我司內(nèi)部的 ABTest 插件和定制化的認(rèn)證插件,開發(fā)成本都相對(duì)較低。Kong 系列的文章將會(huì)在以后持續(xù)連載。
Kirito 有話說:感謝閱讀,為了博主更好地創(chuàng)作,提供更多的原創(chuàng)文章,請(qǐng)大家務(wù)必!務(wù)必!務(wù)必!幫我點(diǎn)擊閱讀一下明天即將發(fā)出來的公眾號(hào)文章?。?!感謝老鐵~
閱讀擴(kuò)展
初識(shí) Kong 之負(fù)載均衡 https://www.cnkirito.moe/kong-loadbalance/
Kong 集成 Jwt 插件 https://www.cnkirito.moe/kong-jwt/
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問題,請(qǐng)聯(lián)系我們,謝謝!