最近我们的集群业务量增加了3T/天。然后发现集群的cpu使用率和load上升的非常高,load最高达到了60。团队分析了性能原因,发现发送结果数据到另一个集群的逻辑消耗了大部分的cpu,于是对这部分发送逻辑进行了优化。
在优化发送逻辑后,cpu下降了一半,load也下降了。但是效果并不明显。有一个机器,load仍然很高。持续的调查发现,在load较高的机器上出现间隔出现多个modprob -q — net-pf-10进程(其中net-pf-10为ipv6模块的别名),行为上似乎在不断的重新加载ipv6模块,但是由于32内核机器modprobe.d中配置了disable_ipv6,因此该模块是被禁止,所以每次加载都无法成功。
对于modprob应该是网络链接访问过程中尝试解析ip地址,涉及网络通信的只有调用libcurl访问存储集群。而且大量modprobe进程的出现与写存储的qps的变化大致吻合。由此怀疑libcurl初始化时会尝试用IPv4和IPv6两种协议对地址解析并在IPv6模块未加载的情况下初始化时会增加额外的延时(大概5-8ms),modprobe命令或许是由于libcurl触发产生。
对比libcurl解析ip地址的代码,调用ioctl(dummy, SIOCGIFADDR, &req)函数对地址进行解析,该函数在判断ipv6模块已经安装的情况下加载相关模块,会触发内核在workqueue中加入modprobe任务尝试加载相关模块,因此在每次curl的调用都会导致modprobe调用产生。这种情形发生在安装了ipv6,但是ipv6被禁止的机器上。而在未安装ipv6的机器,并不存在这个问题。
最终的结论是,libcurl存在一个bug,如果机器安装了ipv6,而且禁止了ipv6,那么libcurl每次调用都会尝试加载ipv6。而这个加载的过程延时非常高,以至于引发了性能问题。