Kong:一个请求的生命期

Kong 扮演的角色

作为一个 API 网关,Kong 既可以作为负载均衡器,也可以作为反向代理、认证中心等等。可以看作一个基于 Lua 的超级加强版的 Nginx

alt

alt

Kong 的每个 Node 是多进程的。有一个 master 进程,多个 worker 进程。每个进程又拥有多个线程。就像下图的黄色圈圈。

alt

作为 worker 的线程,各自又会管理很多个连接。这些连接可以如下分类:

  • 可用连接:这些连接是空闲的,可以被 worker 使用

  • 未阻塞连接:当一个新请求到来时,worker 会从可用连接中取出一个,然后将其放入未阻塞连接中。当请求处理完毕后,worker 会将连接放回可用连接中

  • 正在处理的连接:由于采用多路复用模型,实际上正在处理的连接只有一个。未阻塞连接会一个接一个地被处理

  • 阻塞连接:当请求处理过程中,需要等待外部服务的响应时,连接会被放入阻塞连接中。当外部服务响应后,连接会被放回未阻塞连接中

  • 保持存活(keepalive)的连接:当请求处理完毕后,worker 会判断是否需要保持连接。如果需要,连接会被放入保持存活的连接中。当下一个请求到来时,worker 会从保持存活的连接中取出一个,然后将其放入未阻塞连接中

Keep-Alive 是用于复用连接的方式。由于 TLS 需要进行 SSL 握手,这个过程的开销比较大。所以,如果能够复用连接,就可以避免这个开销。

Phases

每个 Kong Node 都会经历多个阶段。

Init

这个阶段只会在 Node 启动时执行,且只在 Master 进程执行。主要做以下事情:

  1. 创建 Lua VM

  2. 加载配置文件

  3. 检查迁移

  4. 加载插件

  5. 初始化数据库 / Dbless / Hybird

  6. 初始化 DNS

  7. 初始化 PDK

  8. 初始化证书

  9. 初始化路由和插件迭代器

Init Worker

之后进入 init_worker 阶段。这个阶段会在每个 Worker 进程中执行。主要做以下事情:

  1. 复制主进程的 Lua VM 因此,每个 worker 进程都有自己的 Lua VM,且各种变量的初始值和主进程一致 并且,所有的修改都是局部的

  2. 初始化随机种子

  3. 初始化并订阅 cluster events

  4. 初始化并订阅 worker events

  5. 初始化并预热缓存

  6. 初始化负载均衡器和健康检查

  7. 初始化匿名报告

  8. 启动外部插件服务器

  9. 让每个插件执行 init_worker 钩子

请求生命期

当一个请求到来之后,会被以连接的形式对待。

pre-proxy

这个阶段会在请求到达 Kong 的正式 worker 之前执行。主要做以下事情:

  1. certificate phase(每次 TLS 握手时执行,如果启用 KeepAlive,则有时可以跳过)

    1. 使用一个 SNI(Server Name Indication)来选择一个证书,或者使用 Nginx 中配置的证书来处理请求

    2. 清理上下文(ngx.ctx),以免影响后续的阶段

    3. 执行插件的 certificate 钩子

  2. rewrite phase(每个 HTTP 连接执行)

    1. 重写请求的 URI

    2. 不会执行 Router

    3. 不会清理上下文

    4. 执行插件的 rewrite 钩子

  3. access phase(每个 HTTP 连接执行)

    1. 执行 Router

    2. 生成 X-Forwarded-*

    3. 执行 HTTPS 重定向

    4. 准备负载均衡器

    5. 收集相关的插件

    6. 执行负载均衡器

    7. 设置 Host 或者 Authority

    8. 清理 hop-by-hop 头

    9. 将请求放入 buffer

    10. 执行插件的 access 钩子

  4. preread phase(每次 TCP/UDP 连接执行)

    1. 执行 Router

    2. 准备负载均衡器

    3. 收集相关的插件

    4. 执行负载均衡器

    5. 执行插件的 preread 钩子

proxy-send

这个阶段,请求将离开 Kong Gateway 并前往上游服务。可以细分为如下阶段:

  1. content phase(每个连接执行)

    1. 发送请求到上游。

    2. 为上游请求设置客户端证书

    3. 为 HTTP 请求设置 upstream 头

    4. 插件无法接触到这个阶段。在 C 语言编写的代理模块中执行。

  2. balancer pseudo-phase(每个连接可能执行多次)

    1. 同上游处理 Keep-Alive

    2. 设置目标

    3. 在负载均衡器中执行。对于插件不可见。

    当失败时:

    1. 报告 passive 健康状态

    2. 执行负载均衡(重试)

    3. 设置 Host 或者 Authority 头

    4. 同上游处理 Keep-Alive

    5. 设置目标

response

这个阶段,请求将从上游服务返回。可以细分为如下阶段:

  1. header_filter phase(每个 HTTP 连接执行)

    1. 将响应头尽早发回给客户端

    2. 清除 Hop-by-Hop 头

    3. 报告上游状态给负载均衡器

    4. 设置负载均衡器的 Hash Cookie

    5. 添加 Kong headers

    6. 执行插件的 header_filter 钩子

  2. body_filter phase(每个 HTTP 连接执行,可多次)

    1. 将响应体发回给客户端。可能被分成多个块(chunk)。

    2. 执行插件的 body_filter 钩子

  3. response phase(每个 HTTP 连接执行)是 header_filterbody_filter 的组合的替代品。

    1. 激活 buffered 的响应

    2. 存储 buffered 的响应的状态,头,体到 ngx.ctx

    3. 设置响应状态,头,体

    4. 执行插件的 response 钩子

  4. log phase(每个连接执行)

    1. 在响应已经发送给客户端之后执行

    2. 收集匿名统计数据

    3. 报告负载均衡器的状态

    4. 不能使用 Cosockets

    5. 执行插件的 log 钩子

  5. handle_error phase(每个 HTTP 连接执行)

    1. 当请求处理过程中发生错误时执行,例如:

      1. 无法连接到上游

      2. 路由匹配失败

      3. 插件报错等

    2. 生成错误响应

    3. 对插件不可见

    4. 仍然会执行 header_filterbody_filter 以及 log 阶段

总览

alt

参考资料

https://www.youtube.com/watch?v=1sBui6Z0IDc

https://konghq.com/blog/api-gateway-request