自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

通過實例理解API網(wǎng)關(guān)的主要功能特性

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理
本文對已經(jīng)相對成熟的API網(wǎng)關(guān)技術(shù)做了回顧,對API網(wǎng)關(guān)的演進階段、主流特性以及當(dāng)前市面上的主流API網(wǎng)關(guān)進行了簡要說明,并以Go實現(xiàn)的Tyk Gateway社區(qū)開源版為例,以示例方式對API網(wǎng)關(guān)的主要功能做了介紹。

在當(dāng)今的技術(shù)領(lǐng)域中,“下云”的概念正逐漸抬頭,像David Heinemeier Hansson[1](37signals公司的聯(lián)合創(chuàng)始人, Ruby on Rails的Creator)就直接將公司所有的業(yè)務(wù)都從公有云搬遷到了自建的數(shù)據(jù)中心[2]中。雖說大多數(shù)企業(yè)不會這么“極端”,但隨著企業(yè)對云原生架構(gòu)采用的廣泛與深入,不可避免地面臨著對云服務(wù)的依賴。云服務(wù)在過去的幾年中被廣泛應(yīng)用于構(gòu)建靈活、可擴展的應(yīng)用程序和基礎(chǔ)設(shè)施,為企業(yè)提供了許多便利和創(chuàng)新機會。然而,隨著業(yè)務(wù)規(guī)模的增長和數(shù)據(jù)量的增加,云服務(wù)的成本也隨之上升。企業(yè)開始意識到,對云服務(wù)的依賴已經(jīng)成為一個值得重新評估的議題。云服務(wù)的開銷可能占據(jù)了企業(yè)可用的預(yù)算的相當(dāng)大部分。為了保持競爭力并更好地控制成本,企業(yè)需要尋找方法來減少對云服務(wù)的依賴,尋找更經(jīng)濟的解決方案,同時確保仍能獲得所需的性能、安全性和可擴展性。

在這樣的背景下,我們的關(guān)注點是選擇一款適宜的API網(wǎng)關(guān),從主流功能特性的角度來評估候選者的支持。API網(wǎng)關(guān)作為現(xiàn)代云原生應(yīng)用架構(gòu)中的關(guān)鍵組件,扮演著連接前端應(yīng)用和后端服務(wù)的中間層,負(fù)責(zé)管理、控制和保護API的訪問。它的功能特性對于確保API的安全性、可靠性和可擴展性至關(guān)重要。

盡管API網(wǎng)關(guān)并不是一個新鮮事物了,但對于那些長期依賴于云供應(yīng)商的服務(wù)的人來說,它似乎變得有些“陌生”。因此,本文旨在幫助我們重新理解API網(wǎng)關(guān)的主要特性,并獲得對API網(wǎng)關(guān)選型的能力,以便在停止使用云供應(yīng)商服務(wù)之前,找到一個合適的替代品^_^。

1. API網(wǎng)關(guān)回顧

API網(wǎng)關(guān)是現(xiàn)代應(yīng)用架構(gòu)中的關(guān)鍵組件之一,它的存在簡化了應(yīng)用程序的架構(gòu),并為客戶端提供一個單一的訪問入口,并進行相關(guān)的控制、優(yōu)化和管理。API網(wǎng)關(guān)可以幫助企業(yè)實現(xiàn)微服務(wù)架構(gòu)、提高系統(tǒng)的可擴展性和安全性,并提供更好的開發(fā)者體驗和用戶體驗。

1.1 API網(wǎng)關(guān)的演化

隨著互聯(lián)網(wǎng)的快速發(fā)展和企業(yè)對API的需求不斷增長,API網(wǎng)關(guān)作為一種關(guān)鍵的中間層技術(shù)逐漸嶄露頭角并經(jīng)歷了一系列的演進和發(fā)展。這里將API網(wǎng)關(guān)的演進歷史粗略分為以下幾個階段:

  • API網(wǎng)關(guān)之前的早期階段

在互聯(lián)網(wǎng)發(fā)展的早期階段,大多數(shù)應(yīng)用程序都是以單體應(yīng)用的形式存在[3]。后來隨著應(yīng)用規(guī)模的擴大和業(yè)務(wù)復(fù)雜性的增加,單體應(yīng)用的架構(gòu)變得不夠靈活和可擴展,面向服務(wù)架構(gòu)(Service-Oriented Architecture,SOA)逐漸興起,企業(yè)開始將應(yīng)用程序拆分成一組獨立的服務(wù)。這個時期,每個服務(wù)都是獨立對外暴露API,客戶端也是通過這些API直接訪問服務(wù),但這會導(dǎo)致一些安全性、運維和擴展性的問題。之后,企業(yè)也開始意識到需要一種中間層來管理和控制這種客戶端到服務(wù)的通信行為,并確保服務(wù)的可靠性和安全性,于是開始有了API網(wǎng)關(guān)的概念。

  • API網(wǎng)關(guān)的興起

早期的API網(wǎng)關(guān),其主要功能就是單純的路由和轉(zhuǎn)發(fā)。API網(wǎng)關(guān)將請求從客戶端轉(zhuǎn)發(fā)到后端服務(wù),并將后端服務(wù)的響應(yīng)返回給客戶端。在這個階段,API網(wǎng)關(guān)的功能非常簡單,主要用于解決客戶端和后端服務(wù)之間的通信問題。

  • API網(wǎng)關(guān)的成熟

隨著微服務(wù)架構(gòu)的興起和API應(yīng)用的不斷發(fā)展,企業(yè)開始將應(yīng)用程序進一步拆分成更小的、獨立部署的微服務(wù)。每個對外暴露的微服務(wù)都有自己的API,并通過API網(wǎng)關(guān)進行統(tǒng)一管理和訪問。API網(wǎng)關(guān)在微服務(wù)架構(gòu)中的作用變得更加重要,它的功能也逐漸豐富起來了。

在這一階段,它不僅負(fù)責(zé)路由和轉(zhuǎn)發(fā)請求,API網(wǎng)關(guān)還增加了安全和治理的功能,可以滿足幾個不同領(lǐng)域的微服務(wù)需求。比如:API網(wǎng)關(guān)可以通過身份認(rèn)證、授權(quán)、訪問控制等功能來保護API的安全;通過基于重試、超時、熔斷的容錯機制等來對API的訪問進行治理;通過日志記錄、基于指標(biāo)收集以及Tracing等對API的訪問進行觀測與監(jiān)控;支持實時的服務(wù)發(fā)現(xiàn)等。

API網(wǎng)關(guān)(圖來自網(wǎng)絡(luò))API網(wǎng)關(guān)(圖來自網(wǎng)絡(luò))

  • API網(wǎng)關(guān)的云原生化

隨著云原生技術(shù)的發(fā)展,如容器化和服務(wù)網(wǎng)格(Service Mesh)等,API網(wǎng)關(guān)也在不斷演進和適應(yīng)新的環(huán)境。在云原生環(huán)境中,API網(wǎng)關(guān)實現(xiàn)了與容器編排系統(tǒng)(如Kubernetes)和服務(wù)網(wǎng)格集成,其自身也可以作為一個云原生服務(wù)來部署,以實現(xiàn)更高的可伸縮性、彈性和自動化。同時,新的技術(shù)和標(biāo)準(zhǔn)也不斷涌現(xiàn),如GraphQL和gRPC等,API網(wǎng)關(guān)也增加了對這些新技術(shù)的集成和支持。

1.2 API網(wǎng)關(guān)的主要功能特性

