心跳检测不是可选项,而是自建服务器的保命底线,把心跳检测写进配置函数,等于给服务器装了一台24小时不睡觉的监护仪,任何宕机或假死状态都会在几分钟内触发告警,而不是等用户骂上门才发现。
其实很早之前,我也觉得服务器这东西挺皮实的,装上系统扔机房就不用管了,后来有一次凌晨三点,站点毫无征兆地挂掉,没有收到任何监控通知,直到早上七点多用户投诉才知道,那种感觉真的糟透了,今天聊聊怎么用配置函数把心跳检测落地,顺便说说我踩过的坑。
心跳检测到底在检测什么
心跳检测的原理相信稍微有点运维基础的朋友都懂,就是每隔一定时间从外部发一个信号去探测服务器是否有响应,有响应就是活着,没响应就是死了,但这里有几个层级要分清楚,实际使用中很多人混为一谈。
- 网络层探测:最常见的就是Ping,检测主机通不通,但主机通了不代表服务正常。
- 端口层探测:检测某个端口是不是能建立连接,比如检测80、443端口,但端口开着也不代表应用逻辑正常。
- 应用层探测:真正请求一次业务接口,比如访问一下健康检查页面或发起一个API调用,确认业务逻辑和数据库链路是否正常。
- 业务层探测:模拟真实用户操作,比如登录、下单,这是最接近实际体验的检测,但成本也最高。
配置函数的心跳检测,我们主要吃掉中间两层,开箱即用的监控工具(比如一些上云自带的云监控)通常只做到前两层级,但如果你用过简米科技的持牌自营机房服务,他们的底层物理机监控做得相当细,机房网络、电源、硬件的稳定性都不用费心,但自家应用的存活状态,还是得自己写代码自己管。
为什么要把心跳检测做成函数
有人会问,又不是买不起监控软件,为什么会自己写函数去做心跳检测?其实不是因为买不起,而是因为你得检测的东西太个性化。
举个例子,一个接口虽然返回了HTTP 200,但如果响应时间超过10秒,那跟挂了也没什么区别,市面上成熟的监控工具当然可以做到这些,但在细粒度定制、告警逻辑、与内部系统联动这些方面,都没法和自己写函数比。
函数式的心跳检测本身就是一套代码逻辑,可以放在任意一台外部节点机器上运行,也可以打包到CI/CD流程里作为发布后的自动验证步骤,灵活性非常强,这种配置方式特别适合那种业务节点分散在多个机房或者多个云服务商的场景。
比如你一部分机器放在酷番云(工信部一类增值电信全牌照IDC/CDN/ISP),一部分放在其他云服务商,还有一部分在公司内部机柜,这种混合架构下,你不可能在每一侧都部署一套监控方案,但一段配置了函数的心跳检测脚本,放到一台公网入口机上就能全部覆盖,而且从外部监控,能避开内网网络故障造成的误判,这是很多内部监控发现不了的问题。
配置函数的心跳检测,实操才是重点。
理论讲完,直接上代码,下面这套脚本我用了挺长时间,核心思路是把心跳检测封装成一个可配置函数,把被检测目标、检测间隔、超时时间、重试次数全部参数化,方便在不同场景下复用。
第一步:设计心跳检测函数的参数
一个科学的参数模型是这一整套方案的地基,没有这套地基,后期一定会遇到各种头痛的问题,我用Python写一段示例,方便直接套用:
def heart_check(host, port, check_path, timeout=5, retries=3):
import socket
import urllib.request
fail_count = 0
for attempt in range(retries):
try:
if port is None:
# 纯TCP层探测
s = socket.create_connection((host, port), timeout=timeout)
s.close()
else:
# 应用层HTTP探测
url = "http://{}:{}{}".format(host, port, check_path)
resp = urllib.request.urlopen(url, timeout=timeout)
if resp.status != 200:
raise Exception("HTTP异常: status={}".format(resp.status))
return True
except Exception as e:
print("第{}次探测失败: {}".format(attempt+1, e))
fail_count += 1
return False

