Kong:一个请求的生命期
Kong 扮演的角色
作为一个 API 网关,Kong 既可以作为负载均衡器,也可以作为反向代理、认证中心等等。可以看作一个基于 Lua 的超级加强版的 Nginx
Kong 的每个 Node 是多进程的。有一个 master 进程,多个 worker 进程。每个进程又拥有多个线程。就像下图的黄色圈圈。
作为 worker 的线程,各自又会管理很多个连接。这些连接可以如下分类:
-
可用连接:这些连接是空闲的,可以被 worker 使用
-
未阻塞连接:当一个新请求到来时,worker 会从可用连接中取出一个,然后将其放入未阻塞连接中。当请求处理完毕后,worker 会将连接放回可用连接中
-
正在处理的连接:由于采用多路复用模型,实际上正在处理的连接只有一个。未阻塞连接会一个接一个地被处理
-
阻塞连接:当请求处理过程中,需要等待外部服务的响应时,连接会被放入阻塞连接中。当外部服务响应后,连接会被放回未阻塞连接中
-
保持存活(keepalive)的连接:当请求处理完毕后,worker 会判断是否需要保持连接。如果需要,连接会被放入保持存活的连接中。当下一个请求到来时,worker 会从保持存活的连接中取出一个,然后将其放入未阻塞连接中
Keep-Alive 是用于复用连接的方式。由于 TLS 需要进行 SSL 握手,这个过程的开销比较大。所以,如果能够复用连接,就可以避免这个开销。
Phases
每个 Kong Node 都会经历多个阶段。
Init
这个阶段只会在 Node 启动时执行,且只在 Master 进程执行。主要做以下事情:
-
创建 Lua VM
-
加载配置文件
-
检查迁移
-
加载插件
-
初始化数据库 / Dbless / Hybird
-
初始化 DNS
-
初始化 PDK
-
初始化证书
-
初始化路由和插件迭代器
Init Worker
之后进入 init_worker
阶段。这个阶段会在每个 Worker 进程中执行。主要做以下事情:
-
复制主进程的 Lua VM 因此,每个 worker 进程都有自己的 Lua VM,且各种变量的初始值和主进程一致 并且,所有的修改都是局部的
-
初始化随机种子
-
初始化并订阅 cluster events
-
初始化并订阅 worker events
-
初始化并预热缓存
-
初始化负载均衡器和健康检查
-
初始化匿名报告
-
启动外部插件服务器
-
让每个插件执行
init_worker
钩子
请求生命期
当一个请求到来之后,会被以连接的形式对待。
pre-proxy
这个阶段会在请求到达 Kong 的正式 worker 之前执行。主要做以下事情:
-
certificate
phase(每次 TLS 握手时执行,如果启用 KeepAlive,则有时可以跳过)-
使用一个 SNI(Server Name Indication)来选择一个证书,或者使用 Nginx 中配置的证书来处理请求
-
清理上下文(
ngx.ctx
),以免影响后续的阶段 -
执行插件的
certificate
钩子
-
-
rewrite
phase(每个 HTTP 连接执行)-
重写请求的 URI
-
不会执行 Router
-
不会清理上下文
-
执行插件的
rewrite
钩子
-
-
access
phase(每个 HTTP 连接执行)-
执行 Router
-
生成
X-Forwarded-*
头 -
执行 HTTPS 重定向
-
准备负载均衡器
-
收集相关的插件
-
执行负载均衡器
-
设置
Host
或者Authority
头 -
清理 hop-by-hop 头
-
将请求放入 buffer
-
执行插件的
access
钩子
-
-
preread
phase(每次 TCP/UDP 连接执行)-
执行 Router
-
准备负载均衡器
-
收集相关的插件
-
执行负载均衡器
-
执行插件的
preread
钩子
-
proxy-send
这个阶段,请求将离开 Kong Gateway 并前往上游服务。可以细分为如下阶段:
-
content
phase(每个连接执行)-
发送请求到上游。
-
为上游请求设置客户端证书
-
为 HTTP 请求设置 upstream 头
-
插件无法接触到这个阶段。在 C 语言编写的代理模块中执行。
-
-
balancer
pseudo-phase(每个连接可能执行多次)-
同上游处理 Keep-Alive
-
设置目标
-
在负载均衡器中执行。对于插件不可见。
当失败时:
-
报告 passive 健康状态
-
执行负载均衡(重试)
-
设置 Host 或者 Authority 头
-
同上游处理 Keep-Alive
-
设置目标
-
response
这个阶段,请求将从上游服务返回。可以细分为如下阶段:
-
header_filter phase(每个 HTTP 连接执行)
-
将响应头尽早发回给客户端
-
清除 Hop-by-Hop 头
-
报告上游状态给负载均衡器
-
设置负载均衡器的 Hash Cookie
-
添加 Kong headers
-
执行插件的
header_filter
钩子
-
-
body_filter phase(每个 HTTP 连接执行,可多次)
-
将响应体发回给客户端。可能被分成多个块(chunk)。
-
执行插件的
body_filter
钩子
-
-
response phase(每个 HTTP 连接执行)是
header_filter
和body_filter
的组合的替代品。-
激活 buffered 的响应
-
存储 buffered 的响应的状态,头,体到
ngx.ctx
-
设置响应状态,头,体
-
执行插件的
response
钩子
-
-
log phase(每个连接执行)
-
在响应已经发送给客户端之后执行
-
收集匿名统计数据
-
报告负载均衡器的状态
-
不能使用 Cosockets
-
执行插件的
log
钩子
-
-
handle_error phase(每个 HTTP 连接执行)
-
当请求处理过程中发生错误时执行,例如:
-
无法连接到上游
-
路由匹配失败
-
插件报错等
-
-
生成错误响应
-
对插件不可见
-
仍然会执行
header_filter
和body_filter
以及log
阶段
-