從上面的演化歷史我們看到:API網(wǎng)關(guān)的演進使其從最初簡單的請求轉(zhuǎn)發(fā)角色,逐漸成為整個API管理和微服務(wù)架構(gòu)中的關(guān)鍵組件。它不僅扮演著API管理層與后端服務(wù)層之間的適配器,也是云原生架構(gòu)中不可或缺的基礎(chǔ)設(shè)施,使微服務(wù)管理更加智能化和自動化。下面是現(xiàn)代API網(wǎng)關(guān)承擔(dān)的主要功能特性,我們后續(xù)也會基于這些特性進行示例說明:

  • 請求轉(zhuǎn)發(fā)和路由
  • 身份認(rèn)證和授權(quán)
  • 流量控制和限速
  • 高可用與容錯處理
  • 監(jiān)控和可觀測性

2. 那些主流的API網(wǎng)關(guān)

下面是來自CNCF Landscape[4]中的主流API網(wǎng)關(guān)集合(截至2023.11月),圖中展示了關(guān)于各個網(wǎng)關(guān)的一些細(xì)節(jié),包括star數(shù)量和背后開發(fā)的公司或組織:

圖片圖片

主流的API網(wǎng)關(guān)還有各大公有云提供商的實現(xiàn),比如:Amazon的API Gateway[5]、Google Cloud的API Gateway[6]以及上圖中的Azure API Management等,但它們不在我們選擇范圍之內(nèi);雖然被CNCF收錄,但多數(shù)API網(wǎng)關(guān)受到的關(guān)注并不高,超過1k star的不到30%,這些不是很受關(guān)注或dev不是那么active的項目也無法在生產(chǎn)環(huán)境擔(dān)當(dāng)關(guān)鍵角色;而像APISIX[7]、Kong[8]這兩個受關(guān)注很高的網(wǎng)關(guān),它們是建構(gòu)在Nginx之上實現(xiàn)的,技術(shù)棧與我們不契合;而像EMISSARY INGRESS[9]、Gloo等則是完全云原生化或者說是Kubernetes Native的,無法在無Kubernetes的基于VM或裸金屬的環(huán)境下部署和運行。

好吧,剩下的只有幾個Go實現(xiàn)的API Gateway了,在它們之中,我們選擇用Tyk API網(wǎng)關(guān)[10]來作為后續(xù)API功能演示的示例。

注:這并不代表Tyk API網(wǎng)關(guān)就要比其他Go實現(xiàn)的API Gateway優(yōu)秀[11],只是它的資料比較齊全,適合在本文中作演示罷了。

3. API網(wǎng)關(guān)主要功能特性示例(Tyk API網(wǎng)關(guān)版本)

3.1 Tyk API網(wǎng)關(guān)簡介

記得在至少5年前就知道Tyk API網(wǎng)關(guān)[12]的存在,印象中它是使用Go語言開發(fā)的早期的那批API網(wǎng)關(guān)之一。Tyk從最初的純開源項目,到如今由背后商業(yè)公司支持,以O(shè)pen Core模式開源[13]的網(wǎng)關(guān),一直保持了active dev的狀態(tài)。經(jīng)過多年的演進,它已經(jīng)一款功能強大的開源兼商業(yè)API管理和網(wǎng)關(guān)解決方案[14],提供了全面的功能和工具,幫助開發(fā)者有效地管理、保護和監(jiān)控API。同時,Tyk API網(wǎng)關(guān)支持多種安裝部署方式,即可以單一程序的方式放在物理機或VM上運行,也可以支持容器部署,通過docker-compose[15]拉起,亦可以通過Kubernetes Operator[16]將其部署在Kubernetes中,這也讓Tyk API網(wǎng)關(guān)具備了在各大公有云上平滑遷移的能力。

圖片圖片

關(guān)于Tyk API網(wǎng)關(guān)開源版本的功能詳情[17],可以點擊左邊超鏈接到其官網(wǎng)查閱,這里不贅述。

3.2 安裝Tyk API網(wǎng)關(guān)

下面我們就來安裝一下Tyk API網(wǎng)關(guān),我們直接在VM上安裝,VM上的環(huán)境是CentOS 7.9。Tyk API提供了很多中安裝方法,這里使用CentOS的yum包管理工具安裝Tyk API網(wǎng)關(guān)[18],大體步驟如下(演示均以root權(quán)限操作)。

3.2.1 創(chuàng)建tyk gateway軟件源

默認(rèn)的yum repo中是不包含tyk gateway的,我們需要在/etc/yum.repos.d下面創(chuàng)建一個新的源,即新建一個tyk_tyk-gateway.repo文件,其內(nèi)容如下:

[tyk_tyk-gateway]
name=tyk_tyk-gateway
baseurl=https://packagecloud.io/tyk/tyk-gateway/el/7/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/tyk/tyk-gateway/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300

[tyk_tyk-gateway-source]
name=tyk_tyk-gateway-source
baseurl=https://packagecloud.io/tyk/tyk-gateway/el/7/SRPMS
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/tyk/tyk-gateway/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300

接下來我們執(zhí)行下面命令來創(chuàng)建tyk_tyk-gateway這個repo的YUM緩存:

$yum -q makecache -y --disablerepo='*' --enablerepo='tyk_tyk-gateway'
導(dǎo)入 GPG key 0x5FB83118:
 用戶ID     : "https://packagecloud.io/tyk/tyk-gateway (https://packagecloud.io/docs#gpg_signing) <support@packagecloud.io>"
 指紋       : 9179 6215 a875 8c40 ab57 5f03 87be 71bd 5fb8 3118
 來自       : https://packagecloud.io/tyk/tyk-gateway/gpgkey

repo配置和緩存完畢后,我們就可以安裝Tyk API Gateway了:

$yum install -y tyk-gateway

安裝后的tky-gateway將以一個systemd daemon服務(wù)[19]的形式存在于主機上,程序意外退出或虛機重啟后,該服務(wù)也會被systemd自動拉起。通過systemctl status命令可以查看服務(wù)的運行狀態(tài):

# systemctl status tyk-gateway
● tyk-gateway.service - Tyk API Gateway
   Loaded: loaded (/usr/lib/systemd/system/tyk-gateway.service; enabled; vendor preset: disabled)
   Active: active (running) since 日 2023-11-19 20:22:44 CST; 12min ago
 Main PID: 29306 (tyk)
    Tasks: 13
   Memory: 19.6M
   CGroup: /system.slice/tyk-gateway.service
           └─29306 /opt/tyk-gateway/tyk --conf /opt/tyk-gateway/tyk.conf

11月 19 20:34:54 iZ2ze18rmx2avqb5xgb4omZ tyk[29306]: time="Nov 19 20:34:54" level=error msg="Connection to Redis faile...b-sub
11月 19 20:35:04 iZ2ze18rmx2avqb5xgb4omZ tyk[29306]: time="Nov 19 20:35:04" level=error msg="cannot set key in pollerC...ured"
11月 19 20:35:04 iZ2ze18rmx2avqb5xgb4omZ tyk[29306]: time="Nov 19 20:35:04" level=error msg="Redis health check failed...=main
Hint: Some lines were ellipsized, use -l to show in full.

3.2.2 安裝redis

我們看到tyk-gateway已經(jīng)成功啟動,但從其服務(wù)日志來看,它在連接redis時報錯了!tyk gateway默認(rèn)將數(shù)據(jù)存儲在redis中,為了讓tyk gateway正常運行,我們還需要安裝redis!這里我們使用容器的方式安裝和運行一個redis服務(wù):

$docker pull redis:6.2.14-alpine3.18
$docker run -d --name my-redis -p 6379:6379 redis:6.2.14-alpine3.18 
e5d1ec8d5f5c09023d1a4dd7d31d293b2d7147f1d9a01cff8eff077c93a9dab7

