资讯动态

Envoy 看门狗 backtrace_action 改用 SIGUSR2:信号机制解析与部署影响

发布时间:2026/9/12 4:02:52 来源:尧图企业网站定制
Envoy 看门狗 backtrace_action 改用 SIGUSR2信号机制解析与部署影响【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy导读本文基于 Envoy 官方变更记录changelogs/current/minor_behavior_changes/watchdog__backtrace-action-uses-sigusr2.rst深入解析envoy.watchdog.backtrace_action扩展的信号采集机制变更配置该动作后Envoy 现在会安装进程级SIGUSR2信号处理器并通过向卡住的线程发送SIGUSR2来采集其堆栈回溯。读完本文你将掌握 backtrace_action 的触发条件、SIGUSR2信号的完整生命周期槽位状态机、cooldown_duration等关键配置参数以及该变更对依赖SIGUSR2做其他用途的部署带来的兼容性影响。一、变更内容概述从信号到 backtrace 的完整闭环该变更记录的核心内容可以用一句话概括配置envoy.watchdog.backtrace_action后Envoy 会安装一个进程级的SIGUSR2信号处理器并向看门狗Watchdog判定为卡住stuck的线程发送SIGUSR2信号以便在信号处理器上下文中捕获这些线程的堆栈回溯backtrace。该变更同时给出了明确的部署警示依赖SIGUSR2做其他用途的部署应避免启用此动作。这意味着SIGUSR2从用户自定义信号变为 backtrace_action 的功能性占用信号。凡是已经在生产环境中用SIGUSR2做进程内日志滚动、状态导出、自定义脚本触发等用途的运维方案都需要在启用该扩展前重新评估。在 Envoy 源码中这一机制由source/extensions/watchdog/backtrace_action/backtrace_action.cc与backtrace_action.h实现配合source/common/signal/non_fatal_signal_handler.cc提供的非致命信号处理器注册框架以及source/common/thread/signal_thread.h提供的线程定向信号发送能力共同完成。二、backtrace_action 是什么看门狗动作体系中的卡死诊断器envoy.watchdog.backtrace_action是 Envoy GuardDog看门狗框架下的一个动作扩展GuardDogAction。看门狗会持续监控 Envoy 各线程的活跃状态要求每个线程定期签到check-in当某个线程长时间未签到、被判定为卡死stuck时看门狗会触发注册的动作。backtrace_action 的动作就是对被判定卡死的线程发送信号把它的调用栈回溯记录到日志中帮助开发者定位死锁、阻塞或忙循环等导致线程停滞的根因。在源码层面BacktraceAction类实现Server::Configuration::GuardDogAction接口run(...)方法接收看门狗事件、线程签到对thread_last_checkin_pairs以及当前时间是动作的入口见 backtrace_action.cc工厂类BacktraceActionFactory通过REGISTER_FACTORY静态注册扩展名为envoy.watchdog.backtrace_action见 config.cc 与 config.h。三、SIGUSR2 信号的注册与安装进程级信号处理器3.1 首次实例化时安装全局处理器信号处理器不是随每个配置实例重复安装的。backtrace_action.h中定义了两个静态原子变量来跟踪全局注册状态static std::atomicint instance_count_; // 实例计数 static std::atomicbool signal_handler_registered_; // 处理器是否已注册在构造函数中只有当第一个BacktraceAction实例被创建instance_count_从 0 变为 1时才会调用NonFatalSignalHandler::registerNonFatalSignalHandler(onNonFatalSignal)注册信号处理回调见 backtrace_action.cc而析构时只有当最后一个实例销毁时才会调用removeNonFatalSignalHandler移除处理器见 backtrace_action.cc。这一首个实例注册、末个实例注销的引用计数设计保证了多配置、多实例场景下信号处理器恰好只安装一次避免重复安装或提前卸载导致信号处理失效。3.2 非致命信号处理器注册框架底层框架位于 source/common/signal/non_fatal_signal_handler.h。该框架的核心约束是注册的回调必须 async-signal-safe异步信号安全因为回调会在真正的信号处理器上下文中执行。框架接口如下using NonFatalSignalCallback void (*)(int sig, siginfo_t* info, void* context); // 注册回调必须在主线程调用成功返回 true处理器数量达到上限MaxHandlers 16返回 false bool registerNonFatalSignalHandler(NonFatalSignalCallback cb); // 移除回调必须在主线程调用 void removeNonFatalSignalHandler(NonFatalSignalCallback cb); // 在信号处理器上下文中调用所有已注册回调 void callNonFatalSignalHandlers(int sig, siginfo_t* info, void* context); // 查询 SIGUSR2 信号处理器当前是否已安装 bool isInstalled();backtrace_action 的onNonFatalSignal静态方法正是这样一个 async-signal-safe 回调被注册进该框架后由框架统一派发。四、向卡死线程发送 SIGUSR2线程定向信号4.1 线程定向信号的实现传统kill()向进程发信号由进程内任一可接收信号的线程处理而 backtrace_action 需要精确地向某个特定线程投递信号这样才能在该线程自己的上下文中采集它的调用栈。Envoy 在 source/common/thread/signal_thread.h 中抽象出// 向指定线程且仅该线程发送指定信号成功返回 true bool signalThread(const ThreadId tid, int signal);注释中特别说明signalThread与terminateThread有本质区别它要求信号被投递到某一个特定线程以便该线程上的逐线程信号处理器在目标线程上下文中执行。在run()方法中实际调用为Thread::signalThread(tid, SIGUSR2)见 backtrace_action.cc。注意该机制依赖平台对逐线程信号投递的支持目前仅确认在支持信号语义的平台上如 Linux可用这与 proto 定义中该动作目前仅支持 Linux的声明见 backtrace_action.proto一致。4.2 信号处理器的自进程校验onNonFatalSignal处理器收到信号后第一件事是校验信号来源// 只处理本进程自己发送的信号 if (info nullptr || info-si_pid ! getpid()) { return; }见 backtrace_action.cc这意味着如果外部进程例如运维脚本向 Envoy 发送了SIGUSR2backtrace_action 的处理器会直接忽略它。这一安全校验同时暗示了另一个行为特征一旦启用了 backtrace_action进程级SIGUSR2处理器就已安装外部发来的SIGUSR2虽然不会触发 backtrace 采集但也不会再执行任何用户自定义逻辑除非用户自己的处理器也通过该框架注册。五、信号槽状态机并发安全地采集多个线程的回调采集线程的回调是一个并发难题信号处理器会异步地打断目标线程的执行而run()所在的看门狗线程以及定时器线程需要安全地读取采集结果。backtrace_action.h用固定大小的静态槽位数组MaxSlots 16和原子状态机解决这一问题。5.1 槽位生命周期每个SignalSlot的状态机定义在 backtrace_action.hFree - Claimed - Signaled - Writing - Ready - Free \- Free信号处理器从未启动时由定时器释放Free空闲可被run()认领Claimed已认领run()已预留槽位正在写入目标线程 TIDSignaled已发信号TID 已发布信号已发送但信号处理器尚未开始写回溯Writing写入中信号处理器已认领该槽位正在写回溯内容Ready就绪回溯已完整写入定时器可安全读取并记录日志。signal_slots_数组被声明为static见 backtrace_action.h注释明确指出这是为了保证即使实例被销毁信号处理器仍然可以安全使用这些槽位——因为信号处理器可能在实例析构的瞬间仍在执行。5.2 run() 中的认领与投递run()对每个超时未签到的线程执行见 backtrace_action.cc检查冷却期若该线程在cooldown_duration_内刚采集过跳过通过 CAS 将某个空闲槽位从Free置为Claimed写入 TID再置为Signaled调用signalThread(tid, SIGUSR2)投递信号失败则释放槽位并递增backtraces_failed统计成功则启动该槽位对应的 100ms 定时器并记录该线程的上次采集时间。5.3 信号处理器中的写入目标线程收到SIGUSR2后onNonFatalSignal在其上下文中执行见 backtrace_action.cc校验si_pid getpid()用当前线程 IDThread::getCurrentThreadId()在槽位数组中查找状态为Signaled且 TID 匹配的槽位通过 CAS 将槽位从Signaled置为Writing独占写入权若 CAS 失败说明定时器已释放槽位直接跳过调用absl::GetStackTraceWithContext若可用或absl::GetStackTrace采集最多MaxStackDepth 64帧的调用栈见 backtrace_action.h将状态置为Ready交由定时器读取。5.4 定时器中的日志输出每个槽位对应一个 100ms 定时器onSlotTimer见 backtrace_action.cc其处理逻辑是Ready用BackwardsTrace打印回溯到日志critical级别递增backtraces_logged统计释放槽位为FreeSignaled说明目标线程迟迟未进入信号处理器可能完全卡死无法响应信号尝试将其释放为Free并递增backtraces_failed若 CAS 失败说明信号处理器刚好开始写入则继续等待Writing信号处理器仍在写入重新启用 100ms 定时器继续等待Free / Claimed无操作。这一信号处理器写、定时器读的双角色配合配合每个槽位的原子状态迁移实现了在信号异步打断线程的情况下依然无锁、无数据竞争的回溯采集。六、关键配置参数与统计指标6.1 配置原型与参数配置定义在 api/envoy/extensions/watchdog/backtrace_action/v3/backtrace_action.proto扩展标识为envoy.watchdog.backtrace_action目前仅支持 Linux字段类型说明默认值cooldown_durationgoogle.protobuf.Duration每个线程两次回溯日志之间的最小时间间隔设为 0 可禁用冷却、在每次看门狗事件时都采集10 秒在BacktraceAction构造函数中该参数通过PROTOBUF_GET_MS_OR_DEFAULT(config, cooldown_duration, 10000)解析见 backtrace_action.cc未设置时默认 10000ms10 秒。6.2 统计指标动作的统计指标定义在 backtrace_action.h以watchdog.backtrace_action.为前缀见 backtrace_action.ccbacktraces_logged计数器成功记录到日志的回溯数量backtraces_failed计数器采集失败的回溯数量如信号投递失败、目标线程未响应、定时器超时释放槽位等。运维时可将这两个计数器与看门狗事件告警联动当backtraces_failed持续增长而backtraces_logged不增长往往意味着目标线程连信号都无法响应属于深度卡死状态。七、配置示例与实战验证7.1 在 bootstrap 配置中启用backtrace_action 通过看门狗动作WatchdogAction配置需结合watchdog_config与watchdog_actions使用。以下为完整可参考的 bootstrap 配置骨架bootstrap: watchdog_config: miss_timeout: 0.2s megamiss_timeout: 1.0s kill_timeout: 0s max_kill_timeout: 0s multicore_threshold: 0 watchdog_actions: - config: type: type.googleapis.com/envoy.extensions.watchdog.backtrace_action.v3.BacktraceActionConfig cooldown_duration: 10s event: megamiss name: envoy.watchdog.backtrace_actioncooldown_duration设置为10s即默认值若希望快速定位卡死现场可缩短冷却时间注意采集回溯本身有开销event可设为miss、megamiss等看门狗事件按需调整触发时机回溯日志以critical级别输出形如Backtrace Action: backtrace for thread 12345: ... 调用栈帧 ...7.2 行为验证要点从源码路径可验证以下行为特征信号来源过滤外部进程向 Envoy 发送SIGUSR2会被忽略backtrace_action.cc逐线程投递只有目标 TID 匹配的线程才会在信号处理器中写入槽位backtrace_action.cc冷却与去重同一线程在cooldown_duration内不会重复采集backtrace_action.cc。八、部署影响与迁移建议8.1 信号冲突风险本变更最大的部署影响是SIGUSR2被 backtrace_action 占用。变更记录原文明确提示依赖SIGUSR2做其他用途的部署应避免启用此动作。常见的SIGUSR2用途包括外部运维脚本通过kill -USR2 pid触发的自定义行为如日志轮转、状态导出、优雅流程与系统监控、coredump 收集策略的既有约定冲突容器运行时或编排层对信号的既有依赖。启用 backtrace_action 后这些外部触发将不再走自定义逻辑进程级处理器已安装且不会产生 backtrace 输出被si_pid校验过滤。8.2 评估清单在生产环境启用前建议逐项确认信号占用审查确认部署链路脚本、容器、编排平台中没有依赖SIGUSR2的自定义逻辑平台限制该动作仅支持 Linux见 backtrace_action.proto非 Linux 部署应使用其他诊断手段采集开销回溯采集在信号处理器上下文中执行且每秒最多由 100ms 定时器驱动读取应合理设置cooldown_duration避免高频采集统计监控部署后关注watchdog.backtrace_action.backtraces_logged与backtraces_failed两个计数器用于评估看门狗判定的准确性与采集成功率。九、总结envoy.watchdog.backtrace_action从发送通用信号采集回溯演进为进程级SIGUSR2处理器 线程定向投递 槽位状态机的完整方案是 Envoy 看门狗诊断能力的重要增强。理解其信号生命周期注册、投递、校验、写入、读取与部署约束信号占用、平台限制、冷却配置是正确使用这一诊断利器、避免生产事故的前提。对于仍在使用SIGUSR2做自定义用途的部署请务必在启用该动作前完成信号占用评估。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价