<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          開源API網(wǎng)關(guān),到底哪個強(qiáng)?

          共 61963字,需瀏覽 124分鐘

           ·

          2021-07-30 18:37

          點擊上方“程序員大白”,選擇“星標(biāo)”公眾號

          重磅干貨,第一時間送達(dá)


          本文主要分析了 Nginx、Kong、APISIX、Tyk、Zuul、Gravitee 幾個開源 API 網(wǎng)關(guān)架構(gòu)及基本功能,測試了一定場景下各個 API 網(wǎng)關(guān)的性能,文末附有源碼地址。

          我今天就在和大家探討一下 API Gateway。在微服務(wù)的架構(gòu)下,API 網(wǎng)關(guān)是一個常見的架構(gòu)設(shè)計模式。

          以下是微服務(wù)中常見的問題,需要引入 API 網(wǎng)關(guān)來協(xié)助解決:

          • 微服務(wù)提供的 API 的粒度通常與客戶端所需的粒度不同。微服務(wù)通常提供細(xì)粒度的 API,這意味著客戶端需要與多個服務(wù)進(jìn)行交互。例如,如上所述,需要產(chǎn)品詳細(xì)信息的客戶需要從眾多服務(wù)中獲取數(shù)據(jù)。
          • 不同的客戶端需要不同的數(shù)據(jù)。例如,產(chǎn)品詳細(xì)信息頁面桌面的桌面瀏覽器版本通常比移動版本更為詳盡。
          • 對于不同類型的客戶端,網(wǎng)絡(luò)性能是不同的。例如,與非移動網(wǎng)絡(luò)相比,移動網(wǎng)絡(luò)通常要慢得多并且具有更高的延遲。而且,當(dāng)然,任何 WAN 都比 LAN 慢得多。這意味著本機(jī)移動客戶端使用的網(wǎng)絡(luò)性能與服務(wù)器端 Web 應(yīng)用程序使用的 LAN 的性能差異很大。服務(wù)器端 Web 應(yīng)用程序可以向后端服務(wù)發(fā)出多個請求,而不會影響用戶體驗,而移動客戶端只能提供幾個請求。
          • 微服務(wù)實例數(shù)量及其位置(主機(jī)+端口)動態(tài)變化。
          • 服務(wù)劃分會隨著時間的推移而變化,應(yīng)該對客戶端隱藏。
          • 服務(wù)可能會使用多種協(xié)議,其中一些協(xié)議可能對網(wǎng)絡(luò)不友好。

          常見的API網(wǎng)關(guān)主要提供以下的功能:

          • 反向代理和路由: 大多數(shù)項目采用網(wǎng)關(guān)的解決方案的最主要的原因。給出了訪問后端 API 的所有客戶端的單一入口,并隱藏內(nèi)部服務(wù)部署的細(xì)節(jié)。
          • 負(fù)載均衡: 網(wǎng)關(guān)可以將單個傳入的請求路由到多個后端目的地。
          • 身份驗證和授權(quán): 網(wǎng)關(guān)應(yīng)該能夠成功進(jìn)行身份驗證并僅允許可信客戶端訪問 API,并且還能夠使用類似 RBAC 等方式來授權(quán)。
          • IP 列表白名單/黑名單: 允許或阻止某些 IP 地址通過。
          • 性能分析: 提供一種記錄與 API 調(diào)用相關(guān)的使用和其他有用度量的方法。
          • 限速和流控: 控制 API 調(diào)用的能力。
          • 請求變形: 在進(jìn)一步轉(zhuǎn)發(fā)之前,能夠在轉(zhuǎn)發(fā)之前轉(zhuǎn)換請求和響應(yīng)(包括 Header 和 Body)。
          • 版本控制: 同時使用不同版本的 API 選項或可能以金絲雀發(fā)布或藍(lán)/綠部署的形式提供慢速推出 API。
          • 斷路器: 微服務(wù)架構(gòu)模式有用,以避免使用中斷。
          • 多協(xié)議支持: WebSocket/GRPC。
          • 緩存: 減少網(wǎng)絡(luò)帶寬和往返時間消耗,如果可以緩存頻繁要求的數(shù)據(jù),則可以提高性能和響應(yīng)時間
          • API 文檔: 如果計劃將 API 暴露給組織以外的開發(fā)人員,那么必須考慮使用 API 文檔,例如 Swagger 或 OpenAPI。

          有很多的開源軟件可以提供 API 網(wǎng)關(guān)的支持,下面我們就看看他們各自的架構(gòu)和功能。

          為了對這些開源網(wǎng)關(guān)進(jìn)行基本功能的驗證,我創(chuàng)建了一些代碼,使用 OpenAPI 生成了四個基本的 API 服務(wù),包含 Golang,Nodejs,Python Flask 和 Java Spring。

          API 使用了常見的寵物商店的樣例,聲明如下:

          openapi: "3.0.0"  
          info:  
            version: 1.0.0  
            title: Swagger Petstore  
            license:  
              name: MIT  
          servers:  
            - url: http://petstore.swagger.io/v1  
          paths:  
            /pets:  
              get:  
                summary: List all pets  
                operationId: listPets  
                tags:  
                  - pets  
                parameters:  
                  - name: limit  
                    in: query  
                    description: How many items to return at one time (max 100)  
                    required: false  
                    schema:  
                      typeinteger  
                      format: int32  
                responses:  
                  '200':  
                    description: A paged array of pets  
                    headers:  
                      x-next:  
                        description: A link to the next page of responses  
                        schema:  
                          type: string  
                    content:  
                      application/json:      
                        schema:  
                          $ref"#/components/schemas/Pets"  
                  default:  
                    description: unexpected error  
                    content:  
                      application/json:  
                        schema:  
                          $ref"#/components/schemas/Error"  
              post:  
                summary: Create a pet  
                operationId: createPets  
                tags:  
                  - pets  
                responses:  
                  '201':  
                    description: Null response  
                  default:  
                    description: unexpected error  
                    content:  
                      application/json:  
                        schema:  
                          $ref"#/components/schemas/Error"  
            /pets/{petId}:  
              get:  
                summary: Info for a specific pet  
                operationId: showPetById  
                tags:  
                  - pets  
                parameters:  
                  - name: petId  
                    in: path  
                    required: true  
                    description: The id of the pet to retrieve  
                    schema:  
                      type: string  
                responses:  
                  '200':  
                    description: Expected response to a valid request  
                    content:  
                      application/json:  
                        schema:  
                          $ref"#/components/schemas/Pet"  
                  default:  
                    description: unexpected error  
                    content:  
                      application/json:  
                        schema:  
                          $ref"#/components/schemas/Error"  
          components:  
            schemas:  
              Pet:  
                type: object  
                required:  
                  - id  
                  - name  
                properties:  
                  id:  
                    typeinteger  
                    format: int64  
                  name:  
                    type: string  
                  tag:  
                    type: string  
              Pets:  
                type: array  
                items:  
                  $ref"#/components/schemas/Pet"  
              Error:  
                type: object  
                required:  
                  - code  
                  - message  
                properties:  
                  code:  
                    typeinteger  
                    format: int32  
                  message:  
                    type: string  

          構(gòu)建好的 Web 服務(wù)通過 Docker Compose 來進(jìn)行容器化的部署。

          version: "3.7"  
          services:  
            goapi:  
              container_name: goapi  
              image: naughtytao/goapi:0.1  
              ports:  
                - "18000:8080"  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  
            nodeapi:  
              container_name: nodeapi  
              image: naughtytao/nodeapi:0.1  
              ports:  
                - "18001:8080"  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  
            flaskapi:  
              container_name: flaskapi  
              image: naughtytao/flaskapi:0.1  
              ports:  
                - "18002:8080"  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  
            springapi:  
              container_name: springapi  
              image: naughtytao/springapi:0.1  
              ports:  
                - "18003:8080"  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  

          我們在學(xué)習(xí)這些開源網(wǎng)關(guān)架構(gòu)的同時,也會對其最基本的路由轉(zhuǎn)發(fā)功能作出驗證。

          這里用戶發(fā)送的請求 server/service_name/v1/ 會發(fā)送給 API 網(wǎng)關(guān),網(wǎng)關(guān)通過 service name 來路由到不同的后端服務(wù)。

          圖片

          我們使用 K6 用 100 個并發(fā)跑 1000 次測試的結(jié)果如上圖,我們看到直連的綜合響應(yīng),每秒可以處理的請求數(shù)量大概是 1100+。

          Nginx

          Nginx 是異步框架的網(wǎng)頁服務(wù)器,也可以用作反向代理、負(fù)載平衡器和 HTTP 緩存。

          該軟件由伊戈爾·賽索耶夫創(chuàng)建并于 2004 年首次公開發(fā)布。2011 年成立同名公司以提供支持。2019 年 3 月 11 日,Nginx 公司被 F5 Networks 以 6.7 億美元收購。

          Nginx 有以下的特點:

          • 由 C 編寫,占用的資源和內(nèi)存低,性能高。
          • 單進(jìn)程多線程,當(dāng)啟動 Nginx 服務(wù)器,會生成一個 master 進(jìn)程,master 進(jìn)程會 fork 出多個 worker 進(jìn)程,由 worker 線程處理客戶端的請求。
          • 支持反向代理,支持 7 層負(fù)載均衡(拓展負(fù)載均衡的好處)。
          • 高并發(fā),Nginx 是異步非阻塞型處理請求,采用的 epollandqueue 模式。
          • 處理靜態(tài)文件速度快。
          • 高度模塊化,配置簡單。社區(qū)活躍,各種高性能模塊出品迅速。
          圖片

          如上圖所示,Nginx 主要由 Master,Worker 和 Proxy Cache 三個部分組成。

          Master 主控: NGINX 遵循主從架構(gòu)。它將根據(jù)客戶的要求為 Worker 分配工作。

          將工作分配給 Worker 后,Master 將尋找客戶的下一個請求,因為它不會等待 Worker 的響應(yīng)。一旦響應(yīng)來自 Worker,Master 就會將響應(yīng)發(fā)送給客戶端。

          Worker 工作單元: Worker 是 NGINX 架構(gòu)中的 Slave。每個工作單元可以單線程方式一次處理 1000 個以上的請求。

          一旦處理完成,響應(yīng)將被發(fā)送到主服務(wù)器。單線程將通過在相同的內(nèi)存空間而不是不同的內(nèi)存空間上工作來節(jié)省 RAM 和 ROM 的大小。多線程將在不同的內(nèi)存空間上工作。

          Cache 緩存: Nginx 緩存用于通過從緩存而不是從服務(wù)器獲取來非常快速地呈現(xiàn)頁面。在第一個頁面請求時,頁面將被存儲在高速緩存中。

          為了實現(xiàn) API 的路由轉(zhuǎn)發(fā),需要只需要對 Nginx 作出如下的配置:

          server {  
              listen 80 default_server;   
            
              location /goapi {  
                  rewrite ^/goapi(.*) $1 break;  
                  proxy_pass  http://goapi:8080;  
              }  
            
              location /nodeapi {  
                  rewrite ^/nodeapi(.*) $1 break;  
                  proxy_pass  http://nodeapi:8080;  
              }  
            
              location /flaskapi {  
                  rewrite ^/flaskapi(.*) $1 break;  
                  proxy_pass  http://flaskapi:8080;  
              }  
            
              location /springapi {  
                  rewrite ^/springapi(.*) $1 break;  
                  proxy_pass  http://springapi:8080;  
              }  
          }  

          我們基于不同的服務(wù) goapi,nodeapi,flaskapi 和 springapi,分別配置一條路由,在轉(zhuǎn)發(fā)之前,需要利用 rewrite 來去掉服務(wù)名,并發(fā)送給對應(yīng)的服務(wù)。

          使用容器把 Nginx 和后端的四個服務(wù)部署在同一個網(wǎng)絡(luò)下,通過網(wǎng)關(guān)連接路由轉(zhuǎn)發(fā)的。

          Nginx 的部署如下:

          version: "3.7"  
          services:  
            web:  
              container_name: nginx  
              image: nginx  
              volumes:  
                - ./templates:/etc/nginx/templates  
                - ./conf/default.conf:/etc/nginx/conf.d/default.conf  
              ports:  
                - "8080:80"  
              environment:  
                - NGINX_HOST=localhost  
                - NGINX_PORT=80  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  

          K6 通過 Nginx 網(wǎng)關(guān)的測試結(jié)果如下:

          圖片

          每秒處理的請求數(shù)量是 1093,和不通過網(wǎng)關(guān)轉(zhuǎn)發(fā)相比非常接近。

          從功能上看,Nginx 可以滿足用戶對于 API 網(wǎng)關(guān)的大部分需求,可以通過配置和插件的方式來支持不同的功能,性能非常優(yōu)秀。

          缺點是沒有管理的 UI 和管理 API,大部分的工作都需要手工配置 config 文件的方式來進(jìn)行。商業(yè)版本的功能會更加完善。

          Kong

          Kong 是基于 NGINX 和 OpenResty 的開源 API 網(wǎng)關(guān)。

          Kong 的總體基礎(chǔ)結(jié)構(gòu)由三個主要部分組成:NGINX 提供協(xié)議實現(xiàn)和工作進(jìn)程管理,OpenResty 提供 Lua 集成并掛鉤到 NGINX 的請求處理階段。

          而 Kong 本身利用這些掛鉤來路由和轉(zhuǎn)換請求。數(shù)據(jù)庫支持 Cassandra 或 Postgres 存儲所有配置。

          圖片

          Kong 附帶各種插件,提供訪問控制,安全性,緩存和文檔等功能。它還允許使用 Lua 語言編寫和使用自定義插件。

          Kong 也可以部署為 Kubernetes Ingress 并支持 GRPC 和 WebSockets 代理。

          NGINX 提供了強(qiáng)大的 HTTP 服務(wù)器基礎(chǔ)結(jié)構(gòu)。它處理 HTTP 請求處理,TLS 加密,請求日志記錄和操作系統(tǒng)資源分配(例如,偵聽和管理客戶端連接以及產(chǎn)生新進(jìn)程)。

          NGINX 具有一個聲明性配置文件,該文件位于其主機(jī)操作系統(tǒng)的文件系統(tǒng)中。

          雖然僅通過 NGINX 配置就可以實現(xiàn)某些 Kong 功能(例如,基于請求的 URL 確定上游請求路由),但修改該配置需要一定級別的操作系統(tǒng)訪問權(quán)限,以編輯配置文件并要求 NGINX 重新加載它們。

          而 Kong 允許用戶執(zhí)行以下操作:通過 RESTful HTTP API 更新配置。Kong 的 NGINX 配置是相當(dāng)基本的:除了配置標(biāo)準(zhǔn)標(biāo)頭,偵聽端口和日志路徑外,大多數(shù)配置都委托給 OpenResty。

          在某些情況下,在 Kong 的旁邊添加自己的 NGINX 配置非常有用,例如在 API 網(wǎng)關(guān)旁邊提供靜態(tài)網(wǎng)站。在這種情況下,您可以修改 Kong 使用的配置模板。

          NGINX 處理的請求經(jīng)過一系列階段。NGINX 的許多功能(例如,使用 C 語言編寫的模塊)都提供了進(jìn)入這些階段的功能(例如,使用 gzip 壓縮的功能)。

          雖然可以編寫自己的模塊,但是每次添加或更新模塊時都必須重新編譯 NGINX。為了簡化添加新功能的過程,Kong 使用了 OpenResty。

          OpenResty 是一個軟件套件,捆綁了 NGINX,一組模塊,LuaJIT 和一組 Lua 庫。

          其中最主要的是 ngx_http_lua_module一個NGINX 模塊,該模塊嵌入 Lua 并為大多數(shù) NGINX 請求階段提供 Lua 等效項。

          這有效地允許在 Lua 中開發(fā) NGINX 模塊,同時保持高性能(LuaJIT 相當(dāng)快),并且 Kong 用它來提供其核心配置管理和插件管理基礎(chǔ)結(jié)構(gòu)。

          Kong 通過其插件體系結(jié)構(gòu)提供了一個框架,可以掛接到上述請求階段。從上面的示例開始,Key Auth 和 ACL 插件都控制客戶端(也稱為使用者)是否應(yīng)該能夠發(fā)出請求。

          每個插件都在其處理程序中定義了自己的訪問函數(shù),并且該函數(shù)針對通過給定路由或服務(wù)啟用的每個插件執(zhí)行 kong.access()。

          執(zhí)行順序由優(yōu)先級值決定,如果 Key Auth 的優(yōu)先級為 1003,ACL 的優(yōu)先級為 950,則 Kong 將首先執(zhí)行 Key Auth 的訪問功能,如果它不放棄請求,則將執(zhí)行 ACL,然后再通過將該 ACL 傳遞給上游 proxy_pass。

          由于 Kong 的請求路由和處理配置是通過其 admin API 控制的,因此可以在不編輯底層 NGINX 配置的情況下即時添加和刪除插件配置。

          因為 Kong 本質(zhì)上提供了一種在 API 中注入位置塊(通過 API 定義)和配置的方法。它們通過將插件,證書等分配給這些 API。

          我們使用以下的配置部署 Kong 到容器中(省略四個微服務(wù)的部署):

          version: '3.7'  
            
          volumes:  
            kong_data: {}  
            
          networks:  
            kong-net:  
              external: false  
            
          services:  
            kong:  
              image: "${KONG_DOCKER_TAG:-kong:latest}"  
              user: "${KONG_USER:-kong}"  
              depends_on:  
                - db  
              environment:  
                KONG_ADMIN_ACCESS_LOG: /dev/stdout  
                KONG_ADMIN_ERROR_LOG: /dev/stderr  
                KONG_ADMIN_LISTEN: '0.0.0.0:8001'  
                KONG_CASSANDRA_CONTACT_POINTS: db  
                KONG_DATABASE: postgres  
                KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}  
                KONG_PG_HOST: db  
                KONG_PG_USER: ${KONG_PG_USER:-kong}  
                KONG_PROXY_ACCESS_LOG: /dev/stdout  
                KONG_PROXY_ERROR_LOG: /dev/stderr  
                KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password  
              secrets:  
                - kong_postgres_password  
              networks:  
                - kong-net  
              ports:  
                - "8080:8000/tcp"  
                - "127.0.0.1:8001:8001/tcp"  
                - "8443:8443/tcp"  
                - "127.0.0.1:8444:8444/tcp"  
              healthcheck:  
                test: ["CMD""kong""health"]  
                interval: 10s  
                timeout: 10s  
                retries: 10  
              restart: on-failure  
              deploy:  
                restart_policy:  
                  condition: on-failure  
            
            db:  
              image: postgres:9.5  
              environment:  
                POSTGRES_DB: ${KONG_PG_DATABASE:-kong}  
                POSTGRES_USER: ${KONG_PG_USER:-kong}  
                POSTGRES_PASSWORD_FILE: /run/secrets/kong_postgres_password  
              secrets:  
                - kong_postgres_password  
              healthcheck:  
                test: ["CMD""pg_isready""-U""${KONG_PG_USER:-kong}"]  
                interval: 30s  
                timeout: 30s  
                retries: 3  
              restart: on-failure  
              deploy:  
                restart_policy:  
                  condition: on-failure  
              stdin_open: true  
              tty: true  
              networks:  
                - kong-net  
              volumes:  
                - kong_data:/var/lib/postgresql/data  
          secrets:  
            kong_postgres_password:  
              file: ./POSTGRES_PASSWORD  

          數(shù)據(jù)庫選擇了 PostgreSQL,開源版本沒有 Dashboard,我們使用 RestAPI 創(chuàng)建所有的網(wǎng)關(guān)路由:

          curl -i -X POST http://localhost:8001/services \  
                    --data name=goapi \  
                    --data url='http://goapi:8080'  
              curl -i -X POST http://localhost:8001/services/goapi/routes \  
                  --data 'paths[]=/goapi' \  
                    --data name=goapi  

          需要先創(chuàng)建一個 service,然后在該 service 下創(chuàng)建一條路由。

          使用 K6 壓力測試的結(jié)果如下:

          每秒請求數(shù) 705 要明顯弱于 Nginx,所以所有的功能都是有成本的。

          APISIX

          Apache APISIX 是一個動態(tài)、實時、高性能的 API 網(wǎng)關(guān), 提供負(fù)載均衡、動態(tài)上游、灰度發(fā)布、服務(wù)熔斷、身份認(rèn)證、可觀測性等豐富的流量管理功能。

          APISIX 于 2019 年 4 月由中國的支流科技創(chuàng)建,于 6 月開源,并于同年 10 月進(jìn)入 Apache 孵化器。

          支流科技對應(yīng)的商業(yè)化產(chǎn)品的名字叫 API7 。APISIX 旨在處理大量請求,并具有較低的二次開發(fā)門檻。

          APISIX 的主要功能和特點有:

          • 云原生設(shè)計,輕巧且易于容器化。
          • 集成了統(tǒng)計和監(jiān)視組件,例如 Prometheus,Apache Skywalking 和 Zipkin。
          • 支持 gRPC,Dubbo,WebSocket,MQTT 等代理協(xié)議,以及從 HTTP 到 gRPC 的協(xié)議轉(zhuǎn)碼,以適應(yīng)各種情況。
          • 擔(dān)當(dāng) OpenID 依賴方的角色,與 Auth0,Okta 和其他身份驗證提供程序的服務(wù)連接。
          • 通過在運行時動態(tài)執(zhí)行用戶功能來支持無服務(wù)器,從而使網(wǎng)關(guān)的邊緣節(jié)點更加靈活。
          • 支持插件熱加載。
          • 不鎖定用戶,支持混合云部署架構(gòu)。
          • 網(wǎng)關(guān)節(jié)點無狀態(tài),可以靈活擴(kuò)展。

          從這個角度來看,API 網(wǎng)關(guān)可以替代 Nginx 來處理南北流量,也可以扮演 Istio 控制平面和 Envoy 數(shù)據(jù)平面的角色來處理東西向流量。

          APISIX 的架構(gòu)如下圖所示:

          圖片

          APISIX 包含一個數(shù)據(jù)平面,用于動態(tài)控制請求流量;一個用于存儲和同步網(wǎng)關(guān)數(shù)據(jù)配置的控制平面,一個用于協(xié)調(diào)插件的 AI 平面,以及對請求流量的實時分析和處理。

          它構(gòu)建在 Nginx 反向代理服務(wù)器和鍵值存儲 etcd 的之上,以提供輕量級的網(wǎng)關(guān)。

          它主要用 Lua 編寫,Lua 是類似于 Python 的編程語言。它使用 Radix 樹進(jìn)行路由,并使用前綴樹進(jìn)行 IP 匹配。

          使用 etcd 而不是關(guān)系數(shù)據(jù)庫來存儲配置可以使它更接近云原生,但是即使在任何服務(wù)器宕機(jī)的情況下,也可以確保整個網(wǎng)關(guān)系統(tǒng)的可用性。

          所有組件都是作為插件編寫的,因此其模塊化設(shè)計意味著功能開發(fā)人員只需要關(guān)心自己的項目即可。

          內(nèi)置的插件包括流控和速度限制,身份認(rèn)證,請求重寫,URI 重定向,開放式跟蹤和無服務(wù)器。

          APISIX 支持 OpenResty 和 Tengine 運行環(huán)境,并且可以在 Kubernetes 的裸機(jī)上運行。它同時支持 X86 和 ARM64。

          我們同樣使用 Docker Compose 來部署 APISIX:

          version: "3.7"  
            
          services:  
            apisix-dashboard:  
              image: apache/apisix-dashboard:2.4  
              restart: always  
              volumes:  
              - ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml  
              ports:  
              - "9000:9000"  
              networks:  
                apisix:  
                  ipv4_address: 172.18.5.18  
            
            apisix:  
              image: apache/apisix:2.3-alpine  
              restart: always  
              volumes:  
                - ./apisix_log:/usr/local/apisix/logs  
                - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro  
              depends_on:  
                - etcd  
              ##network_mode: host  
              ports:  
                - "8080:9080/tcp"  
                - "9443:9443/tcp"  
              networks:  
                apisix:  
                  ipv4_address: 172.18.5.11  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  
            
            etcd:  
              image: bitnami/etcd:3.4.9  
              user: root  
              restart: always  
              volumes:  
                - ./etcd_data:/etcd_data  
              environment:  
                ETCD_DATA_DIR: /etcd_data  
                ETCD_ENABLE_V2: "true"  
                ALLOW_NONE_AUTHENTICATION: "yes"  
                ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379"  
                ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"  
              ports:  
                - "2379:2379/tcp"  
              networks:  
                apisix:  
                  ipv4_address: 172.18.5.10  
            
          networks:  
            apisix:  
              driver: bridge  
              ipam:  
                config:  
                - subnet: 172.18.0.0/16  

          開源的 APISIX 支持 Dashboard 的方式來管理路由,而不是像 KONG 把儀表盤功能限制在商業(yè)版本中。

          但是 APISIX 的儀表盤不支持對路由 URI 進(jìn)行改寫,所以我們只好使用 RestAPI 來創(chuàng)建路由。

          創(chuàng)建一個服務(wù)的路由的命令如下:

          curl --location --request PUT 'http://127.0.0.1:8080/apisix/admin/routes/1' \  
          --header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \  
          --header 'Content-Type: text/plain' \  
          --data-raw '{  
              "uri": "/goapi/*",  
              "plugins": {  
                  "proxy-rewrite": {  
                      "regex_uri": ["^/goapi(.*)$","$1"]  
                  }  
              },  
              "upstream": {  
                  "type": "roundrobin",  
                  "nodes": {  
                      "goapi:8080": 1  
                  }  
              }  
          }'
            

          使用 K6 壓力測試的結(jié)果如下:

          圖片

          APISix 取得了 1155 的好成績,表現(xiàn)出接近不經(jīng)過網(wǎng)關(guān)的性能,可能緩存起到了很好的效果。

          Tyk

          Tyk 是一款基于 Golang 和 Redis 構(gòu)建的開源 API 網(wǎng)關(guān)。它于 2014 年創(chuàng)建,比 AWS 的 API 網(wǎng)關(guān)即服務(wù)功能早。Tyk 用 Golang 編寫,并使用 Golang 自己的 HTTP 服務(wù)器。

          Tyk 支持不同的運行方式:云,混合(在自己的基礎(chǔ)架構(gòu)中為 GW)和本地。

          圖片

          Tyk 由 3 個組件組成:

          • 網(wǎng)關(guān): 處理所有應(yīng)用流量的代理。
          • 儀表板: 可以從中管理 Tyk,顯示指標(biāo)和組織 API 的界面。
          • Pump: 負(fù)責(zé)持久保存指標(biāo)數(shù)據(jù),并將其導(dǎo)出到 MongoDB(內(nèi)置),ElasticSearch 或 InfluxDB 等。

          我們同樣使用 Docker Compose 來創(chuàng)建 Tyk 網(wǎng)關(guān)來進(jìn)行功能驗證。

          version: '3.7'  
          services:  
            tyk-gateway:  
              image: tykio/tyk-gateway:v3.1.1  
              ports:  
                - 8080:8080  
              volumes:  
                - ./tyk.standalone.conf:/opt/tyk-gateway/tyk.conf  
                - ./apps:/opt/tyk-gateway/apps  
                - ./middleware:/opt/tyk-gateway/middleware  
                - ./certs:/opt/tyk-gateway/certs  
              environment:  
                - TYK_GW_SECRET=foo  
              depends_on:  
                - tyk-redis  
            tyk-redis:  
              image: redis:5.0-alpine  
              ports:  
                - 6379:6379  

          Tyk 的 Dashboard 也是屬于商業(yè)版本的范疇,所我們又一次需要借助 API 來創(chuàng)建路由,Tyk 是通過 app 的概念來創(chuàng)建和管理路由的,你也可以直接寫 app 文件。

          curl --location --request POST 'http://localhost:8080/tyk/apis/' \  
          --header 'x-tyk-authorization: foo' \  
          --header 'Content-Type: application/json' \  
          --data-raw '{  
              "name": "GO API",  
              "slug": "go-api",  
              "api_id": "goapi",  
              "org_id": "goapi",  
              "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": "/goapi/",  
                "target_url": "http://host.docker.internal:18000/",  
                "strip_listen_path": true  
              },  
              "active": true  
          }'
            

          使用 K6 壓力測試的結(jié)果如下:

          圖片

          Tyk 的結(jié)果在 400-600 左右,性能上和 KONG 接近。

          Zuul

          Zuul 是 Netflix 開源的基于 Java 的 API 網(wǎng)關(guān)組件。

          圖片

          Zuul 包含多個組件:

          • zuul-core: 該庫包含編譯和執(zhí)行過濾器的核心功能。
          • zuul-simple-webapp: 該 Webapp 展示了一個簡單的示例,說明如何使用 zuul-core 構(gòu)建應(yīng)用程序。
          • zuul-netflix: 將其他 NetflixOSS 組件添加到 Zuul 的庫,例如,使用 Ribbon 路由請求。
          • zuul-netflix-webapp: 將 zuul-core 和 zuul-netflix 打包到一個易于使用的程序包中的 webapp。

          Zuul 提供了靈活性和彈性,部分是通過利用其他 Netflix OSS 組件進(jìn)行的:

          • Hystrix 用于流控。包裝對始發(fā)地的呼叫,這使我們可以在發(fā)生問題時丟棄流量并確定流量的優(yōu)先級。
          • Ribbon 是來自 Zuul 的所有出站請求的客戶,它提供有關(guān)網(wǎng)絡(luò)性能和錯誤的詳細(xì)信息,并處理軟件負(fù)載平衡以實現(xiàn)均勻的負(fù)載分配。
          • Turbine 實時匯總細(xì)粒度的指標(biāo),以便我們可以快速觀察問題并做出反應(yīng)。
          • Archaius 處理配置并提供動態(tài)更改屬性的能力。

          Zuul 的核心是一系列過濾器,它們能夠在路由 HTTP 請求和響應(yīng)期間執(zhí)行一系列操作。

          以下是 Zuul 過濾器的主要特征:

          • 類型: 通常定義路由流程中應(yīng)用過濾器的階段。(盡管它可以是任何自定義字符串)
          • 執(zhí)行順序: 在類型中應(yīng)用,定義跨多個過濾器的執(zhí)行順序。
          • 準(zhǔn)則: 執(zhí)行過濾器所需的條件。
          • 動作: 如果符合條件,則要執(zhí)行的動作。
          class DeviceDelayFilter extends ZuulFilter {  
            
              def static Random rand = new Random()  
            
              @Override  
              String filterType() {  
                 return 'pre'  
              }  
            
              @Override  
              int filterOrder() {  
                 return 5  
              }  
            
              @Override  
              boolean shouldFilter() {  
                 return  RequestContext.getRequest().  
                 getParameter("deviceType")?equals("BrokenDevice"):false  
              }  
            
              @Override  
              Object run() {  
                 sleep(rand.nextInt(20000)) // Sleep for a random number of  
                                            // seconds between [0-20]  
              }  
          }  

          Zuul 提供了一個框架來動態(tài)讀取,編譯和運行這些過濾器。過濾器不直接相互通信。

          而是通過每個請求唯一的 RequestContext 共享狀態(tài)。過濾器使用 Groovy 編寫。

          圖片

          有幾種與請求的典型生命周期相對應(yīng)的標(biāo)準(zhǔn)過濾器類型:

          • Pre 過濾器在路由到原點之前執(zhí)行。示例包括請求身份驗證,選擇原始服務(wù)器以及記錄調(diào)試信息。
          • Route 路由過濾器處理將請求路由到源。這是使用 Apache HttpClient 或 Netflix Ribbon 構(gòu)建和發(fā)送原始 HTTP 請求的地方。
          • 在將請求路由到源之后,將執(zhí)行 Post 過濾器。示例包括將標(biāo)準(zhǔn) HTTP 標(biāo)頭添加到響應(yīng),收集統(tǒng)計信息和指標(biāo)以及將響應(yīng)從源流傳輸?shù)娇蛻舳恕?/section>
          • 在其他階段之一發(fā)生錯誤時,將執(zhí)行 Error 過濾器。

          Spring Cloud 創(chuàng)建了一個嵌入式 Zuul 代理,以簡化一個非常常見的用例的開發(fā),在該用例中,UI 應(yīng)用程序希望代理對一個或多個后端服務(wù)的調(diào)用。

          此功能對于用戶界面代理所需的后端服務(wù)很有用,從而避免了為所有后端獨立管理 CORS 和身份驗證問題的需求 。

          要啟用它,請使用 @EnableZuulProxy 注解一個 Spring Boot 主類,這會將本地調(diào)用轉(zhuǎn)發(fā)到適當(dāng)?shù)姆?wù)。

          Zuul 是 Java 的一個庫,他并不是一款開箱即用的 API 網(wǎng)關(guān),所以需要用 Zuul 開發(fā)一個應(yīng)用來對其功能進(jìn)行測試。

          對應(yīng)的 Java 的 POM 如下:

          <project  
              xmlns="http://maven.apache.org/POM/4.0.0"  
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
            
              <modelVersion>4.0.0</modelVersion>  
              <groupId>naughtytao.apigateway</groupId>  
              <artifactId>demo</artifactId>  
              <version>0.0.1-SNAPSHOT</version>  
              <parent>  
                  <groupId>org.springframework.boot</groupId>  
                  <artifactId>spring-boot-starter-parent</artifactId>  
                  <version>1.4.7.RELEASE</version>  
                  <relativePath />  
                  <!-- lookup parent from repository -->  
              </parent>  
              <properties>  
                  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
                  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>  
                  <java.version>1.8</java.version>  
                  <!-- Dependencies -->  
                  <spring-cloud.version>Camden.SR7</spring-cloud.version>  
              </properties>  
              <dependencyManagement>  
                  <dependencies>  
                      <dependency>  
                          <groupId>org.springframework.cloud</groupId>  
                          <artifactId>spring-cloud-dependencies</artifactId>  
                          <version>${spring-cloud.version}</version>  
                          <type>pom</type>  
                          <scope>import</scope>  
                      </dependency>  
                  </dependencies>  
              </dependencyManagement>  
              <dependencies>  
                  <dependency>  
                      <groupId>org.springframework.cloud</groupId>  
                      <artifactId>spring-cloud-starter-zuul</artifactId>  
                  </dependency>  
                  <dependency>  
                      <groupId>org.springframework.boot</groupId>  
                      <artifactId>spring-boot-starter-actuator</artifactId>  
                      <exclusions>  
                          <exclusion>  
                              <groupId>org.springframework.boot</groupId>  
                              <artifactId>spring-boot-starter-logging</artifactId>  
                          </exclusion>  
                      </exclusions>  
                  </dependency>  
                  <dependency>  
                      <groupId>org.springframework.boot</groupId>  
                      <artifactId>spring-boot-starter-log4j2</artifactId>  
                  </dependency>  
            
                  <!-- enable authentication if security is included -->  
                  <!-- <dependency>  
                      <groupId>org.springframework.boot</groupId>  
                      <artifactId>spring-boot-starter-security</artifactId>  
                  </dependency> -->
            
                  <dependency>  
                      <groupId>org.springframework.boot</groupId>  
                      <artifactId>spring-boot-starter-web</artifactId>  
                  </dependency>  
                  <!-- API, java.xml.bind module -->  
                  <dependency>  
                      <groupId>jakarta.xml.bind</groupId>  
                      <artifactId>jakarta.xml.bind-api</artifactId>  
                      <version>2.3.2</version>  
                  </dependency>  
            
                  <!-- Runtime, com.sun.xml.bind module -->  
                  <dependency>  
                      <groupId>org.glassfish.jaxb</groupId>  
                      <artifactId>jaxb-runtime</artifactId>  
                      <version>2.3.2</version>  
                  </dependency>  
                  <dependency>  
                      <groupId>org.springframework.boot</groupId>  
                      <artifactId>spring-boot-starter-test</artifactId>  
                      <scope>test</scope>  
                  </dependency>  
                  <dependency>  
                      <groupId>org.junit.jupiter</groupId>  
                      <artifactId>junit-jupiter-api</artifactId>  
                      <version>5.0.0-M5</version>  
                      <scope>test</scope>  
                  </dependency>  
              </dependencies>  
              <build>  
                  <plugins>  
                      <plugin>  
                          <groupId>org.springframework.boot</groupId>  
                          <artifactId>spring-boot-maven-plugin</artifactId>  
                      </plugin>  
                      <plugin>  
                          <groupId>org.apache.maven.plugins</groupId>  
                          <artifactId>maven-compiler-plugin</artifactId>  
                          <version>3.3</version>  
                          <configuration>  
                              <source>1.8</source>  
                              <target>1.8</target>  
                          </configuration>  
                      </plugin>  
                  </plugins>  
              </build>  
          </project>  

          主要應(yīng)用代碼如下:

          package naughtytao.apigateway.demo;  
            
          import org.springframework.boot.SpringApplication;  
          import org.springframework.boot.autoconfigure.EnableAutoConfiguration;  
          import org.springframework.boot.autoconfigure.SpringBootApplication;  
          import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;  
          import org.springframework.cloud.netflix.zuul.EnableZuulProxy;  
          import org.springframework.context.annotation.ComponentScan;  
          import org.springframework.context.annotation.Bean;  
            
          import naughtytao.apigateway.demo.filters.ErrorFilter;  
          import naughtytao.apigateway.demo.filters.PostFilter;  
          import naughtytao.apigateway.demo.filters.PreFilter;  
          import naughtytao.apigateway.demo.filters.RouteFilter;  
            
          @SpringBootApplication  
          @EnableAutoConfiguration(exclude = { RabbitAutoConfiguration.class })  
          @EnableZuulProxy  
          @ComponentScan("naughtytao.apigateway.demo")  
          public class DemoApplication 
          {  
            
              public static void main(String[] args) {  
                  SpringApplication.run(DemoApplication.classargs);  
              }  
          }  

          Docker 構(gòu)建文件如下:

          FROM maven:3.6.3-openjdk-11  
          WORKDIR /usr/src/app  
          COPY src ./src  
          COPY pom.xml ./  
          RUN mvn -f ./pom.xml clean package -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true   
            
          EXPOSE 8080  
          ENTRYPOINT ["java","-jar","/usr/src/app/target/demo-0.0.1-SNAPSHOT.jar"]  

          路由的配置寫在 application.properties 中:

          #Zuul routes.  
          zuul.routes.goapi.url=http://goapi:8080  
          zuul.routes.nodeapi.url=http://nodeapi:8080  
          zuul.routes.flaskapi.url=http://flaskapi:8080  
          zuul.routes.springapi.url=http://springapi:8080  
            
          ribbon.eureka.enabled=false  
          server.port=8080  

          我們同樣使用 Docker Compose 運行 Zuul 的網(wǎng)關(guān)來進(jìn)行驗證:

          version: '3.7'  
          services:  
            gateway:  
              image: naughtytao/zuulgateway:0.1   
              ports:  
                - 8080:8080  
              volumes:  
                - ./config/application.properties:/usr/src/app/config/application.properties  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  

          使用 K6 壓力測試的結(jié)果如下:

          圖片

          在相同的配置條件下(單核,256M),Zuul 的壓測結(jié)果要明顯差于其它幾個,只有 200 左右。

          圖片

          在分配更多資源的情況下,4 核 2G,Zuul 的性能提升到 600-800,所以 Zuul 對于資源的需求還是比較明顯的。

          另外需要提及的是,我們使用的是 Zuul1,Netflix 已經(jīng)推出了 Zuul2。Zuul2 對架構(gòu)做出了較大的改進(jìn)。

          Zuul1 本質(zhì)上就是一個同步 Servlet,采用多線程阻塞模型。Zuul2 的基于 Netty 實現(xiàn)了異步非阻塞編程模型。

          同步的方式,比較容易調(diào)試,但是多線程本身需要消耗 CPU 和內(nèi)存資源,所以它的性能要差一些。

          而采用非阻塞模式的 Zuul,因為線程開銷小,所支持的鏈接數(shù)量要更多,也更節(jié)省資源。

          Gravitee

          Gravitee 是 Gravitee.io 開源的,基于 Java 的,簡單易用,性能高,且具成本效益的開源 API 平臺,可幫助組織保護(hù),發(fā)布和分析您的 API。

          圖片

          Gravitee 可以通過設(shè)計工作室和路徑的兩種方式來創(chuàng)建和管理 API:

          圖片

          Gravity 提供網(wǎng)關(guān),API 門戶和 API 管理,其中網(wǎng)關(guān)和管理 API 部分是開源的,門戶需要注冊許可證來使用。

          圖片
          圖片

          后臺使用 MongoDB 作為存儲,支持 ES 接入。

          我們同樣使用 Docker Compose 來部署整個 Gravitee 的棧:

          #  
          # Copyright (C) 2015 The Gravitee team (http://gravitee.io)  
          #  
          # Licensed under the Apache License, Version 2.0 (the "License");  
          # you may not use this file except in compliance with the License.  
          # You may obtain a copy of the License at  
          #  
          #         http://www.apache.org/licenses/LICENSE-2.0  
          #  
          # Unless required by applicable law or agreed to in writing, software  
          # distributed under the License is distributed on an "AS IS" BASIS,  
          # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
          # See the License for the specific language governing permissions and  
          # limitations under the License.  
          #  
          version: '3.7'  
            
          networks:  
            frontend:  
              name: frontend  
            storage:  
              name: storage  
            
          volumes:  
            data-elasticsearch:  
            data-mongo:  
            
          services:  
            mongodb:  
              image: mongo:${MONGODB_VERSION:-3.6}  
              container_name: gio_apim_mongodb  
              restart: always  
              volumes:  
                - data-mongo:/data/db  
                - ./logs/apim-mongodb:/var/log/mongodb  
              networks:  
                - storage  
            
            elasticsearch:  
              image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION:-7.7.0}  
              container_name: gio_apim_elasticsearch  
              restart: always  
              volumes:  
                - data-elasticsearch:/usr/share/elasticsearch/data  
              environment:  
                - http.host=0.0.0.0  
                - transport.host=0.0.0.0  
                - xpack.security.enabled=false  
                - xpack.monitoring.enabled=false  
                - cluster.name=elasticsearch  
                - bootstrap.memory_lock=true  
                - discovery.type=single-node  
                - "ES_JAVA_OPTS=-Xms512m -Xmx512m"  
              ulimits:  
                memlock:  
                  soft: -1  
                  hard: -1  
                nofile: 65536  
              networks:  
                - storage  
            
            gateway:  
              image: graviteeio/apim-gateway:${APIM_VERSION:-3}  
              container_name: gio_apim_gateway  
              restart: always  
              ports:  
                - "8082:8082"  
              depends_on:  
                - mongodb  
                - elasticsearch  
              volumes:  
                - ./logs/apim-gateway:/opt/graviteeio-gateway/logs  
              environment:  
                - gravitee_management_mongodb_uri=mongodb://mongodb:27017/gravitee?serverSelectionTimeoutMS=5000&connectTimeoutMS=5000&socketTimeoutMS=5000  
                - gravitee_ratelimit_mongodb_uri=mongodb://mongodb:27017/gravitee?serverSelectionTimeoutMS=5000&connectTimeoutMS=5000&socketTimeoutMS=5000  
                - gravitee_reporters_elasticsearch_endpoints_0=http://elasticsearch:9200  
              networks:  
                - storage  
                - frontend  
              deploy:  
                resources:  
                  limits:  
                    cpus: '1'  
                    memory: 256M  
                  reservations:  
                    memory: 256M  
            
            management_api:  
              image: graviteeio/apim-management-api:${APIM_VERSION:-3}  
              container_name: gio_apim_management_api  
              restart: always  
              ports:  
                - "8083:8083"  
              links:  
                - mongodb  
                - elasticsearch  
              depends_on:  
                - mongodb  
                - elasticsearch  
              volumes:  
                - ./logs/apim-management-api:/opt/graviteeio-management-api/logs  
              environment:  
                - gravitee_management_mongodb_uri=mongodb://mongodb:27017/gravitee?serverSelectionTimeoutMS=5000&connectTimeoutMS=5000&socketTimeoutMS=5000  
                - gravitee_analytics_elasticsearch_endpoints_0=http://elasticsearch:9200  
              networks:  
                - storage  
                - frontend  
            
            management_ui:  
              image: graviteeio/apim-management-ui:${APIM_VERSION:-3}  
              container_name: gio_apim_management_ui  
              restart: always  
              ports:  
                - "8084:8080"  
              depends_on:  
                - management_api  
              environment:  
                - MGMT_API_URL=http://localhost:8083/management/organizations/DEFAULT/environments/DEFAULT/  
              volumes:  
                - ./logs/apim-management-ui:/var/log/nginx  
              networks:  
                - frontend  
            
            portal_ui:  
              image: graviteeio/apim-portal-ui:${APIM_VERSION:-3}  
              container_name: gio_apim_portal_ui  
              restart: always  
              ports:  
                - "8085:8080"  
              depends_on:  
                - management_api  
              environment:  
                - PORTAL_API_URL=http://localhost:8083/portal/environments/DEFAULT  
              volumes:  
                - ./logs/apim-portal-ui:/var/log/nginx  
              networks:  
                - frontend  

          我們使用管理 UI 來創(chuàng)建四個對應(yīng)的 API 來進(jìn)行網(wǎng)關(guān)的路由,也可以用 API 的方式,Gravitee 是這個開源網(wǎng)關(guān)中,唯一管理 UI 也開源的產(chǎn)品。

          使用 K6 壓力測試的結(jié)果如下:

          圖片

          和同樣采用 Java 的 Zuul 類似,Gravitee 的響應(yīng)只能達(dá)到 200 左右,而且還出現(xiàn)了一些錯誤。我們只好再一次提高網(wǎng)關(guān)的資源分配到 4 核 2G。

          圖片

          提高資源分配后的性能來到了 500-700,稍微好于 Zuul。

          總結(jié)

          本文分析了幾種開源 API 網(wǎng)關(guān)的架構(gòu)和基本功能,為大家在架構(gòu)選型的時候提供一些基本的參考信息,本文做作的測試數(shù)據(jù)比較簡單,場景也比較單一,不能作為實際選型的依據(jù)。

          Nginx: 基于 C 開發(fā)的高性能 API 網(wǎng)關(guān),擁有眾多的插件,如果你的 API 管理的需求比較簡單,接受手工配置路由,Nginx 是個不錯的選擇。

          Kong: 是基于 Nginx 的 API 網(wǎng)關(guān),使用 OpenResty 和 Lua 擴(kuò)展,后臺使用 PostgreSQL,功能眾多,社區(qū)的熱度很高,但是性能上看比起 Nginx 有相當(dāng)?shù)膿p失。如果你對功能和擴(kuò)展性有要求,可以考慮 Kong。

          APISIX: 和 Kong 的架構(gòu)類似,但是采用了云原生的設(shè)計,使用 ETCD 作為后臺,性能上比起 Kong 有相當(dāng)?shù)膬?yōu)勢,適合對性能要求高的云原生部署的場景。特別提一下,APISIX 支持 MQTT 協(xié)議,對于構(gòu)建 IOT 應(yīng)用非常友好。

          Tyk: 使用 Golang 開發(fā),后臺使用 Redis,性能不錯,如果你喜歡 Golang,可以考慮一下。

          要注意的是 Tyk 的開源協(xié)議是 MPL,是屬于修改代碼后不能閉源,對于商業(yè)化應(yīng)用不是很友好。

          Zuul: 是 Netflix 開源的基于 Java 的 API 網(wǎng)關(guān)組件,他并不是一款開箱即用的 API 網(wǎng)關(guān),需要和你的 Java 應(yīng)用一起構(gòu)建,所有的功能都是通過集成其他組件的方式來使用。

          適合對于 Java 比較熟悉,用 Java 構(gòu)建的應(yīng)用的場景,缺點是性能其他的開源產(chǎn)品要差一些,同樣的性能條件下,對于資源的要求會更多。

          Gravitee: 是 Gravitee.io 開源的基于 Java 的 API 管理平臺,它能對 API 的生命周期進(jìn)行管理,即使是開源版本,也有很好的 UI 支持。

          但是因為采用了 Java 構(gòu)建,性能同樣是短板,適合對于 API 管理有強(qiáng)烈需求的場景。

          本文所有的代碼可以從這里獲得:

          https://github.com/gangtao/api-gateway

          作者:Gang Tao

          編輯:陶家龍

          出處:zhuanlan.zhihu.com/p/358862217


          “拍一拍” 能撤回了 !!!

          5款Chrome插件,第1款絕對良心!

          為開發(fā)色情游戲,這家公司赴日尋找AV女優(yōu)拍攝,期望暴力賺錢結(jié)果...

          拼多多終于釀成慘劇

          華為阿里下班時間曝光:所有的光鮮,都有加班的味道


          關(guān)


          ,學(xué),西學(xué)學(xué)護(hù),質(zhì),結(jié),關(guān)[],學(xué)習(xí)進(jìn)!


          瀏覽 53
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美A区 欧美狂操 | 天码人妻一区二区三区在线看 | 国产在线自在拍在线观看 | 色婷婷国产精品 | 三级在线观看视频 |