拉取并運行redis后,我們通過redis-cli驗證一下與redis server的連接:

# docker run -it --rm redis:6.2.14-alpine3.18  redis-cli -h 192.168.0.24
192.168.0.24:6379>

我們看到可以正常連接!但此時Tyk Gateway仍然無法與redis正常連接,我們還需要對Tyk Gateway做一些配置調(diào)整!

3.2.3 配置Tyk Gateway

yum默認(rèn)將Tyk Gateway安裝到/opt/tyk-gateway下面,這個路徑下的文件布局如下:

$tree -F -L 2 .
.
├── apps/
│   └── app_sample.json
├── coprocess/
│   ├── api.h
│   ├── bindings/
│   ├── coprocess_common.pb.go
│   ├── coprocess_mini_request_object.pb.go
│   ├── coprocess_object_grpc.pb.go
│   ├── coprocess_object.pb.go
│   ├── coprocess_response_object.pb.go
│   ├── coprocess_return_overrides.pb.go
│   ├── coprocess_session_state.pb.go
│   ├── coprocess_test.go
│   ├── dispatcher.go
│   ├── grpc/
│   ├── lua/
│   ├── proto/
│   ├── python/
│   └── README.md
├── event_handlers/
│   └── sample/
├── install/
│   ├── before_install.sh*
│   ├── data/
│   ├── init_local.sh
│   ├── inits/
│   ├── post_install.sh*
│   ├── post_remove.sh*
│   ├── post_trans.sh
│   └── setup.sh*
├── middleware/
│   ├── ottoAuthExample.js
│   ├── sampleMiddleware.js
│   ├── samplePostProcessMiddleware.js
│   ├── samplePreProcessMiddleware.js
│   ├── testPostVirtual.js
│   ├── testVirtual.js
│   └── waf.js
├── policies/
│   └── policies.json
├── templates/
│   ├── breaker_webhook.json
│   ├── default_webhook.json
│   ├── error.json
│   ├── monitor_template.json
│   └── playground/
├── tyk*
└── tyk.conf

其中tyk.conf就是tyk gateway的配置文件,我們先看看其默認(rèn)的內(nèi)容:

$cat /opt/tyk-gateway/tyk.conf
{
  "listen_address": "",
  "listen_port": 8080,
  "secret": "xxxxxx",
  "template_path": "/opt/tyk-gateway/templates",
  "use_db_app_configs": false,
  "app_path": "/opt/tyk-gateway/apps",
  "middleware_path": "/opt/tyk-gateway/middleware",
  "storage": {
    "type": "redis",
    "host": "redis",
    "port": 6379,
    "username": "",
    "password": "",
    "database": 0,
    "optimisation_max_idle": 2000,
    "optimisation_max_active": 4000
  },
  "enable_analytics": false,
  "analytics_config": {
    "type": "",
    "ignored_ips": []
  },
  "dns_cache": {
    "enabled": false,
    "ttl": 3600,
    "check_interval": 60
  },
  "allow_master_keys": false,
  "policies": {
    "policy_source": "file"
  },
  "hash_keys": true,
  "hash_key_function": "murmur64",
  "suppress_redis_signal_reload": false,
  "force_global_session_lifetime": false,
  "max_idle_connections_per_host": 500
}

我們看到:storage下面存儲了redis的配置信息,我們需要將redis的host配置修改為我們的VM地址:

"host": "192.168.0.24",

然后重啟Tyk Gateway服務(wù):

$systemctl daemon-reload
$systemctl restart tyk-gateway

之后,我們再查看tyk gateway的運行狀態(tài):

systemctl status tyk-gateway
● tyk-gateway.service - Tyk API Gateway
   Loaded: loaded (/usr/lib/systemd/system/tyk-gateway.service; enabled; vendor preset: disabled)
   Active: active (running) since 一 2023-11-20 06:54:07 CST; 41s ago
 Main PID: 20827 (tyk)
    Tasks: 15
   Memory: 24.8M
   CGroup: /system.slice/tyk-gateway.service
           └─20827 /opt/tyk-gateway/tyk --conf /opt/tyk-gateway/tyk.conf

11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Loading API configurations...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Tracking hostname" api_nam...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Initialising Tyk REST API ...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="API bind on custom port:0"...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Checking security policy: ...fault
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="API Loaded" api_id=1 api_n...ip=--
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Loading uptime tests..." p...k-mgr
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Initialised API Definition...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=warning msg="All APIs are protected ...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="API reload complete" prefix=main
Hint: Some lines were ellipsized, use -l to show in full.

從服務(wù)日志來看,現(xiàn)在Tyk Gateway可以正常連接redis并提供服務(wù)了!我們也可以通過下面的命令驗證網(wǎng)關(guān)的運行狀態(tài):

$curl localhost:8080/hello
{"status":"pass","version":"5.2.1","description":"Tyk GW","details":{"redis":{"status":"pass","componentType":"datastore","time":"2023-11-20T06:58:57+08:00"}}}

“/hello”是Tyk Gateway的內(nèi)置路由,由Tyk網(wǎng)關(guān)自己提供服務(wù)。

到這里Tyk Gateway的安裝和簡單配置就結(jié)束了,接下來,我們就來看看API Gateway的主要功能特性,并借助Tyk Gateway來展示一下這些功能特性。

注:查看Tyk Gateway的運行日志,可以使用journalctl -u tyk-gateway -f命令實時follow最新日志輸出。

3.3 功能特性:請求轉(zhuǎn)發(fā)與路由

請求轉(zhuǎn)發(fā)和路由是API Gateway的主要功能特性之一,API Gateway可以根據(jù)請求的路徑、方法、查詢參數(shù)等信息將請求轉(zhuǎn)發(fā)到相應(yīng)的后端服務(wù),其內(nèi)核與反向代理類似,不同之處在于API Gateway增加了“API”這層抽象,更加專注于構(gòu)建、管理和增強API。

下面我們來看看Tyk如何配置API路由,我們首先創(chuàng)建一個新API。

3.3.1 創(chuàng)建一個新API

Tyk開源版支持兩種創(chuàng)建API的方式,一種是通過調(diào)用Tyk的控制類API[20],一種則是通過傳統(tǒng)的配置文件,放入特定目錄下[21]。無論哪種方式添加完API,最終都要通過Tyk Gateway熱加載(hot reload)或重啟才能生效。

注:Tyk Gateway的商業(yè)版本提供Dashboard,可以以圖形化的方式管理API,并且商業(yè)版本的API定義會放在Postgres或MongoDB中,我們這里用開源版本,只能手工管理了,并且API定義只能放在文件中。

下面,我們就來在Tyk上創(chuàng)建一個新的API路由,該路由示例的示意圖如下:

圖片圖片

在未添加新API之前,我們使用curl訪問一下該API路徑:

$curl localhost:8080/api/v1/no-authn
Not Found

Tyk Gateway由于找不到API路由,返回Not Found。接下來,我們采用調(diào)用tyk gateway API的方式來添加路由:

$curl -v -H "x-tyk-authorization: {tyk gateway secret}" \
  -s \
  -H "Content-Type: application/json" \
  -X POST \
  -d '{
    "name": "no-authn-v1",
    "slug": "no-authn-v1",
    "api_id": "no-authn-v1",
    "org_id": "1",   
    "use_keyless": true,
    "auth": {         
      "auth_header_name": "Authorization"
    },                
    "definition": {   
      "location": "header",
      "key": "x-api-version"
    },                
    "version_data": { 
      "not_versioned": true,    
      "versions": {             
        "Default": {            
          "name": "Default",    
          "use_extended_paths": true
        }                       
      }                         
    },                          
    "proxy": {                  
      "listen_path": "/api/v1/no-authn",
      "target_url": "http://localhost:18081/",
      "strip_listen_path": true
    },   
    "active": true
}' http://localhost:8080/tyk/apis | python -mjson.tool 