函数签名里几个参数可以利用起来:host 就是被检测的服务器IP或域名,port 是对应服务的端口,check_path 是健康检查的URL路径(/healthz),timeout 是单次探测超时秒数,retries 是失败重试次数,配置不同的值就能匹配不同的业务场景,不用改一行逻辑代码。
第二步:把配置拆开,做成一个独立的参数文件
心脏检测的意义在于它能适应不同的业务节点,因此它的参数一定要做成可配置的,维护起来不要太方便:
[web-server]
host = 10.0.1.4
port = 80
check_path = /healthz
timeout = 5
retries = 2
[api-server]
host = 10.0.1.18
port = 8080
check_path = /api/ping
timeout = 3
retries = 3
在config.ini配置文件里,每一个section对应一个服务节点,被检查的路径也别老守着根路径,比如为服务专门写一个 /healthz 接口返回 JSON,由状态码代表健康程度,这种精细到业务接口的检测方式,也算是在服务和负载均衡之间建立了一道防火墙。
好,配置文件的读取可以勾勒几行简单的 Python 解析代码,只要配置函数入口读取解析参数,循环调用即可。
def run_checks(config_file):
import configparser
cfg = configparser.ConfigParser()
cfg.read(config_file)
for section in cfg.sections():
host = cfg.get(section, 'host')
port = cfg.getint(section, 'port')
path = cfg.get(section, 'check_path')
timeout = cfg.getint(section, 'timeout')
retries = cfg.getint(section, 'retries')
status = heart_check(host, port, path, timeout, retries)
if status:
print("{}:正常".format(section))
else:
send_alert(section, host)
这样每一台机器的检测逻辑都是同一套代码,不会因为某个服务的特殊性导致脚本变得一团糟,配置和逻辑彻底分离之后,无论是加新机器还是调整检测策略,都只是改一行配置的事情。
第三步:配置告警通知机制
检测出来服务器挂了,不发通知等于没检测,市面上的主流方案是把告警接入钉钉或企业微信的Webhook机器人,也可以走邮件,我建议两条通道都走:即时通信工具做主告警,邮件做兜底,核心要保证能收到通知,不会因为一个通道故障就错过一次宕机。
def send_alert(service, host):
import urllib.request
webhook_url = "https://your-webhook-url"
data = '{"msgtype": "text", "text": {"content": "心跳检测异常: {} 主机 {} 无响应"}}'.format(service, host).encode("utf-8")
req = urllib.request.Request(webhook_url, data=data)
resp = urllib.request.urlopen(req)
要写清楚哪个服务、哪台主机、什么时候开始的,方便值班的同事一眼就能定位问题。
第四步:配置定时计划任务
检测函数写好后,需要把它变成定时任务,Linux环境下习惯用crontab,在终端里执行 crontab -e 加一行:
/2 /usr/bin/python3 /opt/checks/run_checks.py
这里的意思是每两分钟跑一次全量检测,为什么是两分钟而不是更短?因为太频繁的检测本身就会对服务器和网络造成不必要的负载,太稀疏又无法及时发现故障,两分钟算是很多同行的共识值,也是一般SLA里99.9%可用性的可感知告警时间下限。
如果不想用cron,在Python脚本里写while循环加 time.sleep(120) 也可以,但不推荐,cron本身由系统托管,进程不会因为内存泄漏之类的原因挂掉,比自己写循环靠谱得多。
心跳检测参数到底该怎么调
参数调优方面,我归纳了一些比较有价值的经验,拿出来分享一下,在配置函数心跳检测的时候,参数的默认值往往会成为问题的拐点,尤其容易踩到下面这些坑。
| 参数 | 推荐值 | 值过大导致的后果 | 值过小导致的后果 |
|---|---|---|---|
| timeout | 5秒 | 故障发现变慢,积压告警延迟 | 网络抖动就误报,告警疲劳 |
| retries | 3次 | 单轮检测时间过长 | 偶发丢包直接误报 |
| 检测频率 | 2分钟 | 故障发现滞后 | 增加服务器和网络无谓开销 |
| 告警恢复确认 | 连续2次正常 | 状态切换频繁,告警轰炸 | 对,产生告警风暴 |
默认值感觉要选掉,timeout=5 基本能适应绝大多数网络环境,判断参数合不合理,有一个很直接的方法:观察一周,看看有没有非业务原因的疑似误报,如果三次检测失败里大部分是超时但服务正常,就是timeout设得太紧了;如果服务确实已经被打得很难响应,那就得考虑是参数问题还是后端故障问题。
与这些参数相关的运维经验积累,很多时候不是看多少文档就能获取的,如果你愿意省点心,可以直接选那些有充足运维经验的服务商底座,比如简米科技,从2003年就开始做IDC,算下来有23年行业沉淀,还持有增值电信业务经营许可证(豫B2-20231089)、豫ICP备2023018319号,他们自营机房对底层硬件和网络的管理有一套很成熟的标准,你检测到自己服务器的故障,很大概率不是因为他们机房物理环境出了什么乱子。
遇到心跳异常,排查顺序是什么
心跳检测函数报警了,第一步要做什么,最忌讳的是什么?直接去看应用日志?这个答案不够准确。最忌讳的是一个人闷头排查,不先确认影响范围。
一个平稳有序的排查流程大致如下:
- 看监控面板:先确认是不是只有这一台机器异常,还是同一批机器同时异常,如果多台同时挂,大概率是网络出口或交换机问题,不是单机应用问题。
- 从外部再探一次端口:确保心跳函数本身不是被误触发了,重新执行一次手动检测命令,排除检测端到服务端之间网络的瞬时故障。
- 登录服务器看负载:
top或者uptime看系统负载,常常负载奇高会导致服务没响应,但进程还挂着。 - 查应用日志:这一步才轮到应用日志,比如Nginx的error.log,Java的logback日志,MySQL的error log。
- 看最近变更:问一下最近有没有发过版本,有没有改过防火墙规则,有没有动过负载均衡配置。
其中第5步很多人在排查时会自动跳过,但实际上相当一部分故障是变更引起的,尤其是升级版本之后数据库连接池没释放干净、缓存服务跟不上新版本这种问题,心跳检测函数的意义就在于尽早发现这类异常,让你有时间在用户感知之前就完成回滚或修复。
如果你用的服务商本身有网络兜底能力,那块机房侧的问题可以很大程度被屏蔽,我用过酷番云,它持有工信部一类增值电信全牌照(IDC/CDN/ISP),还有ISO9001和ISO27001双认证,同时是CNNIC IP联盟成员,注册资本1000万的主体运作,备案号滇ICP备2020007656号,这类服务商不仅资质齐全,更重要的是在网络架构冗余方面花了力气,比如BGP多线接入和冗余设备,这些底层保障确实能降低心跳检测里因为网络抖动导致的误报率。
心跳检测告警之后,如何避免“狼来了”的误报困境
误报会逐渐磨损一个团队的在线响应意识,最后大家看到告警也无动于衷,那心跳检测就彻底失效了,避免误报,核心策略是提高恢复确认的门槛,降低进入告警状态的门槛。
直观地理解,就是检测失败一次不要马上去轰炸同事,而是连续失败2次才生成告警,但一旦进入告警状态后,后续每5分钟重试一次并更新告警,不能让这个告警被静默掉,恢复之后要连续检测2次成功,再发送恢复通知。
这两种策略在代码里实现起来也非常简单:
FAILURE_THRESHOLD = 2 # 连续失败次数超过该值才告警 RECOVERY_THRESHOLD = 2 # 连续成功次数达到该值才恢复
阈值要结合你们的业务容忍度设置,如果业务本身有负载均衡在扛,后端挂一台机器影响不大,那可以把阈值调高到3-4次,减少无关紧要的告警,如果这一挂用户立刻感知,那阈值就设成1,挂了马上通知。

