心跳检测失效主因是表面正常但实际未验证真实连通性,需从日志校验、连接状态穿透检查、三方保活参数协同及抓包验证四方面排查。

心跳检测配置不生效,往往不是“没配”,而是“配了但没起作用”。最典型的假象是日志里持续打印“心跳成功”,连接状态显示 ESTABLISHED,可业务数据早已中断——这说明心跳逻辑根本没在验证真实连通性,只在做表面检查。
看透日志:确认你记录的真是“心跳”
很多服务把“收到任意 TCP 数据包”就当成心跳成功。比如设备每15秒发一次心跳,但实际也在高频上报传感器数据,服务端一收数据就刷新活跃时间、打日志,结果误判链路健康。必须检查代码中日志触发条件:
- 是否严格校验消息类型字段(如 protocol_type == 0x01)才记为心跳
- 是否区分了业务包、心跳包、重连包的处理路径
- 建议加一条 debug 日志:“recv heartbeat pkt, seq=xxx”,只在真正心跳包解析后输出
查清连接状态:ESTABLISHED ≠ 可通信
TCP 层的 ESTABLISHED 状态由内核维护,不感知物理断开、中间 NAT 超时、防火墙静默丢包。要用工具穿透协议层验证:
- 用 ss -o state established 查看连接的 timer 字段:如果显示 “timer:(keepalive,…)” 说明内核 keepalive 已启用;若为空,说明未开启或被覆盖
- 在服务端执行 tcpdump -i any port XXXX and 'tcp[tcpflags] & tcp-ack != 0',观察是否有来自客户端的 ACK 包——没有 ACK,说明客户端发不出,或中间链路已断
- 客户端侧用 netstat -an | grep :XXXX 看连接是否卡在 FIN_WAIT2 或 CLOSE_WAIT,这类状态常意味着对端未正确关闭,连接已半开
验证保活参数:三端协同才有效
心跳不是单边行为,客户端、服务端、中间网络设备(尤其是运营商 NAT、企业防火墙)三方参数必须匹配:
- 客户端应用层心跳间隔(如 30s),应 ≤ 服务端超时阈值(如 60s),且 必须小于运营商 NAT 超时(常见 25 分钟)
- 系统级 TCP keepalive(net.ipv4.tcp_keepalive_time)默认 7200 秒,远大于业务需求,需调低(如设为 600)并确保服务启动前生效
- 检查云防火墙、SLB、NAT 网关是否设置了空闲连接自动回收(如阿里云 SLB 默认 900s),该值必须 > 服务端心跳超时
抓包定位:用原始数据说话
所有推测都要靠抓包验证。重点比对两端流量时间线:
- 在客户端抓包:确认心跳包是否按时发出、是否有重传、SYN/ACK 是否完整
- 在服务端抓包:确认对应心跳包是否到达、是否被 iptables/nftables DROP(可用 iptables -L INPUT -v 查计数)
- 若客户端有包、服务端无包,问题在中间链路;若两端都有包但服务端不响应,检查应用层是否阻塞在读缓冲区满、线程池耗尽、反序列化异常等