* About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> POST /tyk/apis HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
> x-tyk-authorization: {tyk gateway secret}
> Content-Type: application/json
> Content-Length: 797
> 
} [data not shown]
* upload completely sent off: 797 out of 797 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Wed, 22 Nov 2023 05:38:40 GMT
< Content-Length: 53
< 
{ [data not shown]
* Connection #0 to host localhost left intact
{
    "action": "added",
    "key": "no-authn-v1",
    "status": "ok"
}

從curl返回結(jié)果我們看到:API已經(jīng)被成功添加。這時tyk gateway的安裝目錄/opt/tyk-gateway的子目錄apps下會新增一個名為no-authn-v1.json的配置文件,這個文件內(nèi)容較多,有300行,這里就不貼出來了,這個文件就是新增的no-authn API的定義文件[22]

不過此刻,Tyk Gateway還需熱加載后才能為新的API提供服務(wù),調(diào)用下面API可以觸發(fā)Tyk Gateway的熱加載:

$curl -H "x-tyk-authorization: {tyk gateway secret}" -s http://localhost:8080/tyk/reload/group | python -mjson.tool
{
    "message": "",
    "status": "ok"
}

注:即便觸發(fā)熱加載成功,但如果body中的json格式錯,比如多了一個結(jié)尾逗號,Tyk Gateway是不會報錯的!

API路由創(chuàng)建完畢并生效后,我們再來訪問一下API:

$ curl localhost:8080/api/v1/no-authn
{
    "error": "There was a problem proxying the request"
}

我們看到:Tyk Gateway返回的已經(jīng)不是“Not Found”了!現(xiàn)在我們創(chuàng)建一下no-authn這個API服務(wù),考慮到適配更多后續(xù)示例,這里建立這樣一個http server:

// api-gateway-examples/httpserver

func main() {    
    // 解析命令行參數(shù)   
    port := flag.Int("p", 8080, "Port number")  
    apiVersion := flag.String("v", "v1", "API version")  
    apiName := flag.String("n", "example", "API name")   
    flag.Parse()                                         
                                                         
    // 注冊處理程序                                     
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {  
        fmt.Println(*r)                                                  
        fmt.Fprintf(w, "Welcome api: localhost:%d/%s/%s\n", *port, *apiVersion, *apiName)  
    })                                                                                     
                                                                                           
    // 啟動HTTP服務(wù)器                                                                      
    addr := fmt.Sprintf(":%d", *port)  
    log.Printf("Server listening on port %d\n", *port)  
    log.Fatal(http.ListenAndServe(addr, nil))           
}

我們啟動一個該http server的實例:

$go run main.go -p 18081 -v v1 -n no-authn
2023/11/22 22:02:42 Server listening on port 18081

現(xiàn)在我們再通過tyk gateway調(diào)用一下no-authn這個API:

$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn

我們看到這次路由通了!no-authn API返回了期望的結(jié)果!

3.3.2 負(fù)載均衡

如果no-authn API存在多個服務(wù)實例,Tyk Gateway也可以將請求流量負(fù)載均衡到多個no-authn服務(wù)實例上去,下圖是Tyk Gateway進行請求流量負(fù)載均衡[23]的示意圖:


要實現(xiàn)負(fù)責(zé)均衡,我們需要調(diào)整no-authn API的定義,這次我們直接修改/opt/tyk-gateway/apps/no-authn-v1.json,變更的配置主要有三項:

