十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Envoy HTTP Filter Manager 修复:continue 后 addDecodedData/addEncodedData 丢失请求体数据块问题

Envoy HTTP Filter Manager 修复:continue 后 addDecodedData/addEncodedData 丢失请求体数据块问题 Envoy HTTP Filter Manager 修复continue 后 addDecodedData/addEncodedData 丢失请求体数据块问题【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy导读本文深入解析 Envoy 在 HTTP Filter Manager 中发现并修复的一类请求/响应体数据丢失缺陷当过滤器在 headers 阶段停止迭代例如启用了allow_on_headers_stop_iteration的 wasm 过滤器随后异步恢复并在后续某个 body 帧上通过addDecodedData()/addEncodedData()将数据搬入 filter-manager 缓冲区后返回Continue时空帧会被继续向下游转发、已缓冲的字节被静默丢弃。文章基于仓库中的修复说明changelogs/current/bug_fixes/http__filter-manager-lost-body-chunk-on-continue.rst、核心实现source/common/http/filter_manager.cc与回归测试test/common/http/filter_manager_test.cc讲清缺陷成因、修复判定条件、运行时开关以及如何在实践中规避与验证。一、缺陷背景过滤器停止迭代与缓冲机制的碰撞在 Envoy 的 HTTP 过滤器链中每个过滤器通过返回各类FilterHeadersStatus/FilterDataStatus状态码来控制请求/响应在链中的流转节奏。正常情况下数据帧逐过滤器传递每个过滤器处理完当前帧后返回Continue放行。问题出现在一种组合场景下headers 阶段停止迭代某个过滤器在decodeHeaders/encodeHeaders中返回FilterHeadersStatus::StopIteration等待异步操作如 wasm 扩展的外部调用、ext_proc 的外部处理服务完成后再恢复。异步恢复后继续异步回调完成后过滤器调用continueDecoding()/continueEncoding()恢复链的流转。后续 body 帧上做“搬移 放行”在恢复后到达的某个 body 帧中过滤器调用addDecodedData()/addEncodedData()把该帧内容移入 filter-manager 的缓冲区然后返回FilterDataStatus::Continue。此时 filter-manager 内部的迭代状态已是Continue因为该过滤器此前已异步恢复过一次commonHandleAfterDataCallback()会把已经被搬空的帧继续向下游转发而刚刚通过addDecodedData()缓冲的数据却不会随该帧下发——这些字节被静默丢弃。从源码结构看这一缺陷的根因位于 source/common/http/filter_manager.cc 的commonHandleAfterDataCallback()它依据“回调返回Continue且迭代状态已非停止”来放行当前provided_data但没有意识到该数据帧的内容已经在回调内部被搬移到了bufferedData()导致放行的是空壳帧。触发链路的典型场景wasm ext_procchangelog 明确指出两个典型触发者wasm 过滤器其allow_on_headers_stop_iteration配置项映射到单次迭代停止即IterationState::StopSingleIteration而非StopAllIterationAndWatermark。这类过滤器在 headers 上停住、缓冲一个 body 块、异步恢复随后在下一个块上执行上述“搬移 Continue”操作时即命中缺陷。ext_proc 过滤器FULL_DUPLEX_STREAMED模式该模式下 ext_proc 对每个请求体字节流式透传而不重新缓冲。缺陷修复前若它与上述 wasm 过滤器链式组合流式大请求体会出现恰好多一个数据块丢失的现象——例如一个 16 KiB 的块被丢弃而消息计数不变因此极难被察觉。二、修复原理窄化判定条件转发已缓冲数据修复位于 source/common/http/filter_manager.cc 的commonHandleAfterDataCallback()。当过滤器返回FilterDataStatus::Continue且迭代状态已是继续态时新增如下判定逻辑if (parent_.state_.filter_added_data_in_data_callback_ provided_data_nonempty_before_callback provided_data.length() 0 bufferedData() bufferedData().get() ! provided_data bufferedData()-length() 0 Runtime::runtimeFeatureEnabled( envoy.reloadable_features.filter_manager_forward_added_data_on_continue)) { provided_data.move(*bufferedData()); }命中条件可归纳为四个必要检查其设计意图是让修复保持“窄”检查项含义目的filter_added_data_in_data_callback_本回调执行期间过滤器确实调用了addDecodedData()/addEncodedData()排除未主动搬移数据的普通透传路径provided_data_nonempty_before_callback provided_data.length() 0回调前帧非空、回调后帧被搬空精确识别“内容被移入缓冲”的签名bufferedData()存在且bufferedData().get() ! provided_data、长度 0缓冲区内确有刚搬入的数据且不是当前帧自身确保转发的是真正新增的缓冲内容运行时开关filter_manager_forward_added_data_on_continue开启行为变更受 reloadable feature 控制允许用户一键回退旧行为状态标记的来源filter_added_data_in_data_callback_标志位在addDecodedData()与addEncodedData()中设置。以解码路径为例source/common/http/filter_manager.ccif (state_.filter_call_state_ FilterCallState::DecodeData) { state_.filter_added_data_in_data_callback_ true; }即只有过滤器在自身的decodeData()回调执行期间调用addDecodedData()时才会置位。该标志在每次进入decodeData/encodeData迭代时被重置见 filter_manager.cc 与 filter_manager.cc编码路径addEncodedData()中的对称逻辑见 filter_manager.cc。为什么必须窄化不误伤其他合法路径源码注释filter_manager.cc明确列出了不匹配此修复、仍走原有路径的几种情况追加独立缓冲区的过滤器如 StopAll 测试过滤器包括在零长度end_stream帧上的场景它们不把当前帧搬空不满足provided_data.length() 0。未调用addDecodedData()就清空帧的过滤器如内部自行缓冲的压缩过滤器 compressor不满足filter_added_data_in_data_callback_交由既有路径处理。这种“非空变空 回调内调用过 addData 缓冲区非空”的组合签名将修复范围严格限制在 changelog 描述的数据丢失场景内。三、运行时开关如何回退与启用该行为变更是可回退的受 reloadable feature 运行时守卫控制默认开启新行为生效Continue时转发刚缓冲的数据而非空帧。回退旧行为将运行时守卫设置为falseruntime: overrides: envoy.reloadable_features.filter_manager_forward_added_data_on_continue: false该守卫在 source/common/runtime/runtime_features.cc 中注册RUNTIME_GUARD(envoy_reloadable_features_filter_manager_forward_added_data_on_continue);与守卫同名的环境变量ENVOY_RELOADABLE_FEATURES_FILTER_MANAGER_FORWARD_ADDED_DATA_ON_CONTINUE也可用于在启动时控制Envoy 对 reloadable features 的统一机制runtime 配置优先于环境变量。实际排查问题时建议优先通过runtime.overrides精确作用域控制便于灰度验证后再全量放开。四、回归测试同一测试用例验证“丢与不丢”仓库为该缺陷提供了可复现的回归测试位于 test/common/http/filter_manager_test.cc。测试通过forward_data参数切换运行时守卫在同一场景下同时验证缺陷存在与修复生效两种行为void FilterManagerTest::runAddDecodedDataOnContinueTest(bool forward_data) { TestScopedRuntime scoped_runtime; scoped_runtime.mergeValues( {{envoy.reloadable_features.filter_manager_forward_added_data_on_continue, forward_data ? true : false}}); // ... }测试场景设计与 changelog 描述一一对应filter_1 模拟 wasm 过滤器decodeHeaders返回FilterHeadersStatus::StopIteration块 A 到达时返回FilterDataStatus::StopIterationAndBuffer异步完成后续传块 B 到达时调用filter_1-callbacks_-addDecodedData(data, false)后返回FilterDataStatus::Continue——精确复现缺陷签名。filter_2 模拟FULL_DUPLEX_STREAMED的 ext_proc 过滤器将每个收到的请求体字节累加后直接data.drain()丢弃流式透传不重新缓冲。关键断言filter_manager_test.ccif (forward_data) { EXPECT_EQ(AAAABBBBCCCC, filter_2_received); } else { EXPECT_EQ(AAAACCCC, filter_2_received); }守卫开启修复生效三个块全部到达 filter_2顺序完整。守卫关闭复现旧缺陷块 B 被静默丢弃filter_2 只见 “AAAACCCC”且消息计数未变——这正是流式大请求体上“悄无声息丢一块”的现场还原。两个公开测试用例分别覆盖两种状态TEST_F(FilterManagerTest, DecodeDataFrameLostAfterContinueWithoutGuard) { runAddDecodedDataOnContinueTest(/*forward_data*/false); } TEST_F(FilterManagerTest, DecodeDataFrameNotLostAfterContinueWithAddDecodedData) { runAddDecodedDataOnContinueTest(/*forward_data*/true); }五、影响范围与排查建议受影响的流量形态请求方向与响应方向均受影响修复同时覆盖addDecodedData()请求/解码路径与addEncodedData()响应/编码路径两条路径在commonHandleAfterDataCallback()中共用同一修复逻辑。大流量流式传输缺陷只发生在后续帧被搬移后继续的场景且每丢失一个块仅损失其字节、不改变消息计数因此在高吞吐流式请求体如大文件上传中表现为“偶发数据不完整”常规协议层校验难以发现。多过滤器链式组合单一过滤器在 headers 停住 body 搬移本身即构成风险与FULL_DUPLEX_STREAMED模式的 ext_proc 串联时最易暴露changelog 给出的 16 KiB 单块丢失案例即为该组合。升级与验证建议确认版本仅当使用的 Envoy 构建包含 filter_manager.cc 中的修复逻辑即存在filter_manager_forward_added_data_on_continue守卫时新行为才生效。灰度验证若在生产环境观察到与该缺陷描述吻合的数据不完整现象可先保持守卫默认开启观察若担心行为变更影响既有依赖“空帧语义”的自定义过滤器可临时将该守卫设为false回退并通过runtime.overrides控制影响面。组合过滤器自查排查启用了allow_on_headers_stop_iteration的 wasm 过滤器、以及自定义实现中“在 data 回调里先addDecodedData()/addEncodedData()再返回Continue”的过滤器——这正是触发本缺陷的标准签名。六、小结本缺陷的修复体现了 Envoy HTTP Filter Manager 在缓冲语义上的精细化处理区分“过滤器把帧内容搬入自己的缓冲区”与“搬入 filter-manager 缓冲区”两种行为避免空帧下游放行导致的数据静默丢失。修复通过四个窄化条件精准命中问题签名并以可回退的 runtime 守卫保护行为变更配合一正一反的双向回归测试为同类过滤器组合wasm ext_proc 流式链路提供了可验证、可回退的完整解决方案。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表