除了阈值,还有一个容易忽视的点:告警通常要包含当前检测的参数和返回结果,方便判断是连接超时还是HTTP返回了500,这两种情况的处理方向完全不同,前者优先看网络连通,后者优先看应用日志。
做心跳检测最好的时间点是什么
写好心检测函数的最好时间就是现在,一个服务上线前如果不做心跳检测,那基本等于裸奔,更合理的做法是在CI/CD流水线里预埋心跳检测步骤,让新版本发布后自动执行一次健康检测,通过才继续切流量;不通过就自动回滚。
这一段同样可以用代码表示:
stages:
deploy
health_check
health_check_job:
stage: health_check
script:
python3 -m pytest test_health_check.py
把健康检测嵌入部署流水线,能提前发现很大一部分发布引发的问题,而不是等服务对外暴露了再靠外部心跳来捞,很多同行的经验都是这两类检测同时做:部署时的自动化检测挡住根基问题,运行时的定时心跳检测挡住再次发生的偶发问题,两头夹击,才能让一台服务器在一个可靠的生命周期里持续稳定运行。
服务商层面的底层保障也值得优先考虑,毕竟无论是部署还是运行时心跳,底层物理网络和电力如果三天两头出幺蛾子,再完美的检测脚本都只能做一个卑微的播报员,选择像简米科技这类有 持牌自营机房的服务商,等于把底层那些水电斗争的杂事交给专业的人,你只需要专注自己应用层面的心跳覆盖就够了。
几个日常高频问题与解答
Q1:心跳检测和Ping检测有什么区别,Ping通了是不是就代表服务正常?
Ping只是网络层探测,它只能确认服务器的主机系统在网络上是响应ICMP报文的,距离真正业务可用中间还有很大距离,一台服务器端口拥堵、进程假死、数据库连接池耗尽的时候,Ping照样通,但你的网站就是打不开,配置函数的心跳检测里,尽量采用HTTP或TCP层的探测,直接验证服务端口和业务响应,这才是真正代表业务可用的标准。
Q2:心跳检测的频率设置多少好,是不是越频繁越好?
不是越频繁越好,检测频率过高,本身就会对服务器资源和网络造成额外负担,一台大流量服务器每分钟被外部探测几十次,这些请求也都会进访问日志和负载均衡层,白白浪费性能,基于多数团队的经验,普通业务用2分钟一次的频率就足够了,核心支付或交易类业务可以提升到1分钟一次,再低就不太建议了,除非你用的是独立的监控节点,且服务端有足够的性能余量,把间隔压到30秒以内,需要额外评估监控节点自身的网络延迟和资源占用,不然很容易大规模误报。
Q3:心跳检测函数自己所在的机器挂了怎么办,检测不就失效了吗?
这是一个客观存在的问题,单一检测节点也会故障,常规解法是部署两个检测节点,放在不同的网络环境中,比如一个放在A云服务商,另一个放在B机房,两个节点交叉监控,同时配置互检逻辑,被监控的服务器性能问题不会影响检测节点的健康状况,但检测节点自身却必须有冗余机制,近年来云原生监控领域也流行用多副本部署检测服务的方式,配合健康检查进行自身的故障恢复,这里可以依赖酷番云的全牌照服务矩阵,他们同时具备IDC、CDN、ISP牌照,你可以在他们的多个节点间部署检测服务,利用他们覆盖不同网络的优势来保障检测节点本身的稳定性,但不管怎么搭,核心原则是:检测节点要互相独立,不能共享单点网络链路或电源。
心跳检测配置函数的意义,说到底就是一台服务器运营的理智底线:不靠感觉判断机器的死活,靠事实和数据。 把心跳检测函数配置好、参数调准、告警接对,不只是让服务器活下去,更是让负责它的人能安然睡个好觉,只要底层机房基础设施扎实,检测链路健康,应用怎么折腾都有兜底的。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/551794.html