// /opt/tyk-gateway/apps/no-authn-v1.json

  "proxy": {
    "preserve_host_header": false,
    "listen_path": "/api/v1/no-authn",
    "target_url": "",                  // (1) 改為""
    "disable_strip_slash": false,
    "strip_listen_path": true,
    "enable_load_balancing": true,     // (2) 改為true
    "target_list": [                   // (3) 填寫no-authn服務(wù)實例列表
      "http://localhost:18081/",
      "http://localhost:18082/",
      "http://localhost:18083/"
    ],

修改完配置后,調(diào)用Tyk的控制類API使之生效,然后我們啟動三個no-authn的API實例:

$go run main.go -p 18081 -v v1 -n no-authn
$go run main.go -p 18082 -v v1 -n no-authn
$go run main.go -p 18083 -v v1 -n no-authn

接下來,我們多次調(diào)用curl訪問no-authn API:

$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18083/v1/no-authn

$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18083/v1/no-authn

我們看到:Tyk Gateway在no-authn API的各個實例之間做了等權(quán)重的輪詢。如果我們停掉實例3,再來訪問該API,我們將得到下面結(jié)果:

$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Bad Request

$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Bad Request

注:Tyk Gateway商業(yè)版通過Dashboard支持配置帶權(quán)重的RR負(fù)載均衡算法[24]。

我們看到:實例3已經(jīng)下線,但Tyk Gateway并不會跳過該已經(jīng)下線的實例,這在生產(chǎn)環(huán)境會給客戶端帶來不一致的響應(yīng)。

3.3.3 服務(wù)實例存活檢測(uptime test)

Tyk Gateway在開啟負(fù)載均衡的時候,也提供了對后端服務(wù)實例的存活檢測機制,當(dāng)某個服務(wù)實例down了后,負(fù)載均衡機制會繞過該實例將請求發(fā)到下一個處于存活狀態(tài)的實例;而當(dāng)down機實例恢復(fù)后,Tyk Gateway也能及時檢測到服務(wù)實例上線,并將其加入流量負(fù)載調(diào)度。

支持存活檢測(uptime test)的API定義配置如下:

// /opt/tyk-gateway/apps/no-authn-v1.json

"uptime_tests": {
    "disable": false,
    "poller_group":"",
    "check_list": [
      {
        "url": "http://localhost:18081/"
      },
      {
        "url": "http://localhost:18082/"
      },
      {
        "url": "http://localhost:18083/"
      }
    ],
    "config": {
      "enable_uptime_analytics": true,
      "failure_trigger_sample_size": 3,
      "time_wait": 300,
      "checker_pool_size": 50,
      "expire_utime_after": 0,
      "service_discovery": {
        "use_discovery_service": false,
        "query_endpoint": "",
        "use_nested_query": false,
        "parent_data_path": "",
        "data_path": "",
        "port_data_path": "",
        "target_path": "",
        "use_target_list": false,
        "cache_disabled": false,
        "cache_timeout": 0,
        "endpoint_returns_list": false
      },
      "recheck_wait": 0
    }
}

"proxy": {
    ... ...
    "enable_load_balancing": true,
    "target_list": [
      "http://localhost:18081/",
      "http://localhost:18082/",
      "http://localhost:18083/"
    ],
    "check_host_against_uptime_tests": true,
    ... ...
}

我們新增了uptime_tests的配置,uptime_tests的check_list中的url的值要與proxy中target_list中的值完全一樣,這樣Tyk Gateway才能將二者對應(yīng)上。另外proxy的check_host_against_uptime_tests要設(shè)置為true。

這樣配置并生效后,等我們將服務(wù)實例3停掉后,后續(xù)到no-authn的請求就只會轉(zhuǎn)發(fā)到實例1和實例2了。而當(dāng)恢復(fù)實例3運行后,Tyk Gateway又會將流量分擔(dān)到實例3上。

3.3.4 動態(tài)負(fù)載均衡

上面負(fù)載均衡示例中target_list中的目標(biāo)實例的IP和端口的手工配置的,而在云原生時代,我們經(jīng)常會基于容器承載API服務(wù)實例,當(dāng)容器因故退出,并重新啟動一個新容器時,IP可能會發(fā)生變化,這樣上述的手工配置就無法滿足要求,這就對API Gateway提出了與服務(wù)發(fā)現(xiàn)組件集成的要求:通過服務(wù)發(fā)現(xiàn)組件動態(tài)獲取服務(wù)實例的訪問列表,進而實現(xiàn)動態(tài)負(fù)載均衡[25]

Tyk Gateway內(nèi)置了主流服務(wù)發(fā)現(xiàn)組件(比如Etcd、Consul、ZooKeeper等)的對接能力,鑒于環(huán)境所限,這里就不舉例了,大家可以在Tyk Gateway的服務(wù)發(fā)現(xiàn)示例文檔頁面[26]找到與不同服務(wù)發(fā)現(xiàn)組件對接時的配置示例。

3.3.5 IP訪問限制

針對每個API,API網(wǎng)關(guān)還提供IP訪問限制的特性,比如Tyk Gateway就提供了IP白名單[27]IP黑名單[28]功能,通常二選一開啟一種限制即可。

以白名單為例,即凡是在白名單中的IP才被允許訪問該API。下面是白名單配置樣例:

// /opt/tyk-gateway/apps/no-authn-v1.json

  "enable_ip_whitelisting": true,
  "allowed_ips": ["12.12.12.12", "12.12.12.13", "12.12.12.14"],

生效后,當(dāng)我們訪問no-authn API時,會得到下面錯誤:

$curl localhost:8080/api/v1/no-authn
{
    "error": "access from this IP has been disallowed"
}

如果開啟的是黑名單,那么凡是在黑名單中的IP都被禁止訪問該API,下面是黑名單配置樣例:

// /opt/tyk-gateway/apps/no-authn-v1.json

  "enable_ip_blacklisting": true,
  "blacklisted_ips": ["12.12.12.12", "12.12.12.13", "12.12.12.14", "127.0.0.1"],

生效后,當(dāng)我們訪問no-authn API時,會得到如下結(jié)果:

$curl 127.0.0.1:8080/api/v1/no-authn
{
    "error": "access from this IP has been disallowed"
}

到目前為止,我們的API網(wǎng)關(guān)和定義的API都處于“裸奔”狀態(tài),因為沒有對客戶端進行身份認(rèn)證,任何客戶端都可以訪問到我們的API,顯然這不是我們期望的,接下來,我們就來看看API網(wǎng)關(guān)的一個重要功能特性:身份認(rèn)證與授權(quán)。

3.4 功能特性:身份認(rèn)證和授權(quán)

在《通過實例理解Go Web身份認(rèn)證的幾種方式[29]》一文中,我們提到過:建立全局的安全通道是任何身份認(rèn)證方式的前提

3.4.1 建立安全通道,卸載TLS證書

Tyk Gateway支持在Gateway層面統(tǒng)一配置TLS證書[30],同時也起到在Gateway卸載TLS證書的作用:

圖片圖片

這次我們要在tyk.conf中進行配置,才能在Gateway層面生效。這里我們借用《通過實例理解Go Web身份認(rèn)證的幾種方式[31]》一文中生成的幾個證書(大家可以在https://github.com/bigwhite/experiments/tree/master/authn-examples/tls-authn/make_certs下載),并將它們放到/opt/tyk-gateway/certs/下面:

$ls /opt/tyk-gateway/certs/
server-cert.pem  server-key.pem

然后,我們在/opt/tyk-gateway/tyk.conf文件中增加下面配置:

// /opt/tyk-gateway/tyk.conf 

  "http_server_options": {
    "use_ssl": true,
    "certificates": [
      {
        "domain_name": "server.com",
        "cert_file": "./certs/server-cert.pem",
        "key_file": "./certs/server-key.pem"
      }
    ]
  }

之后,重啟tyk gateway服務(wù),使得tyk.conf的配置修改生效。

注:在/etc/hosts中設(shè)置server.com為127.0.0.1。

現(xiàn)在我們用之前的http方式訪問一下no-authn的API:

$curl server.com:8080/api/v1/no-authn
Client sent an HTTP request to an HTTPS server.

由于全局啟用了HTTPS,采用http方式的請求將被拒絕。我們換成https方式訪問:

// 不驗證服務(wù)端證書
$curl -k https://server.com:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn

// 驗證服務(wù)端的自簽證書
$curl --cacert ./inter-cert.pem https://server.com:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn

3.4.2 Mutual TLS雙向認(rèn)證

在《通過實例理解Go Web身份認(rèn)證的幾種方式[32]》一文中,我們介紹的第一種身份認(rèn)證方式就是TLS雙向認(rèn)證,那么Tyk Gateway對MTLS的支持如何呢?Tyk官方文檔[33]提到它既支持client mTLS[34],也支持upstream mTLS[35]。

我們更關(guān)心的是client mTLS,即客戶端在與Gateway建連后,Gateway會使用Client CA驗證客戶端的證書!我最初認(rèn)為這個Client CA的配置是在tyk.conf中,但找了許久,也沒有發(fā)現(xiàn)配置Client CA的地方。

在no-authn API的定義文件(no-authn-v1.json)中,我們做如下配置改動:

"use_mutual_tls_auth": true,
  "client_certificates": [
      "/opt/tyk-gateway/certs/inter-cert.pem"
  ],

但使用下面命令訪問API時報錯:

$curl --key ./client-key.pem --cert ./client-cert.pem --cacert ./inter-cert.pem https://server.com:8080/api/v1/no-authn
{
    "error": "Certificate with SHA256 bc8717c0f2ea5a0b81813abb3ec42ef8f9bf60da251b87243627d65fb0e3887b not allowed"
}

如果將"client_certificates"的配置中的inter-cert.pem改為client-cert.pem,則是可以的,但個人感覺這很奇怪,不符合邏輯,將tyk gateway的文檔、issue甚至代碼翻了又翻,也沒找到合理的配置client CA的位置。

Tyk Gateway支持多種身份認(rèn)證方式[36],下面我們來看一種使用較為廣泛的方式:JWT Auth。

主要JWT身份認(rèn)證方式的原理和詳情,可以參考我之前的文章《通過實例理解Go Web身份認(rèn)證的幾種方式[37]》。

3.4.3 JWT Token Auth

下面是我為這個示例做的一個示意圖:

圖片圖片

這是我們?nèi)粘i_發(fā)中經(jīng)常遇到的場景,即通過portal用用戶名和密碼登錄后便可以拿到一個jwt token,然后后續(xù)的訪問功能API的請求僅攜帶該jwt token即可。API Gateway對于portal/login API不做任何身份認(rèn)證;而對后續(xù)的功能API請求,通過共享的secret(也稱為static secret)對請求中攜帶的jwt token進行簽名驗證。

portal/login API由于不進行authn,這樣其配置與前面的no-authn API幾乎一致,只是API名稱、路徑和target_list有不同:

// apps/portal-login-v1.json

{
  "name": "portal-login-v1",
  "slug": "portal-login-v1",
  "listen_port": 0,
  "protocol": "",
  "enable_proxy_protocol": false,
  "api_id": "portal-login-v1",
  "org_id": "1",
  "use_keyless": true,
  ... ...
  "proxy": {
    "preserve_host_header": false,
    "listen_path": "/api/v1/portal/login",
    "target_url": "",
    "disable_strip_slash": false,
    "strip_listen_path": true,
    "enable_load_balancing": true,
    "target_list": [
      "http://localhost:28084"
    ],
    "check_host_against_uptime_tests": true,
  ... ... 
}

對應(yīng)的portal login API也不復(fù)雜:

// api-gateway-examples/portal-login/main.go

package main

import (
 "log"
 "net/http"
 "time"

 "github.com/golang-jwt/jwt/v5"
)

func main() {
 // 創(chuàng)建一個基本的HTTP服務(wù)器
 mux := http.NewServeMux()

 username := "admin"
 password := "123456"
 key := "iamtonybai"

 // for uptime test
 mux.HandleFunc("/health", func(w http.ResponseWriter, req *http.Request) {
  w.WriteHeader(http.StatusOK)
 })

 // login handler
 mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
  // 從請求頭中獲取Basic Auth認(rèn)證信息
  user, pass, ok := req.BasicAuth()
  if !ok {
   // 認(rèn)證失敗
   w.WriteHeader(http.StatusUnauthorized)
   return
  }

  // 驗證用戶名密碼
  if user == username && pass == password {
   // 認(rèn)證成功,生成token
   token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
    "username": username,
    "iat":      jwt.NewNumericDate(time.Now()),
   })
   signedToken, _ := token.SignedString([]byte(key))
   w.Write([]byte(signedToken))
  } else {
   // 認(rèn)證失敗
   http.Error(w, "Invalid username or password", http.StatusUnauthorized)
  }
 })

 // 監(jiān)聽28084端口
 err := http.ListenAndServe(":28084", mux)
 if err != nil {
  log.Fatal(err)
 }
}

