背景
有段时间某台服务器的网络质量总是不太好,由于缺少持续的监测,报障的时候也没办法给出具体影响时间。虽然已经有类似 zabbix 等等的现成监测工具,但是生命在于折腾。
结构设计
总体结构的设计与微软的 Pingmesh 很类似。基本分为三个部分:
控制
负责给探测部分下达控制命令,诸如被探测的地址,Ping 超时时间,Ping间隔等参数。
探测
根据控制器给出的参数进行探测。由于网络质量受到各种各样的因素影响,探测器应该布置在尽可能多的地方,尽可能的去收集信息
分析
对数据进行聚合分析,诸如计算平均Rtt,丢包率等等。
控制部分和探测部分保持长连接,以便支持动态的指令下发,实现丢包告警触发 MTR 信息采集等功能。
探测部分对探测器所在的设备的影响应该尽可能的小,一个是如果设备上没有其他的服务,最少的资源占用可以探测尽可能多的信息;另外是如果设备上有其他服务,探测器应该尽可能少的影响其他服务的运行。所以探测部分几乎完全不对探测到的原始数据做任何的处理,直接上报给分析模块处理。又因为相对于网络探测的方法而言,分析数据的方法迭代速度要快得多,而分散布置的探测器更新非常困难。
Mini版实现
Mini版只实现了持续通过 ping 探测网络 Rtt 及丢包率。探测模块只在 Linux 上测试。
控制及分析
这部分与业务模型及需求有强关联,讨论价值不高也不过多赘述。这两部分我使用 Go 语言实现,为了方便,我把他们实现在了一起,同时数据存储部分也用了同一个数据库。监测信息存储当然也可以使用 Prometheus 之类的专门工具,但目前我的需求里,数据量没有这么大,放到 PGSQL 里也没有太大的问题。
探测
出于安全性,性能,最小化资源占用的考虑,我选择使用 Rust 语言实现。
想要发 Ping 包,需要通过 ip raw socket 或者是 icmp socket 。 ip raw socket 需要 root 权限,自行构造数据包,并且内核会将收到的每一个协议号与 socket 绑定的协议号相同的数据包都送给 socket 。而 icmp socket 不需要root权限,但目前只能发送 icmp echo 及 code 为 0 的包,内核会负责填写 id ,计算 checksum ,并且会自动 bind 。相当于内核已经帮我们完成了 request 和 reply 的配对工作。
于是大致上可以分为下面几种实现思路。
- 使用 icmp socket ,阻塞多线程,每个线程负责一个 socket。
- 使用 raw socket,阻塞多线程,两个线程一发一收。
- 使用 icmp socket + epoll 等 IO 多路复用技术,非阻塞单线程或线程池。
第一种方案中基本上一个线程的生存时间不到 1s,当被探测的地址很多的时候,会产生大量的开销。
第二种方案中当设备也被大量 ping 的时候,收线程会收到大量的无用的数据,进行大量无用的判断,做许多无用功。同时,为了配对 request 及 reply,计算 Rtt,处理超时等问题,需要在线程之间传递大量的状态,虽然有 channel 等高级封装,虽然 Rust 可以在编译期检查出数据竞争问题,但仍然免不了诸如锁等令人头疼的问题。也是由于 Rust 的所有权系统,使得整个开发过程中并不令人愉快。尝试后最终还是放弃了这条路线。
第三种方案也是我最后选择的方案。得益于 Rust 下的异步生态非常活跃,Rust 自身的异步编程模型也非常漂亮,逻辑非常清晰。async/await 写起来就像是在写同步的逻辑。但也有个大坑。目前 tokio 中没有支持 icmp socket,需要基于 mio 及 socket2 进行封装,可以参考 这篇文章 ,tokio 社区有 issue 在讨论对 icmp 包及 raw ip 包的收发支持问题,但是目前没有看到清晰的支持路线。
最终实现的结构如图,探测器内部分为:控制、探测、上报,三部分。每个模块之间通过 channel 进行通信。目前只实现了 Ping 探测、上报、控制部分,其他部分日后实现时也很方便,如果对二进制文件大小有极致要求的设备也可以很方便的通过条件编译控制需要编译的探测模块数量,最终控制编译产品的大小。
性能上,由于功能还非常的弱鸡,程序并没有到开始优化性能的时候,实现上也没有太关注性能,也没有进行极限的性能测试,但得益于 Rust 自身的优势及 epoll 加成,目前的性能并不差。目前的数据是在一台1C的云主机上进行约 2万次 ping 并上报数据,大约需要 0:05-0:10 的CPU TIME。
数据展示
展示及告警部分选择了 Grafana ,几乎就是最好的选择。简单配置后它就可以从数据库拉出数据进行展示。同时也可以进行各种聚合操作。
结束
由于网络上关于 icmp socket 相关的资料数量非常的少,实现这个东西的时候做很多的实验, 查了很多资料,最终搭出来了一个算是能用的东西。
希望这篇流水账能让大家在折腾 icmp 相关内容的时候少走一些坑。
接下来丢包告警触发MTR功能实现后,下一步考虑继续优化探测程序的抗打击能力,使其能轻松面对弱网情况下,控制中断,上报中断的场景。
再下一步就考虑优化性能。
文章评论