Fluent Bit 内置 nghttp2:nghttp2_session_terminate_session2() 主动终止 HTTP/2 连接的原理与实现解析
Fluent Bit 内置 nghttp2nghttp2_session_terminate_session2() 主动终止 HTTP/2 连接的原理与实现解析【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit本文围绕 Fluent Bit 仓库中随库 vendored 的 nghttp2 1.65.0 的 API 文档nghttp2_session_terminate_session2.rst展开。该函数是 HTTP/2 会话的受控终止入口调用方可以精确指定 GOAWAY 帧中的last_stream_id从而告知对端哪些流仍可处理、哪些必须放弃。读完后你将掌握该函数的签名语义、参数约束奇偶性、单调不增、返回值与错误码并能结合 Fluent Bit 仓库中的实际源码理解它内部如何构造 GOAWAY 帧、如何冻结会话状态、以及它对后续帧发送的影响。1. API 概览函数签名与文档定义API 文档位于 lib/nghttp2-1.65.0/doc/nghttp2_session_terminate_session2.rst其 Synopsis 部分给出的原型为#include nghttp2/nghttp2.h int nghttp2_session_terminate_session2(nghttp2_session *session, int32_t last_stream_id, uint32_t error_code);文档对该函数的描述可以归纳为三点核心语义目的向会话发出信号表示连接应当被终止Signals the session so that the connection should be terminated。与nghttp2_session_terminate_session()的区别行为与后者一致但允许应用层显式指定last_stream_id实现对流级的细粒度控制。单调性约束HTTP/2 规范不允许last_stream_id增大。因此实际作为last_stream_id发出的值是传入值与此前已向对端发送过的last_stream_id两者中的较小值。关于参数last_stream_id本身文档明确了身份约束它是对端的流 ID或者为 0。因此若session被初始化为clientlast_stream_id必须是偶数或 0若session被初始化为serverlast_stream_id必须是奇数或 0。返回值语义与文档一致成功返回0失败返回以下负数错误码之一错误码含义NGHTTP2_ERR_NOMEM内存不足Out of memoryNGHTTP2_ERR_INVALID_ARGUMENT传入的last_stream_id非法在仓库中该函数的头文件声明位于 nghttp2.h文档注释与上述.rst文件内容一一对应NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session, int32_t last_stream_id, uint32_t error_code);2. 源码实现调用链与 GOAWAY 帧构造2.1 入口nghttp2_session_terminate_session2只是薄封装在 fluent-bit 仓库中的 nghttp2_session.c 中实现仅有两行int nghttp2_session_terminate_session2(nghttp2_session *session, int32_t last_stream_id, uint32_t error_code) { return session_terminate_session(session, last_stream_id, error_code, NULL); }它与相邻的三个姊妹函数nghttp2_session_terminate_session、nghttp2_session_terminate_session_with_reason及无 reason 版本共用同一个静态函数session_terminate_session()区别只在于last_stream_id的来源不带2后缀的版本使用session-last_proc_stream_id会话记录的最后处理流 ID而terminate_session2把决定权交给调用者。2.2 核心逻辑静态函数session_terminate_session静态实现位于 nghttp2_session.c 第 223-249 行执行顺序为幂等检查若session-goaway_flags已含NGHTTP2_GOAWAY_TERM_ON_SEND标志直接返回 0——终止 GOAWAY 只提交一次即可重复调用是安全的忽略所有入站帧将session-iframe.state置为NGHTTP2_IB_IGN_ALL。源码注释写明原因Ignore all incoming frames because we are going to tear down the session.既然要拆除会话就忽略所有传入帧提交 GOAWAY调用nghttp2_session_add_goaway(session, last_stream_id, error_code, debug_data, debug_datalen, NGHTTP2_GOAWAY_AUX_TERM_ON_SEND)把终止意图放入出站帧队列打上终止标志session-goaway_flags | NGHTTP2_GOAWAY_TERM_ON_SEND;。2.3 参数校验last_stream_id为什么必须是对端的流 IDnghttp2_session_add_goawaynghttp2_session.c 第 6882-6940 行首先做身份校验if (nghttp2_session_is_my_stream_id(session, last_stream_id)) { return NGHTTP2_ERR_INVALID_ARGUMENT; }即这是本端流 ID时直接返回NGHTTP2_ERR_INVALID_ARGUMENT。而nghttp2_session_is_my_stream_id第 271-282 行的规则是stream_id 0永远不属于本端奇偶性与角色互补——server 端的本端流是偶数 IDclient 端的本端流是奇数 ID。这正好解释了文档中的约束client 会话的last_stream_id必须是偶数或 0server 会话必须是奇数或 0传反了就会落入NGHTTP2_ERR_INVALID_ARGUMENT分支。2.4 单调不增nghttp2_min_int32钳制紧接着nghttp2_session_add_goaway实现了文档所述的取最小值语义第 6919-6922 行/* last_stream_id must not be increased from the value previously sent */ last_stream_id nghttp2_min_int32(last_stream_id, session-local_last_stream_id);session-local_last_stream_id在 GOAWAY 帧真正被打包写出时更新第 2185-2191 行case NGHTTP2_GOAWAY: ... session-local_last_stream_id frame-goaway.last_stream_id;。因此无论应用传入多大的值实际写上线的last_stream_id只减不增严格符合 HTTP/2 规范中GOAWAY 的 last_stream_id 不得递增的要求。此外add_goaway成功后还会置位NGHTTP2_GOAWAY_SUBMITTED表示一条 GOAWAY 已经在出站队列中等待发送。3. 调用之后的会话行为终止状态如何生效terminate_session2成功后会话进入关闭中状态从源码结构看NGHTTP2_GOAWAY_TERM_ON_SEND标志会影响以下几类行为均在 nghttp2_session.c 中会话是否处于关闭态session_is_closing()第 1372-1376 行只要看到NGHTTP2_GOAWAY_TERM_ON_SEND即判定为 closing此时session_predicate_for_stream_send()会对所有流发送返回NGHTTP2_ERR_SESSION_CLOSING不再接收新流session_allow_incoming_new_stream()第 1364-1367 行要求NGHTTP2_GOAWAY_TERM_ON_SEND与NGHTTP2_GOAWAY_SENT均不存在才允许对端发起新流客户端不再发起新请求session_predicate_request_headers_send()第 1424-1437 行在会话关闭时返回NGHTTP2_ERR_START_STREAM_NOT_ALLOWEDPING 也被拦截打包出站 PING 时第 2178-2182 行注释明确 PING frame is allowed to be sent unless termination GOAWAY is sent即终止 GOAWAY 提交后 PING 发送直接失败。需要区分的是这只是信号而非立即断开。函数注释与实现都表明它是Signals the session so that the connection should be terminated——真正的断开由应用层根据nghttp2_session_want_read()/nghttp2_session_want_write()等到帧排空后自行关闭底层传输这也解释了session_is_closing()中want_read 与 want_write 均为 0的另一个关闭条件。4. 在 Fluent Bit 中的位置vendored 依赖与 HTTP/2 集成Fluent Bit 将 nghttp2 1.65.0 完整 vendored 在 lib/nghttp2-1.65.0/ 下用于其 HTTP/2 能力。仓库内两处直接与 nghttp2 会话交互的代码HTTP/2 客户端src/flb_http_client_http2.c 中通过nghttp2_submit_settings()第 518 行、nghttp2_submit_request()第 777 行发起请求回调失败时返回NGHTTP2_ERR_CALLBACK_FAILUREHTTP/2 服务端src/http_server/flb_http_server_http2.c 中同样以NGHTTP2_ERR_CALLBACK_FAILURE作为回调错误约定第 481、811 行。从源码结构看Fluent Bit 自身并未直接调用nghttp2_session_terminate_session2但理解该 API 对把握 Fluent Bit 内置 HTTP/2 客户端/服务的连接拆除行为至关重要任何经由 nghttp2 发出的 GOAWAY 终止信号都遵循本文所述的参数校验、单调钳制与状态机语义。若你基于 Fluent Bit 的 HTTP/2 模块做二次开发例如通过fluent-bit.h公共 API 定制下游连接terminate_session2就是带流边界声明的连接终止这一需求对应的底层原语。5. 使用要点与错误排查清单结合文档与源码调用nghttp2_session_terminate_session2时的实践要点要点依据last_stream_id传对端流 ID 或 0client 端传偶数/0server 端传奇数/0文档约束 nghttp2_session_is_my_stream_id校验传错即NGHTTP2_ERR_INVALID_ARGUMENT传入值过大会被静默钳制为与历史 GOAWAY 的最小值不会报错nghttp2_min_int32钳制逻辑重复调用安全已提交则直接返回 0NGHTTP2_GOAWAY_TERM_ON_SEND幂等检查成功后会话进入关闭态不再收新流、不再发新请求、PING 被拦截session_is_closing、session_allow_incoming_new_stream、PING 打包分支成功仅表示 GOAWAY 已排队实际断开仍需应用层驱动读写直至排空Signals the session... 语义 want_read/want_write关闭判定常见排查若调用返回负值优先核对last_stream_id的奇偶性是否与端角色匹配NGHTTP2_ERR_INVALID_ARGUMENT返回NGHTTP2_ERR_NOMEM则说明出站项或 opaque data 分配失败。6. 小结nghttp2_session_terminate_session2是 nghttp2 提供的应用层指定流边界的会话终止 API它在nghttp2_session_terminate_session的基础上允许显式指定last_stream_id并内建了身份校验对端流 ID 或 0、单调不增钳制与历史 GOAWAY 取最小值与幂等保护。在 Fluent Bit 仓库中该 API 的文档、声明与实现分别位于 doc/nghttp2_session_terminate_session2.rst、lib/includes/nghttp2/nghttp2.h 与 lib/nghttp2_session.c三者内容相互印证为 HTTP/2 连接的优雅/受控终止提供了完整可追溯的实现证据。【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考