運行該login API服務(wù)后,我們用curl命令獲取一下jwt token:

$curl -u 'admin:123456' -k https://server.com:8080/api/v1/portal/login
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDA3NTEyODEsInVzZXJuYW1lIjoiYWRtaW4ifQ.-wC8uPsLHDxSXcEMxIxJ8O2l3aWtWtWKvhtmuHmgIMA

現(xiàn)在我們再來建立protected API:

// apps/protected-v1.json

{
  "name": "protected-v1",
  "slug": "protected-v1",
  "listen_port": 0,
  "protocol": "",
  "enable_proxy_protocol": false,
  "api_id": "protected-v1",
  "org_id": "1",
  "use_keyless": false,    // 設(shè)置為false, gateway才會進行jwt的驗證
  ... ...
  "enable_jwt": true,      // 開啟jwt
  "use_standard_auth": false,
  "use_go_plugin_auth": false,
  "enable_coprocess_auth": false,
  "custom_plugin_auth_enabled": false,
  "jwt_signing_method": "hmac",        // 設(shè)置alg為hs256
  "jwt_source": "aWFtdG9ueWJhaQ==",    // 設(shè)置共享secret: base64("iamtonybai")
  "jwt_identity_base_field": "username", // 設(shè)置代表請求中的用戶身份的字段,這里我們用username
  "jwt_client_base_field": "",
  "jwt_policy_field_name": "",
  "jwt_default_policies": [
     "5e189590801287e42a6cf5ce"        // 設(shè)置security policy,這個似乎是jwt auth必須的
  ],
  "jwt_issued_at_validation_skew": 0,
  "jwt_expires_at_validation_skew": 0,
  "jwt_not_before_validation_skew": 0,
  "jwt_skip_kid": false,
  ... ...
  "version_data": {
    "not_versioned": true,
    "default_version": "",
    "versions": {
      "Default": {
        "name": "Default",
        "expires": "",
        "paths": {
          "ignored": null,
          "white_list": null,
          "black_list": null
        },
        "use_extended_paths": true,
        "extended_paths": {
          "persist_graphql": null
        },
        "global_headers": {
          "username": "$tyk_context.jwt_claims_username" // 設(shè)置轉(zhuǎn)發(fā)到upstream的請求中的header字段username
        },
        "global_headers_remove": null,
        "global_response_headers": null,
        "global_response_headers_remove": null,
        "ignore_endpoint_case": false,
        "global_size_limit": 0,
        "override_target": ""
      }
    }
  },
  ... ...
  "enable_context_vars": true, // 開啟上下文變量
  "config_data": null,
  "config_data_disabled": false,
  "tag_headers": ["username"], // 設(shè)置header
  ... ...
}

這個配置就相對復(fù)雜許多,也是翻閱了很長時間資料才驗證通過的配置。JWT Auth必須有關(guān)聯(lián)的policy設(shè)置,我們在tyk gateway開源版中要想設(shè)置policy,需要現(xiàn)在tyk.conf中做如下設(shè)置:

// /opt/tyk-gateway/tyk.conf

  "policies": {
    "policy_source": "file",
    "policy_record_name": "./policies/policies.json"
  },

而policies/policies.json的內(nèi)容如下:

// /opt/tyk-gateway/policies/policies.json
{
 "5e189590801287e42a6cf5ce": {
  "rate": 1000,
  "per": 1,
  "quota_max": 100,
  "quota_renewal_rate": 60,
  "access_rights": {
   "protected-v1": {
    "api_name": "protected-v1",
    "api_id": "protected-v1",
    "versions": [
     "Default"
    ]
   }
  },
  "org_id": "1",
  "hmac_enabled": false
 }
}

上述設(shè)置完畢并重啟tyk gateway生效后,且protected api服務(wù)也已經(jīng)啟動時,我們訪問一下該API服務(wù):

$curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDA3NTEyODEsInVzZXJuYW1lIjoiYWRtaW4ifQ.-wC8uPsLHDxSXcEMxIxJ8O2l3aWtWtWKvhtmuHmgIMA" -k https://server.com:8080/api/v1/protected
invoke protected api ok

我們看到curl發(fā)出的請求成功通過了Gateway的驗證!并且通過protected API輸出的請求信息來看,Gateway成功解析出username,并將其作為Header中的字段傳遞給了protected API服務(wù)實例:

http.Request{Method:"GET", URL:(*url.URL)(0xc0002f6240), Proto:"HTTP/1.1", ProtoMajor:1, ProtoMinor:1, Header:http.Header{"Accept":[]string{"*/*"}, "Accept-Encoding":[]string{"gzip"}, "Authorization":[]string{"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDA3NTEyODEsInVzZXJuYW1lIjoiYWRtaW4ifQ.-wC8uPsLHDxSXcEMxIxJ8O2l3aWtWtWKvhtmuHmgIMA"}, "User-Agent":[]string{"curl/7.29.0"}, "Username":[]string{"admin"}, "X-Forwarded-For":[]string{"127.0.0.1"}}, Body:http.noBody{}, GetBody:(func() (io.ReadCloser, error))(nil), ContentLength:0, TransferEncoding:[]string(nil), Close:false, Host:"localhost:28085", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"[::1]:55583", RequestURI:"/", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), ctx:(*context.cancelCtx)(0xc0002e34f0)}

如果不攜帶Authorization頭字段或jwt的token是錯誤的,那么結(jié)果將如下所示:

$ curl -k https://server.com:8080/api/v1/protected
{
    "error": "Authorization field missing"
}

$ curl -k -H "Authorization: Bearer xxx" https://server.com:8080/api/v1/protected
{
    "error": "Key not authorized"
}

一旦通過API Gateway的身份認(rèn)證,上游的API服務(wù)就會拿到客戶端身份,有了唯一身份后,就可以進行授權(quán)操作[38]了,其實policy設(shè)置本身也是一種授權(quán)訪問控制。Tyk Gateway自身也支持RBAC等模型[39],也支持與OPA(open policy agent)等的集成,但更多是在商業(yè)版的tyk dashboard下完成的,這里也就不重點說明了。

下面的Gateway的幾個主要功能特性由于試驗環(huán)境受限以及文章篇幅考量,我不會像上述例子這么細(xì)致的說明了,只會簡單說明一下。

3.5 功能特性:流量控制與限速

