线上接口突然变慢的那一刻,我手里的咖啡都凉了——原本毫秒级响应的接口,突然稳定卡在10-12秒才返回结果,监控面板上的超时告警红得刺眼。更诡异的是,代码没人动过,SQL查起来也飞快,这波“无妄之灾”直接给我整懵了。
一、先排除“显而易见”的坑
接到告警的第一反应:先按常规套路排查。毕竟之前接口一直稳如老狗,优先排除人为改动的问题。
首先查代码提交记录,近三天的Git日志翻了个遍,涉及该接口的服务端、消费端代码全没动过,甚至依赖的Jar包版本都没变——排除代码变更问题。
接着盯上SQL,接口里的查询语句直接复制到SQLPad执行,好家伙,带索引的查询跑下来才200毫秒,数据库CPU、IO利用率也都正常,连慢查询日志里都没它的影子——SQL和数据库的锅也甩了。
那问题出在哪?转头去扒消费端日志,一行报错信息瞬间抓住了我的眼球:
Although retry the method xxx in the service xxx was successful by the provider xxx but there have been failed providers xxx(1/2)from the registry xxx on the consumer xxx using the dubbo version 2.8.4.
翻译过来就是:调用服务时,先访问了一个节点失败了,重试到第二个节点才成功。
这就对上了!10秒左右的延迟,刚好是Dubbo默认的超时时间(一般5秒)叠加重试一次的耗时——第一次调用失败节点等了5秒超时,重试成功节点又走了一遍流程,总耗时刚好卡在10-12秒。
二、揪出“隐身”的假死节点
顺着日志里的“failed providers xxx”找到那个失败的节点IP,接下来的操作直接让我傻了眼:
登录到该节点的服务器,查服务进程还在(ps -ef | grep xxx能看到进程ID),端口也在监听(netstat -tulpn显示8080端口活跃),甚至注册中心里这个节点还挂着“存活”的状态。
但翻服务日志才发现,这个节点的日志停留在3天前——服务进程没死,但已经“假死”了,既不输出日志,也无法处理请求,却还赖在注册中心里没被踢出去。
为啥假死节点没被剔除?想起Dubbo 2.8.4的心跳机制:默认是消费端每隔60秒发送心跳,服务端超时90秒未响应才标记不可用。但如果服务进程陷入死锁、内存溢出(但没崩),或者网络层出了问题,就可能出现“进程在、心跳断、注册中心没感知”的情况。这个节点大概率是某次JVMGC异常后陷入假死,既没崩掉,也没触发注册中心的下线逻辑。
三、根治方案:临时救场+长效预防
找到病根就好办了,先快速止血,再补牢防复发。
1. 临时救场:重启“活死人”节点
直接kill -9干掉假死的服务进程,再用启动脚本重启。重启后消费端日志里的“failed providers”消失了,接口响应时间瞬间回落到300毫秒以内,告警也跟着消了——这步属于“治标但救命”。
2. 长效预防:堵上三个漏洞
光重启可不行,得避免下次再踩坑。结合Dubbo 2.8.4的特性,我们针对性加了三重防护:
(1)优化Dubbo心跳与超时配置
既然默认心跳机制不灵敏,就缩短检测周期。在服务端和消费端的dubbo.properties里加了这几行:
# 消费端心跳间隔30秒,超时60秒就剔除节点 dubbo.consumer.heartbeat=30000 dubbo.consumer.timeout=3000 dubbo.registry.fileCache=true
把心跳间隔从60秒缩到30秒,超时时间从5秒改到3秒,让假死节点能更快被识别并剔除。
(2)加节点健康检查脚本
写了个简单的Shell脚本,每隔1分钟检测服务日志是否更新、接口是否能正常返回数据,一旦发现“日志停更但进程存活”就自动重启,还会发告警到企业微信:
#!/bin/bash # 检查服务日志更新时间 log_time=$(stat-c %Y /var/log/xxx-service.log) current_time=$(date +%s) # 日志超过5分钟没更新,且进程存在则重启 if[ $((current_time - log_time)) -gt 300 ] && [ $(ps -ef | grep xxx-service | wc -l) -gt 1 ];then kill-9 $(ps -ef | grep xxx-service | grep -v grep | awk'{print $2}') /opt/xxx-service/start.sh curl -H"Content-Type: application/json"-d'{"msg":"xxx节点假死,已自动重启"}'企业微信告警接口 fi
把脚本加到crontab里,相当于给节点加了个“自动除颤器”。
(3)规划Dubbo版本升级
Dubbo 2.8.4是2017年的老版本了,很多稳定性问题在后续版本已经修复,比如3.x版本优化了注册中心的节点健康检测逻辑,还支持了服务端主动下线通知。目前已经把“升级Dubbo版本”排进了迭代计划,从根源上减少老版本的坑。
四、踩坑总结:排查线上问题的3个关键思维
这次排查虽然折腾,但也摸清了Dubbo节点假死的套路,总结出3个线上问题排查的关键点:
-
别忽略“重试日志”:很多人看到“retry successful”就觉得问题解决了,却没注意背后的“failed providers”——重试成功往往意味着有节点出问题了,只是被重试机制掩盖了。
-
进程存活≠服务可用:排查节点时别只看
ps和netstat,一定要结合日志、接口探测等“活性检查”,否则很容易被假死进程骗了。 -
老版本有暗坑:像Dubbo 2.8.4这类老旧版本,心跳、注册中心同步等机制可能存在缺陷,遇到诡异问题时,不妨先查查版本是否有已知Bug。
线上问题从来不是“突然发生”的,只是我们没及时发现隐患。这次的假死节点如果早加健康检查,也不会藏3天之久。各位用Dubbo的同学,赶紧回去查查自己的老节点日志吧~


被折叠的 条评论
为什么被折叠?



