ARTICLE DETAIL

资讯详情

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

Envoy 非优雅 Drain 行为变更解读:`/drain_listeners` 现在会通知连接进入排空

Envoy 非优雅 Drain 行为变更解读:`/drain_listeners` 现在会通知连接进入排空 Envoy 非优雅 Drain 行为变更解读/drain_listeners现在会通知连接进入排空【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy导读本文深入解读 Envoy 管理接口/drain_listeners的一项关键行为变更不带graceful参数的非优雅 drain 不再仅仅是停止监听器listener而是会启动完整的 drain 序列并通知这些监听器所持有的连接“排空已经开始”。你将掌握变更前后的行为差异、--drain-strategy与graceful/skip_exit参数的正确组合用法以及如何通过运行时守卫runtime guard临时回退到旧行为并了解对应的源码实现与测试验证。一、背景Envoy 的 Drain排空机制在 Envoy 中drain 是指优雅地停止服务的过程先让已建立的连接有机会完成正在进行的请求连接级 drain 逻辑再停止监听器、拒绝新的连接。核心流程围绕两部分展开停止监听器stop listeners监听器停止后不再接受新连接。连接级 drain 通知告知已有连接 drain 已经开始连接随后依据配置的 drain 策略决定何时关闭。连接级 drain 逻辑由 drain_manager_impl.cc 中的DrainManager实现其中startDrainSequence()负责启动 drain 序列drainClose()供轮询方查询是否应关闭连接draining()判断当前是否处于排空状态参见 drain_manager_impl.h。drain 行为受两个服务端命令行选项控制定义于 source/server/options_impl.cc选项默认值含义--drain-time-s600drain 时长秒用于 hot restart 与 LDS 移除场景--drain-strategygradualdrain 序列行为取值gradual默认或immediate其中--drain-strategy的解析逻辑位于 options_impl.cc值为immediate时立即关闭连接值为gradual时逐步关闭传入其他值会抛出MalformedArgvException。在操作层面管理接口POST /drain_listeners是触发 drain 的主要入口其文档见 docs/root/operations/admin.rst。二、变更前非优雅 drain 只“停”不“排”在本次变更之前POST /drain_listeners不带graceful的行为存在明显短板监听器被立即停止不再接受新连接但监听器已经持有的连接从未被告知 drain 已经开始因此连接级 drain 逻辑对这些连接完全不生效——结果是“连接其实什么也没被排空”。架构文档 draining.rst 中对此也有印证默认情况下 Envoy 在关闭时会立即关闭监听器drain_listeners会使监听器被“直接停止而不进行任何优雅排空行为”立即停止接受新连接。与之相关的一个直接后果是参数组合校验由于非优雅 drain 什么都不做skip_exit跳过停止监听器在这个场景下就失去了意义因此服务端会以 HTTP 400 拒绝skip_exit与graceful缺一不可的组合。三、变更后非优雅 drain 同样触发完整排空本次 minor behavior change记录于 admin__non-graceful-drain-notifies-connections.rst后非优雅 drain 的行为与优雅 drain 对齐POST /drain_listeners不带graceful现在会启动一个 drain 序列并通知被覆盖监听器所持有的连接“drain 已经开始”而不再只是停止监听器连接级 drain 逻辑由--drain-strategy配置现在对非优雅 drain 同样生效与优雅 drain 完全一致graceful参数的作用被收窄为唯一决定监听器是否在 drain 周期内继续接受新连接graceful意味着先经历一段 drain 时长再停止监听器非优雅则是立即停止——两者在“如何排空已有连接”上不再有区别。skip_exit 语义变化skip_exit的语义也随之上调变更前skip_exit不带graceful会返回 HTTP 400变更后skip_exit可以单独使用含义是“排空连接但永不停止监听器”——这实际上就是gracefulskip_exit早已实现的行为因为 drain 周期只影响监听器何时停止与连接如何排空无关。四种组合的最终语义对比如下参数组合监听器行为连接排空无参数立即停止启动 drain 序列并通知连接?graceful等待 drain 周期后停止启动 drain 序列并通知连接?skip_exit不停止持续接受新连接启动 drain 序列并通知连接?gracefulskip_exit不停止持续接受新连接启动 drain 序列并通知连接四、源码级实现剖析核心处理逻辑位于 source/server/admin/listeners_handler.cc。请求处理时依次解析查询参数并执行分支参数解析与守卫检查L26-L43解析graceful与skip_exit查询参数若skip_exit存在、graceful不存在、且运行时守卫envoy.reloadable_features.non_graceful_drain_notifies_connections关闭则返回 400skip_exit requires graceful\n。守卫通过Runtime::runtimeFeatureEnabled()读取其注册位于 source/common/runtime/runtime_features.cc 的RUNTIME_GUARD(envoy_reloadable_features_non_graceful_drain_notifies_connections)。优雅 drain 分支L50-L75先通过drainManager().draining(direction)检测是否已在排空重复请求直接返回OK否则调用listenerManager().onServerDrainStart(direction, ConnectionDrainEvent{...})通知连接并调用startDrainSequence(direction, callback)启动 drain 序列——回调在 drain 时长结束后若未设置skip_exit执行stopListeners()。非优雅 drain 分支L76-L97在守卫开启时先调用onServerDrainStart(...)通知连接再调用startDrainSequence(direction, [](){})空回调因为监听器随后立即停止或按skip_exit保持运行最后按skip_exit决定是否执行stopListeners()。值得注意的细节非优雅分支中 “先通知再停止” 是有意为之——代码注释L78-L80说明这样可以保证在两个操作之间窗口期新接受的连接也能收到通知活跃监听器会把该事件重放给 drain 开始后才接受的连接。同时 drain 策略使用服务端全局默认值server_.options().drainStrategy()与优雅 drain 一致graceful只影响监听器停与不停。源码中还留有 TODOL35-L37一旦守卫被移除两个分支可以合并——届时所有 drain 都以相同方式排空连接graceful/skip_exit只决定监听器何时或是否停止。五、回退开关运行时守卫如行为变更不符合预期可通过运行时守卫临时恢复旧行为runtime: values: envoy.reloadable_features.non_graceful_drain_notifies_connections: false将其设为false后非优雅 drain 恢复为仅停止监听器、不通知连接且skip_exit不带graceful会再次返回 400参见 docs/root/operations/admin.rst 中的相关说明。需要提醒的是该守卫属于“可临时回退”的过渡机制后续版本中将被移除届时新行为将成为唯一语义。六、测试验证本次变更在 test/server/admin/admin_test.cc 中有三组针对性测试用例NonGracefulDrainNotifiesListenersL86-L107验证非优雅 drain 会立即停止监听器但依然通知连接 drain 已开始——正如测试注释所言“非优雅 drain 立即停止监听器但它们拥有的连接仍须被告知 drain 已开始否则这些连接根本不会被排空”。NonGracefulDrainSkipExitDoesNotStopListenersL113-L121验证skip_exit同样适用于非优雅 drain——连接被排空但监听器保持运行与gracefulskip_exit行为一致。NonGracefulDrainNotifyRuntimeGuardDisabledL124-L142通过TestScopedRuntime将守卫设为false断言stopListeners不被调用、请求返回Http::Code::BadRequest且响应体为skip_exit requires graceful\n——精确复现了旧行为。这三个用例共同构成了本次行为变更的回归防线。七、实践建议希望已有连接优雅收尾时无需再依赖graceful直接POST /drain_listeners即可触发连接级 drain配合--drain-strategygradual默认获得逐步排空效果。希望监听器持续接受新连接但排空存量连接如滚动发布期间保留入口使用POST /drain_listeners?skip_exit此前的 400 拒绝已解除。依赖轮询式 drain 判断的下游组件非优雅 drain 现在也会将 DrainManager 置为 draining 状态startDrainSequence空回调调用见 listeners_handler.cc因此通过DrainDecision::drainClose()轮询的消费方同样能感知到排空而不只是收到推送通知的连接。升级前评估如果线上对“非优雅 drain 期间连接级 drain 逻辑完全不运行”存在隐式依赖请在升级窗口内评估并考虑临时设置运行时守卫为false以平滑过渡。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表