- 请求的生命周期:pingora-proxy 的阶段和过滤器
- 介绍
- 一个代理 HTTP 请求的生命周期
- Pingora-proxy 的阶段和过滤器
- 通用过滤器使用指南
early_request_filter()
request_filter()
request_body_filter()
proxy_upstream_filter()
upstream_peer()
connected_to_upstream()
fail_to_connect()
upstream_request_filter()
upstream_response_filter()/upstream_response_body_filter()/upstream_response_trailer_filter()
response_filter()/response_body_filter()/response_trailer_filter()
error_while_proxy()
fail_to_proxy()
logging()
request_summary()
suppress_error_log()
- 缓存过滤器
请求的生命周期:pingora-proxy 的阶段和过滤器
介绍
Pingora-proxy HTTP 代理框架支持高度可编程的代理行为。这通过允许用户在请求生命周期的不同阶段插入自定义逻辑来实现。
一个代理 HTTP 请求的生命周期
- 一个代理 HTTP 请求的生命周期始于代理从 下游(即客户端)读取请求头。
- 然后,代理连接到 上游(即远程服务器)。如果之前已经建立了 可复用连接,此步骤将被跳过。
- 代理随后将请求头发送到上游。
- 一旦请求头发送完毕,代理进入双工模式,同时代理:
a. 将上游响应(包括头部和正文)发送到下游,
b. 将下游请求正文(如果有)发送到上游。 - 当整个请求/响应完成时,请求的生命周期结束。所有资源将被释放,下游连接和上游连接将被回收以供重用(如适用)。
Pingora-proxy 的阶段和过滤器
Pingora-proxy 允许用户在请求的生命周期中插入任意逻辑。
graph TD;
start("new request")-->early_request_filter;
early_request_filter-->request_filter;
request_filter-->upstream_peer;
upstream_peer-->Connect{{IO: connect to upstream}};
Connect--connection success-->connected_to_upstream;
Connect--connection failure-->fail_to_connect;
connected_to_upstream-->upstream_request_filter;
upstream_request_filter --> request_body_filter;
request_body_filter --> SendReq{{IO: send request to upstream}};
SendReq-->RecvResp{{IO: read response from upstream}};
RecvResp-->upstream_response_filter-->response_filter-->upstream_response_body_filter-->response_body_filter-->logging-->endreq("request done");
fail_to_connect --can retry-->upstream_peer;
fail_to_connect --can't retry-->fail_to_proxy--send error response-->logging;
RecvResp--failure-->IOFailure;
SendReq--failure-->IOFailure;
error_while_proxy--can retry-->upstream_peer;
error_while_proxy--can't retry-->fail_to_proxy;
request_filter --send response-->logging;
Error>any response filter error]-->error_while_proxy;
IOFailure>IO error]-->error_while_proxy;
通用过滤器使用指南
- 大多数过滤器返回一个
pingora_error::Result<_>
。当返回值为Result::Err
时,将调用fail_to_proxy()
并终止请求。 - 大多数过滤器是异步函数,允许在过滤器中执行其他异步操作(例如 IO)。
- 每个请求可以定义一个
CTX
对象,用于在同一请求的过滤器之间共享状态。所有过滤器都可以对该对象进行可变访问。 - 大多数过滤器是可选的。
- 同时存在
upstream_response_*_filter()
和response_*_filter()
的原因是为了 HTTP 缓存集成(仍在进行中)。
early_request_filter()
这是每个请求的第一个阶段。
此函数类似于 request_filter()
,但执行时间早于任何其他逻辑,包括下游模块逻辑。此函数的主要目的是为模块行为提供更细粒度的控制。
request_filter()
此阶段通常用于验证请求输入、限流以及初始化上下文。
request_body_filter()
此阶段在响应正文准备好发送到上游之后触发。每次接收到一部分请求正文时都会调用它。
proxy_upstream_filter()
此阶段决定是否继续访问上游以获取响应。如果中断,则默认返回 502,但可以实现不同的响应。
此阶段返回一个布尔值,以决定是否继续访问上游或返回错误。
upstream_peer()
此阶段决定连接到哪个上游(例如,通过 DNS 查找和哈希/轮询)以及如何连接。
此阶段返回一个定义要连接上游的 Peer
。实现此阶段是 必须的。
connected_to_upstream()
此阶段在成功连接到上游时执行。
此阶段通常用于记录目的。此阶段报告的连接信息包括 RTT 和上游 TLS 密码套件等。
fail_to_connect()
connected_to_upstream()
的对应阶段。当连接上游时遇到错误时,将调用此阶段。
在此阶段,用户可以在 Sentry/Prometheus/错误日志中报告错误。用户还可以决定错误是否可重试。
如果错误可重试,将再次调用 upstream_peer()
,在这种情况下,用户可以决定是否重试相同的上游或切换到次要上游。
如果错误不可重试,请求将结束。
upstream_request_filter()
此阶段用于在发送到上游之前修改请求。
upstream_response_filter()/upstream_response_body_filter()/upstream_response_trailer_filter()
此阶段在接收到上游响应头/正文/尾部之后触发。
此阶段用于在发送到下游之前修改或处理响应头、正文或尾部。请注意,此阶段在 HTTP 缓存之前调用,因此在此处所做的任何更改都将影响存储在 HTTP 缓存中的响应。
response_filter()/response_body_filter()/response_trailer_filter()
此阶段在响应头/正文/尾部准备好发送到下游之后触发。
此阶段用于在发送到下游之前修改它们。
error_while_proxy()
此阶段在上游代理错误期间触发,即在连接建立之后。
此阶段可能决定是否重试请求(如果连接已复用且 HTTP 方法是幂等的)。
fail_to_proxy()
此阶段在上述任何阶段期间遇到错误时调用。
此阶段通常用于错误日志记录以及向下游报告错误。
logging()
这是在请求完成(或出错)之后且在释放其任何资源之前运行的最后一个阶段。每个请求最终都将进入此阶段。
此阶段通常用于日志记录和请求后清理。
request_summary()
这不是一个阶段,而是一个常用的回调函数。
每个到达 fail_to_proxy()
的错误都会自动记录在错误日志中。当记录错误时,将调用 request_summary()
来转储有关请求的信息。
此回调返回一个字符串,允许用户自定义在错误日志中转储哪些信息以帮助跟踪和调试故障。
suppress_error_log()
这也不是一个阶段,而是另一个回调函数。
fail_to_proxy()
错误会自动记录在错误日志中,但用户可能并不关心每个错误。例如,如果客户端提前断开连接,下游错误会记录下来,但如果用户主要关注上游问题,这些错误可能会显得嘈杂。此回调可以检查错误并返回 true 或 false。如果返回 true,则不会将错误写入日志。
缓存过滤器
有待补充