API 网关
1. API 网关介绍
作用: 用来接收客户端的请求,把这些请求转发给后端服务
当前端客户端请求代理向后端发出请求的时候,这个请求先由 API 网关接收,然后 API 网关把请求转发个对应的服务
无论服务有多少个,反应给用户端的只有一个接口
核心作用: 转发请求
现代的 API 网关,除了具备基本的转发功能外,通常还具有:
多协议支持:tcp,http、https、websock、gRPC
负载均衡 ( 将多个请求进行负载均衡 )
身份验证 ( 访问控制 : 判断请求有没有权限访问对应的服务 )
监控、日志 ( 监控服务正常不正常 )
缓存 ( 可以缓存一部分服务的数据,有些请求就不要请求打到对应的服务了 )
熔断、限流
2. Kong 介绍
The fastest, most-adopted API gateway is just the start.
以上是 Kong 官网的口号。最快、使用最多的 API 网关仅是个开始。
Kong 是一个可扩展的开源 API 平台(也称为 API 网关或 API 中间件)。Kong 最初由 Kong Inc.(以前称为 Mashape)构建,用于为其 API Marketplace 保护,管理和扩展超过15,000 个微服务,每月产生数十亿个请求。
Kong 是一个在 Nginx 中运行的 Lua 应用程序,可以通过 lua-nginx 模块实现。但是 Kong 不是用这个模块编译 Nginx 的,而是与 OpenRestry 一起发布,OpenRestry 已经包含了 lua-nginx-module。OpenRestry 是Nginx 的一组扩展功能模块。
特性:
云原生:平台无关,支持任意平台,裸机容器或云平台
服务发现:通过第三方 DNS 解析做服务发现,如consul
各种协议支持:ws、wss、gRPC、HTTP、HTTPs、RestAPI
支持分布式集群部署、节点恢复等
支持多种负载均衡实现:Hash-Based(cookie、ip),多个 upstream
日志、监控
SSL 证书
支持多种认证机制:OAuth2.0、JWT、HMAC、Basic 等
性能高,基于 Nginx,支持缓存等
支持服务检测,心跳、断路、限流等
支持插件功能扩展
3. Kong docker 方式yunx
3.1 非数据环境启动
不推荐
3.2 数据库环境启动
初始化数据库
sudo docker pull postgres
sudo docker run -d --name kongDatabaseDev \
--net=host \
-p 5432:5432 \
-e "POSTGRES_USER=kong" \
-e "POSTGRES_DB=kong" \
-e "POSTGRES_PASSWORD=kong" \
postgres
在数据库里面初始化 kong 所需要的数据库结构
指定 kong 这个镜像怎么找到 postgres 这个数据库,同时要指定数据库的密码
sudo docker run \
--net=host \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=localhost" \
-e "KONG_PG_USER=kong" \
-e "KONG_PG_PASSWORD=kong" \
kong kong migrations bootstrap
docker run \
--net=host \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=localhost" \
-e "KONG_PG_USER=kong" \
-e "KONG_PG_PASSWORD=kong" \
kong/kong-gateway:3.5.0.1 kong migrations bootstrap
执行完成说明,在 postgres 这个数据库中已经构建好了 Kong 所依赖的数据结构
启动 Kong
https://docs.konghq.com/gateway/3.5.x/reference/configuration
sudo docker run -it -d --rm --name kongDev \
--net=host \
-p 8000:8000 \
-p 8443:8443 \
-p 8001:8001 \
-p 8444:8444 \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=localhost" \
-e "KONG_PG_USER=kong" \
-e "KONG_PG_PASSWORD=kong" \
-e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
-e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
-e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
-e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
-e "KONG_DNS_RESOLVER=127.0.0.1:8600" \
-e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \
kong
docker run -d --name kong-Dev \
--net=host \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=localhost" \
-e "KONG_PG_USER=kong" \
-e "KONG_PG_PASSWORD=kong" \
-e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
-e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
-e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
-e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
-e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \
-e "KONG_DNS_RESOLVER=127.0.0.1:8600" \
-e "KONG_ADMIN_GUI_URL=http://localhost:8002" \
-p 8000:8000 \
-p 8443:8443 \
-p 8001:8001 \
-p 8444:8444 \
-p 8002:8002 \
-p 8445:8445 \
-p 8003:8003 \
-p 8004:8004 \
kong/kong-gateway:3.5.0.1
KONG_DNS_RESOLVER 重要 ! ! !
说明:
-e "KONG_DATABASE=postgres"
,postgres 数据库-e "KONG_PG_HOST=localhost"
, 数据库信息,host、user、password-e "KONG_PG_USER=kong"
-e "KONG_PG_PASSWORD=kong"
-e "KONG_PROXY_ACCESS_LOG=/dev/stdout"
,代理访问日志-e "KONG_ADMIN_ACCESS_LOG=/dev/stdout"
,Admin 访问日志-e "KONG_PROXY_ERROR_LOG=/dev/stderr"
,代理错误日志-e "KONG_ADMIN_ERROR_LOG=/dev/stderr"
, Admin 错误日志-e "KONG_DNS_RESOLVER=127.0.0.1:8600"
,DNS 解析服务器-e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl"
,Admin 监听-e "KONG_ADMIN_GUI_URL=http://..:8002"
,GUI 界面暴露端口,我们使用 --net=host 模式,可以忽略端口映射
先安装数据库,再安装数据库结构,最后再初始化 Kong
测试
# 1.首页
localhost:8001/
# 2.所有服务
localhost:8001/services
# 3.GUI界面
http://...:8002/workspaces
4. 配置基于 Counsul 的转发服务
利用 Kong 的 Admin API 完成配置服务,完成对服务的转发
步骤:
前端通过 8000 端口请求 Kong API 网关请求 Product 服务 ( 自己定义的微服务 ) ,Kong 五服务注册中心找到 Product 服务的地址,然后将这个地址转发到对应的服务上
其中 Admin API 负责管理请求路由
4.1 添加一个 service
curl -i -X POST \
--url http://localhost:8001/services/ \
--data 'name=product-service' \
--data 'url=http://product.service.consul'
也可以通过 APIfox 发送请求
到这里服务就添加完毕了,但是还不知道服务具体的地址,这个需要 consul 来配置
4.2 添加一个路由 route
在
serveces/
后面添加对应的服务名product—service
,表示针对product-service
处理路由以
/product
开头的请求都应该转发到 service 上
curl -i -X POST \
--url http://localhost:8001/services/product-service/routes \
--data 'paths[]=/product'
访问:8001/route
可以看到路由定义成功
4.3 启动 consul 服务中心
sudo docker run -it -d \
--net=host \
-p 8500:8500 \
-p 8600:8600 \
--name=ConsulDevServer \
consul:1.15.4 agent -dev -client=0.0.0.0
# 验证是否能进入ui界面
http://....:8500/
通过 Go 代码注册服务 ( 在服务发现博客中 )
// 启动三个服务
// addr 使用服务器内网IP
go run ServiceHealthCheck.go -addr 10.0.8.13 -port 9000
go run ServiceHealthCheck.go -addr 10.0.8.13 -port 9001
go run ServiceHealthCheck.go -addr 10.0.8.13 -port 9002
root@VM-8-13-debian:~# curl http://10.0.8.13:9000/info
Product Service, 10.0.8.13:9000
root@VM-8-13-debian:~# curl http://10.0.8.13:9001/info
Product Service, 10.0.8.13:9001
root@VM-8-13-debian:~# curl http://10.0.8.13:9002/info
Product Service, 10.0.8.13:9002
会随机在三个服务中选择一个为当前请求进行服务
目前的负载均衡是 consul 做的
一定要给 kong 配置 dns_resolver , 并且端口为 8600 ( 因为 consul 的 dns 默认监听在 127.0.0.1:8600 )
5. Kong 核心对象
Sevice : 某个服务
Route : 路由,接收前端请求
Consumer : 消费者 , 服务的使用者 ( 使用网站/APP的登录之后的用户信息 )
Plugin : 插件 , 附加在消费者 , 路由 , 服务上的扩展功能 ( Kong 的核心功能是请求转发,除此之外的大部分功能都是以插件的形式扩展到 Kong )
Certificate : 证书
SNI : 服务器名称指示
Upstream : 虚拟主机名 , 可用于通过多个服务 ( 目标 ) 对传入请求进行负载均衡
一个服务可以对应一个 Upstream 服务地址,一个 Upstram 对应多个 Target ,在其中做负载均衡
Target : 目标 IP 地址 / 主机名 , 其端口表示后端服务的实力 , 每个 upstream 都可以有多个 target,支持负载均衡
如图 : 消费发起请求,请求携带者消费者数据到路由,路由转发到服务,插件会部署到路由,服务,消费者上
对应关系:
service : route -> 1 : n
service, route, consumer : plugin -> 1 : n
service, upstram -> 1 : 1
upstream : target -> 1 : n
全部的对象支持 Admin API 管理,同时 API 为 Restful 风格
另外,非 DB 模式下面,所有修改类的 API 全部失效,只有在 DB 模式下面,才能做全部的 crud 操作
6. Kong 管理 consumer
Kong 管理 consumer : https://docs.konghq.com/gateway/latest/admin-api/#consumer-object
consumer 结构定义
{
"id": "ec1a1f6f-2aa4-4e58-93ff-b56368f19b27",
"created_at": 1422386534,
"updated_at": 1422386534,
"username": "my-username",
"custom_id": "my-custom-id",
"tags": ["user-level", "low-priority"]
}
7. Kong 管理 services
Kong 管理 services : https://docs.konghq.com/gateway/latest/admin-api/#service-object
service 结构定义
{
"id": "9748f662-7711-4a90-8186-dc02f10eb0f5",
"created_at": 1422386534,
"updated_at": 1422386534,
"name": "my-service",
"retries": 5,
"protocol": "http",
"host": "example.com",
"port": 80,
"path": "/some_api",
"connect_timeout": 60000,
"write_timeout": 60000,
"read_timeout": 60000,
"tags": ["user-level", "low-priority"],
"client_certificate": {"id":"4e3ad2e4-0bc4-4638-8e34-c84a417ba39b"},
"tls_verify": true,
"tls_verify_depth": null,
"ca_certificates": ["4e3ad2e4-0bc4-4638-8e34-c84a417ba39b", "51e77dc2-8f3e-4afa-9d0e-0e3bbbcfd515"],
"enabled": true
}
8. Kong 管理插件
官网列出了所有插件 : https://docs.konghq.com/hub/
Kong 管理插件 API : https://docs.konghq.com/gateway/latest/admin-api/#plugin-object
插件结构定义
{
"id": "ce44eef5-41ed-47f6-baab-f725cecf98c7",
"name": "rate-limiting",
"created_at": 1422386534,
"updated_at": 1422386534,
"route": null,
"service": null,
"consumer": null,
"instance_name": rate-limiting-foo,
"config": {"hour":500, "minute":20},
"protocols": ["http", "https"],
"enabled": true,
"tags": ["user-level", "low-priority"],
"ordering": {"before":["plugin-name"]}
}
插件有优先级,始终执行一次,并且每个请求仅运行一次
在官网优优先级顺序,可以简单的记为消费者,路由,服务
9. Kong 负载均衡
限流 : 当请求当到一定规模时,控制 API 的请求量
对超出限制的请求量作出快速拒绝,快速失败,丢弃处理,以保证本服务以及下游资源系统的稳定
常用的限流算法有:
固定窗口计数法 ( Fixed Window )
滑动窗口计数法 ( Sliding Window )
漏桶算法 ( Leaky Bucket )
令牌桶算法 ( Token Bucket )
kong 网关中实现了固定窗口计数法和滑动窗口计数法
10.1 固定窗口计数法
在固定的时间内,比如 5s 内只能处理 10000 个请求,在该窗口时间段内,每来一个请求,计数器加 1,当请求数达到限额时,窗口时间内之后的请求都讲被丢弃
优点:实现容器,资源使用率低
缺点:
如果在前半段时间内达到了请求阈值,那个后半段时间内该服务无法使用
瞬时流量可能产生两倍于阈值的问题
10.2 滑动窗口计数法
滑动窗口计数法是固定窗口计数法的改进,解决了切换窗口可能会产生两倍与请求阈值的问题,TCP 协议中的数据包传输,同样采用滑动窗口进行流量控制
滑动窗口的窗口时间段是随着时间向下滑动的,而滑动的时间段就是滑动周期,将 5s 划分为 5个小窗口,每隔 1s 移动一次,子窗口划分的越多,则限流越精准,也称越平滑。
每个小区间单独统计请求次数,滑动窗口的次数为全部子区间次数之和。若超过最大限制,则本窗口后续请求会被限制。随着时间推移,进入下一个窗口期,重新计算全部子区间之和
实操时,超限后的请求往往会被缓存起来,后边慢慢处理,而不是直接丢弃,来提升应用可用性。
10.3 漏桶算法
10.4 令牌桶算法
11. 服务熔断和降级
11.1
评论区