Tyk Gateway內(nèi)置提供了強大的流量控制功能,可以通過全局級別和API級別的限速[40]來管理請求流量。此外,Tyk Gateway 還支持請求配額(request quota)[41]來限制每個用戶或應(yīng)用程序在一個時間周期內(nèi)的請求次數(shù)。

流量不僅和請求速度和數(shù)量有關(guān)系,與請求的大小也有關(guān)系,Tyk Gateway還支持在全局層面和API層面設(shè)置Request的size limit[42],以避免超大包對網(wǎng)關(guān)運行造成不良影響。

3.6 功能特性:高可用與容錯處理

在許多情況下,我們要為客戶確保服務(wù)水平(service level),比如:最大往返時間、最大響應(yīng)時延等。Tyk Gateway提供了一系列功能,可幫助我們確保網(wǎng)關(guān)的高可用運行和SLA服務(wù)水平。

Tyk支持健康檢查[43],這對于確定Tyk Gateway的狀態(tài)極為重要,沒有健康檢查,就很難知道網(wǎng)關(guān)的實際運行狀態(tài)如何。

Tyk Gateway還內(nèi)置了斷路器(circuit breaker)[44],這個斷路器是基于比例的,因此如果y個請求中的x請求都失敗了,斷路器就會跳閘,例如,如果x = 10,y = 100,則閾值百分比為10%。當(dāng)失敗比例到達10%時,斷路器就會切斷流量,同時跳閘還會觸發(fā)一個事件,我們可以記錄和處理該事件。

當(dāng)upstream的服務(wù)響應(yīng)遲遲不歸時,Tyk Gateway還可以設(shè)置強制超時[45],可以確保服務(wù)始終在給定時間內(nèi)響應(yīng)。這在高可用性系統(tǒng)中非常重要,因為在這種系統(tǒng)中,響應(yīng)性能至關(guān)重要,這樣才能干凈利落地處理錯誤。

3.7 功能特性:監(jiān)控與可觀測性

微服務(wù)時代,可觀測性對運維以及系統(tǒng)高可用的重要性不言而喻。Tyk Gateway在多年的演化過程中,也逐漸增加了對可觀測的支持,

可觀測主要分三大塊:

  • log

Tyk Gateway支持設(shè)置輸出日志的級別(log level),默認(rèn)是info級別。Tyk輸出的是結(jié)構(gòu)化日志,這使得它可以很好的與其他日志收集查詢系統(tǒng)集成,Tyk支持與主流的日志收集工具對接[46],包括:logstash、sentry、Graylog、Syslog等。

  • metrics

度量數(shù)據(jù)是反映網(wǎng)關(guān)系統(tǒng)健康狀況、錯誤計數(shù)和類型、IT基礎(chǔ)設(shè)施(服務(wù)器、虛擬機、容器、數(shù)據(jù)庫和其他后端組件)及其他流程的硬件資源數(shù)據(jù)的重要參考。運維團隊可以通過使用監(jiān)控工具來利用實時度量的數(shù)據(jù)[47],識別運行趨勢、在系統(tǒng)故障時設(shè)置警報、確定問題的根本原因并緩解問題。

Tyk Gateway內(nèi)置了對主流metrics采集方案Prometheus+Grafana的支持[48],可以在網(wǎng)關(guān)層面以及對API進行實時度量數(shù)據(jù)采集和展示。


  • tracing

Tyk Gateway從5.2版本開始支持了與服務(wù)Tracing界的標(biāo)準(zhǔn):OpenTelemetry的集成[49],這樣你可以使用多種支持OpenTelemetry的Tracing后端,比如Jaeger、Datadog等。Tracing可在Gateway層面開啟,也可以延展到API層面。

4. 小結(jié)

本文對已經(jīng)相對成熟的API網(wǎng)關(guān)技術(shù)做了回顧,對API網(wǎng)關(guān)的演進階段、主流特性以及當(dāng)前市面上的主流API網(wǎng)關(guān)進行了簡要說明,并以Go實現(xiàn)的Tyk Gateway社區(qū)開源版為例,以示例方式對API網(wǎng)關(guān)的主要功能做了介紹。

總體而言,Tyk Gateway是一款功能強大,社區(qū)相對活躍并有商業(yè)公司支持的產(chǎn)品,文檔很豐富,但從實際使用層面,這些文檔對Tyk社區(qū)版本的使用者來說并不友好,指導(dǎo)性不足(更多用商業(yè)版的Dashboard說明,與配置文件難于對應(yīng)),就像本文例子中那樣,為了搞定JWT認(rèn)證,筆者著實花了不少時間查閱資料,甚至閱讀源碼。

Tyk Gateway的配置設(shè)計平坦,沒有層次和邏輯,感覺是隨著時間隨意“堆砌”上去的。并且配置文件更新時,如果出現(xiàn)格式問題,Tyk Gateway并不報錯,讓人難于確定配置是否真正生效了,只能用Tyk Gateway的控制API[50]去查詢結(jié)果來驗證,非常繁瑣低效。

本文涉及的源碼可以在這里[51]下載,文中涉及的一些tyk gateway api和security policy的配置也可以在其中查看。

5. 參考資料

  • Leaving the Cloud[52] - https://37signals.com/podcast/leaving-the-cloud/
  • The Past, Present, and Future of API Gateways[53] - https://www.infoq.com/articles/past-present-future-api-gateways/
  • How moving from AWS to Bare-Metal saved us 230,000/yr[54] - https://blog.oneuptime.com/moving-from-aws-to-bare-metal/
  • A Comprehensive Guide to API Gateways, Kubernetes Gateways, and Service Meshes[55] - https://navendu.me/posts/gateway-and-mesh/
  • Use API gateways in microservices[56] - https://learn.microsoft.com/en-us/azure/architecture/microservices/design/gateway
  • The Tyk API Gateway and Postman[57] - https://blog.postman.com/the-tyk-api-gateway-and-postman/
  • Getting Started with Tyk API Gateway with Keycloak[58] - https://javascript.plainenglish.io/getting-started-to-tyk-api-gateway-with-keycloak-16307435584a
  • Observing your API traffic with Tyk, Elasticsearch & Kibana[59] - https://medium.com/@asoorm/observing-your-api-metrics-with-tyk-elasticsearch-kibana-74e8fd946c39
  • Set up JWT token in tyk gateway[60] - https://community.tyk.io/t/set-up-jwt-token-in-tyk-gateway/6572/9


參考資料

[1] David Heinemeier Hansson: https://dhh.dk/

[2] 將公司所有的業(yè)務(wù)都從公有云搬遷到了自建的數(shù)據(jù)中心: https://37signals.com/podcast/leaving-the-cloud/

[3] 以單體應(yīng)用的形式存在: https://tonybai.com/2023/10/09/service-weaver-coding-in-monolithic-deploy-in-microservices/

[4] CNCF Landscape: https://https://landscape.cncf.io

[5] Amazon的API Gateway: https://aws.amazon.com/cn/api-gateway/

[6] Google Cloud的API Gateway: https://cloud.google.com/api-gateway

[7] APISIX: https://apisix.apache.org/

[8] Kong: https://konghq.com/

[9] EMISSARY INGRESS: https://github.com/emissary-ingress/emissary

[10] Tyk API網(wǎng)關(guān): https://tyk.io/blog/res-api-management-vendor-comparisons/

[11] 不代表Tyk API網(wǎng)關(guān)就要比其他Go實現(xiàn)的API Gateway優(yōu)秀: https://tyk.io/blog/enter-the-leader-tyk-recognised-as-a-leader-in-gartners-2023-magic-quadrant-for-api-management/

[12] Tyk API網(wǎng)關(guān): https://github.com/TykTechnologies/tyk

