某产品采用微服务架构,而其中的一个 ping 微服务归我负责。
这个程序的功能很简单,提供一个 REST API,调用者把一些 IP 或域名还有一些其他必要的信息通过 JSON 的格式发给程序,程序通过发送、接收 ICMP 报文进行 ping 操作,将结果(RTT 等)返回给调用者。
它的问题在于,得到的 RTT 有时会明显比正常的值大一些。例如,客户拿自己电脑 ping 一个机器,得到 30 ms,但 ping 服务返回的 RTT 是 1029 ms。所以,在界面上,我们只给客户显示一个设备是否 ping 通,而不显示 RTT。
经过分析,问题出现在 ping 服务的实现上。在最开始,它的实现方式如下:
先在用户态记下一个时刻 t1,然后发送 ICMP,然后接收 ICMP,然后在用户态记下一个时刻 t2,求得 t1 和 t2 的差 dt,就得到 RTT。
这样做的问题在于,dt 并非真正的 RTT,而是真正的 RTT 加上用户态与内核态复制数据的时间,而且多出来的这段时间会随着所在机器的压力的增大而增大。
上司决定改进它。
我采取了两个独立的方案。
一是把 Linux 的 ping 程序(开源)的代码拿出来,提取出相关的部分,塞到我的程序中。Linux 自带的 ping 是可以获取到真实的 RTT的。尽管这样获取到的结果也会随着机器压力的增大而稍稍增大,但这是由计算机本身的特性决定的,任何程序都这样,而且,这样的差异程度是可以向客户解释的(就说这个机器负载压力大即可,还可以 SSH 到这个机器上让客户“眼见为实”)。
一是使用 DPDK。这样获取到的 RTT 更精确,但:
1)开发代价过大(相对这个功能而言),得不偿失;
2)有的客户用的服务器的 CPU 不是 Intel 的(DPDK 要求 Intel CPU);
3)上一种方案已经可以得到可解释的结果。
权衡一下,我采用第一种办法。
这样一来,产品界面就可以直接把 RTT 数值显示出来了。