2026/1/15 12:41:02
网站建设
项目流程
如何做一个大型网站,广州腾虎网络网站建设,校园网站网络文明建设,广告优化师怎么学在嵌入式开发、服务器运维这些场景里#xff0c;最头疼的事儿莫过于系统“卡死”——CPU负载飙到满格、进程僵死、甚至整个系统失去响应#xff0c;没人手动干预的话#xff0c;设备就彻底“趴窝”了。这时候#xff0c;“看门狗守护进程#xff08;watchdogd#xff09;…在嵌入式开发、服务器运维这些场景里最头疼的事儿莫过于系统“卡死”——CPU负载飙到满格、进程僵死、甚至整个系统失去响应没人手动干预的话设备就彻底“趴窝”了。这时候“看门狗守护进程watchdogd”就成了系统的“贴身保镖”它盯着系统状态定期给硬件看门狗“喂饭”一旦系统出问题没法喂饭看门狗就会触发硬件重启把系统从死机状态拉回来。今天我们就拆解这款轻量的watchdogd实现聊聊它是怎么守护系统稳定的。一、先搞懂看门狗到底是个啥先说白话版定义硬件层面有个“看门狗芯片”你可以把它理解成一个“倒计时炸弹”——设定好20秒超时只要系统每隔10秒给它发个“我还活着”的信号行业里叫“喂狗”炸弹就重置倒计时要是系统卡死了没法发信号倒计时结束芯片就会触发硬件重启让系统重新运行。而我们今天聊的watchdogd是运行在用户态的守护进程核心作用就是“替人干活”自动定期给硬件看门狗发“喂狗”信号还能监控系统负载、支持外部程序管控是连接用户态和硬件看门狗的“桥梁”。二、核心实现代码到底在干啥这款watchdogd的代码不算复杂但把看门狗的核心逻辑都覆盖了整体流程就像“按剧本走流程的保安”先看简易流程文字版原理图启动程序 ↓ 解析命令行参数比如是否后台跑、喂狗间隔、是否交给外部管控 ↓ 后台运行→ 是变成守护进程脱离终端默认用syslog打日志否前台运行 ↓ 创建PID文件/var/run/watchdogd.pid→ 方便外部程序找进程ID ↓ 打开看门狗设备/dev/watchdog打不开直接退出没硬件看门狗玩不了 ↓ 设置硬件超时比如设20秒→ 读实际超时值怕硬件不支持自定义→ 确定喂狗间隔默认超时的一半 ↓ 注册信号处理比如按CtrlC退出、收到SIGPWR强制重启、外部发SIGUSR1喂狗 ↓ 记录上次重启原因比如是看门狗触发、CPU过热还是断电→ 写进/var/run/watchdogd.status ↓ 进入主循环核心环节 ├─ 没开外部管控主动调用wdt_kick“喂狗”给内核发IOCTL指令 ├─ 开了外部管控等外部程序发SIGUSR1喂狗启动时可设延迟先自己喂几次 ├─ 检查系统负载负载超阈值→触发重启 ├─ 睡够喂狗间隔被信号唤醒就补觉剩余时间 └─ 循环往复 ↓ 收到退出信号 ├─ 安全退出给/dev/watchdog写V→关闭硬件看门狗→退出 └─ 普通退出直接关设备→退出看门狗仍生效没人喂就重启再拆解几个关键代码逻辑1. 代码实现...staticintusage(intstatus){printf(Usage: %s [-f] [-w sec] [-k sec] [-s] [-h|--help]\nA simple watchdog deamon that kicks /dev/watchdog every %d sec, by default.\nOptions:\n --foreground, -f Start in foreground (background is default)\n --external-kick, -x [N] Force external watchdog kick using SIGUSR1\n A N x interval delay for startup is given\n --logfile, -l file Log to file when backgrounding, otherwise silent\n --syslog, -L Use syslog, even if in foreground\n --timeout, -w sec Set the HW watchdog timeout to sec seconds\n --interval, -k sec Set watchdog kick interval to sec seconds\n --safe-exit, -s Disable watchdog on exit from SIGINT/SIGTERM\n --load-average, -a val Adjust load average check, default: 0.7, reboot at 0.8\n --verbose, -V Verbose operation, noisy output suitable for debugging\n --version, -v Display version and exit\n --help, -h Display this help message and exit\n,__progname,WDT_TIMEOUT_DEFAULT);returnstatus;}intmain(intargc,char*argv[]){...structoptionlong_options[]{{foreground,0,0,f},{external-kick,2,0,x},{interval,1,0,k},{load-average,1,0,a},{logfile,1,0,l},{safe-exit,0,0,s},{syslog,0,0,L},{timeout,1,0,w},{verbose,0,0,V},{version,0,0,v},{help,0,0,h},{NULL,0,0,0}};while((cgetopt_long(argc,argv,a:fx::l:Lw:k:sVvh?,long_options,NULL))!EOF){switch(c){casea:loadstrtod(optarg,NULL);if(load0){ERROR(Load average argument must be greater than zero.);returnusage(1);}load_warnload;load_rebootload0.1;break;casef:background0;break;casex:if(!optarg)extdelay1;elseextdelayatoi(optarg);break;casel:if(!optarg){ERROR(Missing logfile argument.);returnusage(1);}logfilestrdup(optarg);break;caseL:sys_log1;break;casew:if(!optarg){ERROR(Missing timeout argument.);returnusage(1);}timeoutatoi(optarg);break;casek:if(!optarg){ERROR(Missing interval argument.);returnusage(1);}periodatoi(optarg);break;cases:magic1;break;casev:printf(v%s\n,VERSION);return0;caseV:verbose1;break;caseh:returnusage(0);default:printf(Unrecognized option \-%c\.\n,c);returnusage(1);}}if(background){pid_tpid;if(!logfile)sys_log1;piddaemonize(logfile);if(pid)returnpid0?1:0;}INFO(Userspace watchdog daemon v%s starting ...,VERSION);setup_signals();if(pidfile(NULL))PERROR(Cannot create pidfile);fdopen(WDT_DEVNODE,O_WRONLY);if(fd-1){PERROR(Failed opening watchdog device, %s,WDT_DEVNODE);return1;}wdt_set_timeout(timeout);real_timeoutwdt_get_timeout();if(real_timeout0){PERROR(Failed reading current watchdog timeout);}else{if(real_timeoutperiod){ERROR(Warning, watchdog timeout kick interval: %d %d,real_timeout,period);}}if(-1period){if(real_timeout0)periodWDT_KICK_DEFAULT;elseperiodreal_timeout/2;if(!period)period1;}DEBUG(Watchdog kick interval set to %d sec.,period);create_bootstatus(real_timeout,period);while(1){intrem;if(!extkick)wdt_kick(Kicking watchdog.);if(extdelay){DEBUG(Pending external kick in %d sec ...,extdelay*period);if(!--extdelay)extkick1;}loadcheck_loadavg();if(loadload_warnloadload_reboot){WARN(System load average very high!);}elseif(loadload_reboot){ERROR(System load too high, rebooting system ...);wdt_reboot(0);}remperiod;do{remsleep(rem);}while(rem0);}}...If you need the complete source code, please add the WeChat number (c17865354792)逐个选项测试示例 效果验证基础帮助/版本查看无风险先测查看帮助信息对应-h/--help./watchdogd -h# 或./watchdogd --help预期效果打印所有选项说明和usage函数里的内容一致。查看版本对应-v/--version./watchdogd -v# 或./watchdogd --version预期效果输出程序版本号需确保代码里定义了VERSION宏比如加#define VERSION 1.0在代码开头。前台运行详细日志核心调试选项必测sudo./watchdogd -f -V# 等价长选项sudo ./watchdogd --foreground --verbose预期效果程序不后台运行直接在终端输出日志能看到Kicking watchdog.喂狗、Watchdog kick interval set to X sec.等详细调试信息每隔默认 10 秒超时 20 秒的一半打印一次喂狗日志。自定义超时喂狗间隔-w/--timeout-k/--interval# 设置硬件看门狗超时为 30 秒喂狗间隔为 10 秒前台详细输出sudo./watchdogd -f -V -w30-k10# 等价长选项sudo ./watchdogd --foreground --verbose --timeout 30 --interval 10预期效果日志里显示Setting watchdog timeout to 30 sec.喂狗间隔固定为 10 秒不再是超时的一半若设置的间隔 ≥ 超时比如-w 10 -k 10会打印警告Warning, watchdog timeout kick interval。安全退出测试-s/--safe-exit# 启动时加安全退出前台详细输出sudo./watchdogd -f -V -s# 另开一个终端给程序发终止信号或直接按 CtrlC# 方式1按 CtrlC触发 SIGINT# 方式2先查PIDps aux | grep watchdogd再杀进程sudo kill -TERM PID预期效果退出时日志打印Safe exit, disabling HW watchdog.看门狗被关闭不会因为程序退出触发系统重启对比不加-s的情况退出日志是Exiting, watchdog still active.若没人喂狗系统会在超时后重启。外部喂狗测试-x/--external-kick这个选项是让外部程序通过SIGUSR1信号控制喂狗分两步测试步骤1启动程序并设置外部喂狗延迟# -x 2 表示先自己喂2次间隔默认10秒共20秒再交给外部管控sudo./watchdogd -f -V -x2# 等价sudo ./watchdogd --foreground --verbose --external-kick2预期效果启动后日志打印Pending external kick in 20 sec ...前2次喂狗是程序自己来每隔10秒之后打印External supervisor now controls watchdog kick via SIGUSR1.。步骤2外部发SIGUSR1喂狗另开终端先查 watchdogd 的 PIDpsaux|grepwatchdogd|grep-vgrep|awk{print$2}给程序发SIGUSR1信号触发外部喂狗sudokill-USR1watchdogd的PID预期效果原终端日志打印External kick.表示喂狗成功若不发信号超过看门狗超时时间默认20秒系统会触发重启测试时注意保存数据。步骤3恢复自主喂狗发SIGUSR2sudokill-USR2watchdogd的PID预期效果日志打印External supervisor requested safe exit. Reverting to built-in kick.程序恢复自己每隔10秒喂狗。日志文件输出-l/--logfile# 后台运行日志输出到 /tmp/watchdog.log同时开详细输出sudo./watchdogd -V -l /tmp/watchdog.log# 等价sudo ./watchdogd --verbose --logfile /tmp/watchdog.log预期效果程序后台运行终端无输出查看日志文件能看到所有调试信息tail-f /tmp/watchdog.log强制用 syslog 日志-L/--syslog即使前台运行也把日志输出到系统日志/var/log/syslog或/var/log/messagessudo./watchdogd -f -V -L# 等价sudo ./watchdogd --foreground --verbose --syslog预期效果终端可能无输出或少量日志会写入系统日志查看系统日志# Debian/Ubuntutail-f /var/log/syslog|grepwatchdogd# CentOS/RHELtail-f /var/log/messages|grepwatchdogd负载平均值调整-a/--load-average默认负载超过 0.7 警告、0.8 重启自定义阈值# 设置负载警告阈值为 1.0重启阈值为 1.11.00.1sudo./watchdogd -f -V -a1.0测试负载触发用stress工具压测CPU先安装sudo apt install stressstress --cpu4--timeout 60s若系统负载超过 1.0日志打印System load average very high!超过 1.1 则打印System load too high, rebooting system ...并触发看门狗重启。强制重启测试SIGPWR 信号# 先启动程序sudo./watchdogd -f -V# 另开终端发 SIGPWR 信号sudokill-PWRwatchdogd的PID预期效果日志打印Forced watchdog reboot.程序将看门狗超时设为 1 秒关闭设备后等待重启系统会在 1 秒后重启测试前务必保存数据。2. 灵活的信号处理不止能喂狗还能控退出程序注册了好几类信号对应不同操作SIGINT/SIGTERM比如CtrlC触发wdt_close→退出程序开了–safe-exit就先关看门狗SIGPWR强制重启→把看门狗超时设为1秒关设备后等重启SIGUSR1外部喂狗→比如你写了个自定义监控程序检测到业务正常就给watchdogd发这个信号让它喂狗SIGUSR2恢复自主喂狗→外部程序不想管控了发这个信号watchdogd就自己继续喂。3. 负载监控不止防“卡死”还防“过载”程序会定期调用check_loadavg读系统负载默认负载超过0.8就触发重启——比如服务器扛不住高并发CPU满了系统没法处理请求这时候主动重启比卡死强。三、设计思路为啥这么写这款watchdogd的设计核心是“默认能用灵活扩展”完全贴合实际使用场景1. 兼容性优先适配不同硬件看门狗有些硬件看门狗不支持自定义超时程序会先读实际超时值wdt_get_timeout再用一半时间当喂狗间隔——比如硬件默认30秒超时程序就15秒喂一次既不频繁占用资源又不会超时重启。2. 兼顾“自主”和“外部管控”默认自己喂狗也支持–external-kick参数比如系统启动时外部监控程序还没起来可设-x 3让watchdogd先自己喂3次等外部程序就绪后再交给外部用SIGUSR1管控——嵌入式场景里多进程协作时这个功能特别实用。3. 运维友好日志状态文件日志支持syslog、日志文件、前台输出调试时开–verbose就能看详细信息状态文件/var/run/watchdogd.status记录重启原因、超时时间、喂狗间隔——系统重启后查这个文件就知道上次为啥重启是看门狗触发还是CPU过热。4. 安全退出避免误操作加了–safe-exit参数退出时会给/dev/watchdog写V——这是内核看门狗驱动的“魔法指令”告诉硬件“我要正常退出别重启”测试或维护时不会误触发重启。四、必懂的相关知识点新手也能懂想搞懂看门狗开发这些知识点绕不开1. Linux看门狗驱动/dev/watchdog是内核给用户态留的“接口”所有和硬件看门狗的交互都通过这个文件核心靠IOCTL指令喂狗、设超时、查状态。2. 守护进程Daemon程序默认后台运行通过daemonize函数脱离终端——要是不做守护进程化终端一关程序就退出了看门狗没人喂系统直接重启这就本末倒置了。3. Linux信号机制信号是Linux进程间通信的“简易方式”watchdogd靠信号实现“外部管控”比如SIGUSR1/SIGUSR2就是自定义信号专门用来控喂狗。4. PID文件/var/run/watchdogd.pid存进程ID外部程序想给watchdogd发信号先读这个文件找PID就行——这是Linux守护进程的通用做法。五、总结这款watchdogd虽然代码精简但把看门狗守护进程的核心需求都覆盖了基础喂狗、外部管控、负载监控、安全退出特别适合嵌入式Linux、边缘服务器这些需要高可用性的场景。从设计角度看它遵循了Linux系统编程的“最佳实践”用守护进程保证后台运行用信号实现灵活管控用日志/状态文件方便运维兼容不同硬件看门狗保证通用性。对开发者来说理解这个程序的思路不光能搞懂看门狗怎么用还能掌握“用户态与内核驱动交互”“守护进程开发”“系统监控”这些核心技能——不管是做嵌入式开发还是服务器运维这些都是必备的硬本事。简单说看门狗守护进程的核心就是“兜底”系统能自己跑的时候它默默喂狗系统出问题的时候它触发重启让系统“起死回生”——这也是工业级设备、无人值守服务器里看门狗必不可少的原因。Welcome to follow WeChat official account【程序猿编码】