[13] Open Core模式開源: https://opensource.com/article/21/11/open-core-vs-open-source

[14] 開源兼商業(yè)API管理和網(wǎng)關(guān)解決方案: https://tyk.io/docs/tyk-oss-gateway/

[15] docker-compose: https://tonybai.com/2021/11/26/build-all-in-one-runtime-environment-with-docker-compose

[16] Kubernetes Operator: https://tonybai.com/2022/08/15/developing-kubernetes-operators-in-go-part1

[17] Tyk API網(wǎng)關(guān)開源版本的功能詳情: https://tyk.io/docs/tyk-oss-gateway/

[18] 使用CentOS的yum包管理工具安裝Tyk API網(wǎng)關(guān): https://tyk.io/docs/tyk-oss/ce-redhat-rhel-centos/

[19] systemd daemon服務(wù): https://tonybai.com/2016/12/27/when-docker-meets-systemd/

[20] 調(diào)用Tyk的控制類API: https://tyk.io/docs/getting-started/create-api/#tutorial-create-an-api-with-the-tyk-gateway-api

[21] 通過傳統(tǒng)的配置文件,放入特定目錄下: https://tyk.io/docs/getting-started/create-api/#tutorial-create-an-api-in-file-based-mode

[22] API的定義文件: https://tyk.io/docs/tyk-gateway-api/api-definition-objects/

[23] 請求流量負(fù)載均衡: https://tyk.io/docs/planning-for-production/ensure-high-availability/load-balancing/

[24] 支持配置帶權(quán)重的RR負(fù)載均衡算法: https://tyk.io/docs/planning-for-production/ensure-high-availability/load-balancing/

[25] 動態(tài)負(fù)載均衡: https://tyk.io/docs/planning-for-production/ensure-high-availability/service-discovery/

[26] 服務(wù)發(fā)現(xiàn)示例文檔頁面: https://tyk.io/docs/planning-for-production/ensure-high-availability/service-discovery/examples/

[27] IP白名單: https://tyk.io/docs/tyk-apis/tyk-gateway-api/api-definition-objects/ip-whitelisting/

[28] IP黑名單: https://tyk.io/docs/tyk-apis/tyk-gateway-api/api-definition-objects/ip-blacklisting/

[29] 通過實例理解Go Web身份認(rèn)證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example

[30] 統(tǒng)一配置TLS證書: https://tyk.io/docs/basic-config-and-security/security/tls-and-ssl/

[31] 通過實例理解Go Web身份認(rèn)證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example/

[32] 通過實例理解Go Web身份認(rèn)證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example

[33] Tyk官方文檔: https://tyk.io/docs/basic-config-and-security/security/mutual-tls/

[34] client mTLS: https://tyk.io/docs/basic-config-and-security/security/mutual-tls/client-mtls

[35] upstream mTLS: https://tyk.io/docs/basic-config-and-security/security/mutual-tls/upstream-mtls

[36] Tyk Gateway支持多種身份認(rèn)證方式: https://tyk.io/docs/apim-best-practice/api-security-best-practice/authentication/

[37] 通過實例理解Go Web身份認(rèn)證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example/

[38] 授權(quán)操作: https://tonybai.com/2023/11/04/understand-go-web-authz-by-example/

[39] 支持RBAC等模型: https://tyk.io/docs/tyk-dashboard/rbac/#understanding-the-concept-of-users-and-permissions

[40] 全局級別和API級別的限速: https://tyk.io/docs/basic-config-and-security/control-limit-traffic/rate-limiting/

[41] 支持請求配額(request quota): https://tyk.io/docs/basic-config-and-security/control-limit-traffic/request-quotas/

[42] 設(shè)置Request的size limit: https://tyk.io/docs/basic-config-and-security/control-limit-traffic/request-size-limits/

[43] Tyk支持健康檢查: https://tyk.io/docs/planning-for-production/ensure-high-availability/health-check/

[44] 內(nèi)置了斷路器(circuit breaker): https://tyk.io/docs/planning-for-production/ensure-high-availability/circuit-breakers/

[45] 設(shè)置強制超時: https://tyk.io/docs/planning-for-production/ensure-high-availability/enforced-timeouts/

[46] Tyk支持與主流的日志收集工具對接: https://tyk.io/docs/log-data/#logging

[47] 使用監(jiān)控工具來利用實時度量的數(shù)據(jù): https://tyk.io/docs/planning-for-production/monitoring/

[48] 對主流metrics采集方案Prometheus+Grafana的支持: https://tyk.io/blog/service-level-objectives-for-your-apis-with-tyk-prometheus-and-grafana/

[49] 支持了與服務(wù)Tracing界的標(biāo)準(zhǔn):OpenTelemetry的集成: https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/distributed-tracing/open-telemetry/open-telemetry-overview/

[50] Tyk Gateway的控制API: https://tyk.io/docs/tyk-gateway-api/

[51] 這里: https://github.com/bigwhite/experiments/tree/master/api-gateway-examples

[52] Leaving the Cloud: https://37signals.com/podcast/leaving-the-cloud/

[53] The Past, Present, and Future of API Gateways: https://www.infoq.com/articles/past-present-future-api-gateways/

[54] How moving from AWS to Bare-Metal saved us 230,000/yr: https://blog.oneuptime.com/moving-from-aws-to-bare-metal/

[55] A Comprehensive Guide to API Gateways, Kubernetes Gateways, and Service Meshes: https://navendu.me/posts/gateway-and-mesh/

[56] Use API gateways in microservices: https://learn.microsoft.com/en-us/azure/architecture/microservices/design/gateway

[57] The Tyk API Gateway and Postman: https://blog.postman.com/the-tyk-api-gateway-and-postman/

[58] Getting Started with Tyk API Gateway with Keycloak: https://javascript.plainenglish.io/getting-started-to-tyk-api-gateway-with-keycloak-16307435584a

[59] Observing your API traffic with Tyk, Elasticsearch & Kibana: https://medium.com/@asoorm/observing-your-api-metrics-with-tyk-elasticsearch-kibana-74e8fd946c39

[60] Set up JWT token in tyk gateway: https://community.tyk.io/t/set-up-jwt-token-in-tyk-gateway/6572/9

[61] “Gopher部落”知識星球: https://public.zsxq.com/groups/51284458844544

[62] 鏈接地址: https://m.do.co/c/bff6eed92687


責(zé)任編輯:武曉燕 來源: TonyBai
相關(guān)推薦

2011-11-16 09:59:50

私有云云存儲

2009-12-22 09:41:15

無線路由器

2010-06-30 11:04:41

SNMP協(xié)議網(wǎng)絡(luò)管理

2010-04-26 16:51:11

Oracle Deco

2010-03-05 13:53:38

Python Thre

2010-06-01 10:52:14

IPv6交換中心

2019-10-31 09:14:27

物聯(lián)網(wǎng)網(wǎng)關(guān)物聯(lián)網(wǎng)IOT

2025-02-05 07:00:00

Next.jsWeb前端

2016-12-02 16:00:22

服務(wù)器托管機柜

2009-12-03 13:55:10

路由器主要功能

2016-02-19 10:03:30

蘋果支付Apple Pay

2010-06-24 13:57:57

Linux Cat命令

2010-03-03 13:50:40

Python文件

2009-03-08 09:15:09

Windows 7微軟功能禁用

2010-01-14 17:46:29

智能交換機

2014-12-22 10:39:44

虛擬化云平臺PaaS

2009-11-20 16:33:02

備份路由器

2009-07-07 13:45:52

JDK日志框架

2009-11-09 10:51:46

2010-02-22 16:09:18

骨干交換機
點贊
收藏

51CTO技術(shù)棧公眾號