一个人管一台服务器的时候,判断网络好不好用 ping 就够了。一旦变成三四个机房、七八条专线,「到底哪一段慢」就成了必须回答的问题,而答案往往藏在「从 A 到 B 快、从 C 到 B 慢」这种对比里。
SmartPing 解决的就是这件事。它把多台机器做成一个互 Ping 的网,把每段链路的延迟与丢包画成曲线,超过阈值就报警,并且报警的时候顺手跑一次 MTR,把逐跳路由一并附上。项目是 smartping/smartping,Apache-2.0,1895 星、332 fork,版本停在 0.8.0。
先说清楚它的时间线:文档站首页的「最后更新」显示是六年前,代码版权写的是 2017–2020。这是个老项目,但仓库、官网、发布包都还在正常访问。国内不少讲机房链路监控的文章一直拿它当例子,原因大概是——这类工具里,愿意把「互 Ping 拓扑」做成可视化界面的本来就不多。
一、先看它长什么样
上面这张是官方仓库自带的功能截图。左边十个小图,每一格是一条链路的延迟曲线,横轴是时间(截图上大约是最近一小时的窗口),纵轴是毫秒;曲线上出现的红色标记是丢包点。右边一列是节点列表,点一下就能切换要看的目标。
顶部七个标签基本就是它的全部功能:正向 Ping、反向 Ping、拓扑、全国延迟、检测工具、系统配置,还有一个告警记录页。七个页面加上内置的一段报警提示音,构成了整个前端——没有任何构建工具,就是几个静态 HTML 页面加 ECharts。这也是为什么它能在十年前的老机器上跑得很轻。
顺带一提,这张官方截图里所有节点名称都被作者打了码。用生产环境的真实界面当宣传图,还得先手动抹掉机器名,这件事本身就挺能说明它的使用场景——它是被真拿去看机房的,不是玩具。
二、无中心化:数据各存各家,查询时才拼起来
README 里对设计思路的表述很直接:本系统定位为轻量级工具,即使组多点成互 Ping 网络也遵守无中心化原则,所有数据均存储自身节点中,每个节点只提供出方向的数据;从任意节点查询,都会通过 Ajax 请求关联节点的 API 接口,获取并组装全部数据。
翻代码可以确认这句话是怎么落地的:每台机器上跑的是同一份程序,采集循环每 60 秒执行一次,把本轮 Ping 的结果写进本地 SQLite 的 pinglog 表;你在浏览器里打开 A 的页面,前端会去问 B、C 要数据,在页面上拼成一张完整拓扑。聚合发生在浏览器这一层,服务端之间不交换数据,也没有主节点。
这个设计的收益很实在:
- 没有单点。任何一台节点挂了,其余节点照常采集,只是它那一段数据缺失;不存在「中心一死全盘空白」。
- 扩容只是多装一台。加一个新机房不需要改任何中心配置,装完在别的节点里把它加进互 Ping 列表即可。
- 数据不出机房。每台机器只存自己发出去的方向,等于天然做了数据分片。
代价同样明确:查询是要等所有节点回话的。节点一多、或者某个节点网络不好,打开页面就会转圈;而且查到的数据是「此刻各节点本地的最新值」,不是一份统一的时序快照。它不是时序数据库,别指望拿它做历史对账。
三、报警这块,作者想得比一般工具细
大多数自建监控的报警逻辑是「一超标就发」,结果是半夜被同一件事吵醒二十次,然后你就把告警关掉了。SmartPing 在这一段做了两层约束,配置里能看出来。
每条互 Ping 链路上可以单独设四个阈值:平均延迟上限、丢包率上限、检查周期、容忍次数。默认模板给的是 200 毫秒、30%、900 秒、3 次。判定的时候不是看「最后一次采样」,而是回头统计这 900 秒窗口内,延迟或丢包超标的记录有多少条——必须超过 3 条才算异常。按每 60 秒一采算,也就是说至少要有四五轮持续变差才认账,一次抖动不算。
第二层是边沿触发:报警状态从「健康」翻成「异常」时才发一次,之后即使一直坏着也不再重复发,直到恢复正常。这一条看起来简单,但它决定了这个工具能不能长期开着——能长期开着的告警才有意义。
真正让它在同类工具里显得特别的是第三步:一旦判定异常,程序会对故障目标立刻跑一次 MTR,把逐跳路由的结果一起写进 alertlog 表,并把 MTR 结果渲染成一张八列的表格塞进报警邮件。这八列是 mtr 命令的标准输出:跳数、主机、丢包率、发包数、最后/平均/最好/最差延迟、标准差。
为什么这步重要?因为报警本身只能告诉你「某个目标现在不对」,MTR 才能告诉你「从第几跳开始不对」。半夜被叫起来的时候,这一份逐跳数据足以让你区分:是自己机房出口的问题、中间骨干的问题,还是对端的问题。
还有个实现细节值得记一笔:MTR 是纯 Go 写的——用原始 ICMP 加 TTL 自己组包,不调用系统的 mtr 或 traceroute 命令。每跳发 10 个包、间隔 1 秒,连续 6 跳没有响应就放弃。好处是镜像里不用装任何网络工具,一个二进制就能跑;代价是它需要原始套接字权限,普通用户跑不起来。
四、全国延迟地图的数据从哪来
「全国 Ping 延迟地图」这个名字容易让人以为它接了某个公共探测网络。实际上它的数据完全来自你自己配置的一张 IP 表:配置项按「运营商 → 省份 → IP 列表」三级组织,运营商只有三档,对应电信、联通、移动。
采集方式也很朴素:对表里每个 IP 打 3 个包取平均,把结果按省份归拢成三条线路的数值,每分钟往 mappinglog 表写一次(同一分钟内覆盖)。所以那张图的本质,是一张「省份 × 运营商」的二维表,只是用颜色渲染了出来。
需要说明:上面这张示意图是为了讲清形态而自绘的,格子里的数值是示意值,不是任何真实环境的实测结果。
这里有个实用的小设计:如果某个 IP 一个包都没回来,程序不会留空,而是直接记 2000 毫秒。这样前端永远有值可画,不用到处处理空数据——代价是地图上会立刻出现一片最深的颜色,看着吓人,但至少不会静默。
要提醒的是,官方给的配置模板里只预置了北京、上海、广东、浙江四个省市,每省每运营商一个 IP。想做成全国覆盖,得自己补齐剩下的省份和探测点,而这些 IP 的可用性和代表性要自己负责——一套过期的 IP 表,画出来的地图就是一张假图。
五、部署前必须知道的几件事
看完代码和配置模板,有几条是上手前就该知道的,不然会踩:
- 默认口令是 smartping,而且是明文存在配置文件里。程序会在自己的配置里存一个访问密码,默认值就是这个;同一份文件里还存着 SMTP 账号密码。放到公网之前,这两项必须先处理,最省事的做法是让它只监听内网,前面挡一层带口令校验的网关。
- 邮件只支持明文 SMTP。代码里用的是标准库的明文认证,主机名不带端口时默认走 25 端口,没有 TLS 通道。用 465 或 587 端口的邮箱基本发不出去,实际可行的做法是配一个内网邮件中继,或者本机跑个 postfix 转发。
- 采集频率改不了。60 秒一轮是硬编码在主程序里的,配置文件里那个「刷新」参数控制的是前端图表的刷新周期,不是采集周期。
- 历史只留 10 天。三张表(Ping 记录、告警记录、地图记录)会按保留天数清理,默认 10 天。清理任务的触发是每小时整点——不是每天零点,因为定时用的是秒级表达式,第一位到第六位依次是秒、分、时、日、月、周。想要更长的历史,得自己改数据保留天数或做导出。
- 需要原始套接字权限。Ping 和 MTR 都是自己组 ICMP 包,Linux 下用 root 跑最省事,或者给二进制加网络原始套接字的能力;容器里则要显式加上对应权限,否则所有目标都是超时。
- Windows 用 NSSM 注册服务。发布包里直接带了 NSSM 可执行文件,Linux 侧是一个控制脚本,负责启动、停止、重启、编译和打包。
六、代码里两个值得一提的地方
翻实现的时候有两处让我停下来多看了几眼。
第一处是地图聚合里的一段过滤。作者显然想在求平均值之前剔除掉一部分「全丢包」的坏样本,最多丢四分之一。但那个判断条件用的是丢包率的数值等于 3,而丢包率在这个环节存的是百分比,取值只会是 0、33、67、100 —— 这个条件取不到 3,于是过滤实际上从来没有生效过,那些记为 2000 毫秒的兜底值会原样进入平均。结果是:只要某个探测点挂了,它所在省份那一格的延迟就会被拉高得很明显。对「看趋势」来说问题不大,但别把它当精确的平均延迟用。
第二处是 GitHub 的语言统计:这个项目的第一语言标的是 CSS,不是 Go。看过目录就明白了——七张页面加上 ECharts 的样式占了绝大部分代码量,Go 那部分只负责定时调度、ICMP 采集和一堆 API 接口,核心逻辑加起来不到十个文件。这也解释了它的界面为什么比同类工具耐看,而后端功能为什么相对克制:这是一个把力气花在「看得清」上的项目,不是一个把力气花在「算得细」上的项目。
七、适合谁,不适合谁
适合:
- 手上有几台分布在不同地区、不同运营商的机器,想在自己的机器之间看链路质量。装上去、互相加进列表,几分钟就有图了。
- 需要向人解释「为什么华东的用户慢」——互 Ping 拓扑那张图比一堆数字直观得多。
- 想找一个不依赖任何云服务、单文件部署、连数据库都不用另装的轻量方案。SQLite 是嵌在程序里的,整个目录拷走就能搬。
不适合:
- 要接 Prometheus、要发 Webhook、要做 SLA 报表。它没有这些出口,告警只有声音和邮件两条路。
- 要精确的长期历史数据。10 天保留、每分钟一条、聚合在浏览器里,这套组合是给「看当下」设计的。
- 只想监控一个网站能不能打开。这种事有更轻的工具。
- 完全不想碰命令行和配置文件。它的界面能改大部分东西,但互 Ping 关系、运营商 IP 表这些还是要落到配置里。
最后说个整体印象:SmartPing 是那种「设计取舍写得很诚实」的老项目。它承认自己轻量,所以不搞中心化;承认要长期开着,所以报警做了容忍和边沿触发;承认报警信息不够,所以绑了 MTR。它没有跟着这几年监控系统的主流路线走(时序库、标签、告警路由),而是把「多机房互看」这一件事做透了。对于正好需要这件事的人来说,它比一堆重量级方案更趁手。
本文根据项目公开仓库 smartping/smartping 的 README、配置模板与核心源码(主程序、告警判定、地图聚合、MTR 实现、归档清理)整理撰写。第一张配图为项目仓库自带的官方功能截图(图内节点名称为原图所有);其余三张均为依据源码与配置结构自绘,其中全国延迟矩阵一张为形态示意,格内数值非实测数据。文中星标数、许可协议、默认阈值与端口均为撰写时仓库所载,项目自 2020 年后未再发版,请以仓库当前状态为准。本文不含外链入口与推广内容。
本文整理自公开资料并做重写,原始出处:https://github.com/smartping/smartping。文中配图已去除站点叠加水印与推广信息;版权归原作者所有。



