文
章
目
录
章
目
录
在负责NTA(Network Traffic Analysis,网络流量分析)基础建设工作的近两年时间里,我遇到了不少棘手的问题,其中网络组件丢包问题尤为突出。最近刚好又碰到排查丢包问题的需求,借着这个机会,我把这两年积累的经验做个总结,分享给大家,希望能帮到正在处理类似问题的小伙伴们。
一、丢包问题的“出场背景”
我目前主要负责NTA相关的基础建设工作,用到的组件有zeek、suricata和arkime。在实际使用过程中,丢包问题频繁出现。我们的网络流量比较大,每个集群的流量能达到30 Gbps,单台服务器的流量也有1.2 Gbps ,而且服务器上要同时运行多个组件。在这样的情况下,以下几种场景都存在丢包现象:
- 组件重启的时候会丢包;
- 流量突然增加时丢包;
- 流量持续过大,也会丢包;
- 遇到特殊流量时,不仅持续丢包,丢包率还一直降不下来。
二、抽丝剥茧:丢包分析全过程
- 梳理资产,锁定“嫌疑对象”:要想找到丢包的根源,得先把NTA涉及的资产梳理清楚。整个资产梳理的思路是从数据源开始,接着是网卡、数据包捕获框架,最后到应用程序。
- 数据源:这里需要关注数据包的封装协议、流量组成、流量大小以及包速率。这些因素都有可能影响网络传输,进而导致丢包。
- 网卡:重点查看网卡的丢包情况,还有RSS(Receive Side Scaling,接收端缩放)队列的状态。
- 数据包捕获框架:我们用的是PF_RING这个开源的高性能数据包捕获和传输框架,它能减少数据包复制次数,降低CPU开销。除此之外,还得了解它的工作原理,像传统模式、AF_Packet、PF_RING各自的特点。
- 应用程序:看看服务器上是运行单套还是多套应用程序,是多进程还是多线程模式,以及数据包的负载均衡模式是怎样的。
- 打造监控报表,掌握“一手情报”:这一步非常关键。只有搜集尽可能多的指标数据,创建监控报表,才能更直观地发现问题,做出准确判断。我用的是Prometheus和Grafana来搭建监控系统,当然,像InfluxDB2这样的时序数据库也是不错的选择。我重点搜集的监控指标有这些:
- 流量:包括流入和流出的流量大小,这能直观反映网络的繁忙程度。
- 包速率:也就是数据包传输的速度,这个指标对判断网络是否稳定很重要。
- 包数据:涵盖丢包数据、接收包数据、空闲数据包缓冲区数据,还有预设的数据包缓冲区数据(我们用的是PF_RING数据)。
- 性能数据:细化到每个进程的CPU使用率和内存使用率,了解应用程序对系统资源的占用情况。
- 多层面深度分析,查找“真凶”
- 数据源层面:这个层面和数据包捕获框架、应用配置关系紧密,先暂时放一放,后面详细说。
- 网卡层面:我们的流量是从云平台镜像过来的,所以重点关注RX侧参数。这里主要查看几个关键指标:
- errors:表示接收错误数,比如CRC校验失败的次数,如果这个数值增加,说明可能存在数据传输错误。
- dropped:指因缓冲区不足导致丢弃的包数量,这和丢包直接相关。
- overruns:是因硬件无法及时处理数据包,导致接收缓冲区溢出的次数。经过检查,我们发现这部分一切正常。
- 数据包捕获框架层面(PF_RING):我们使用的PF_RING框架在数据包传输上有独特优势,相比传统路径,它减少了数据包复制次数。传统模式下,数据包从网卡到用户空间应用,要经过内核缓冲区和Socket缓冲区,会有2 – 3次复制;而PF_RING只需要1次复制,甚至在特定模式(PF_RING zC)下可以实现0复制。
- RSS功能:RSS是一种网络I/O优化技术,PF_RING也实现了这个功能。按照PF_RING官方的说法,它可以设置多个RX队列,默认会根据数据包的五元组(源IP、目的IP、源端口、目的端口、协议)将数据包平均分配到不同队列,实现负载均衡。可以用ethtool工具来设置这个功能。不过,因为我们用的是云主机,RSS队列是云平台预设的,没办法用ethtool根据CPU核心数量调整参数,所以这部分我没有深入测试分析。大家要是感兴趣,可以去PF_RING官方文档(https://www.ntop.org/guides/pf_ring/rss.html)看看。
- PF_RING各项参数说明:先给大家看看几个有代表性的图。
这里面有很多参数,我们重点关注下面这些:
- Slot相关参数:
- Ring slots:代表环形缓冲区的总容量,也就是理论上最大的插槽数。
- Min Num Slots:是实际预分配的插槽数,这个数值会根据内存和性能优化情况动态调整。
- Num Free Slots:表示空闲的插槽数。
- Tot相关参数:
- Tot Packets:指捕获的总数据包数。
- Tot Pkt Lost:是丢弃的总数据包数。
- Tot Insert:是成功插入环形缓冲区的数据包总数。
- Tot Read:是应用程序从环形缓冲区成功读取的数据包总数。
了解这些参数后,分析问题就有方向了。比如,通过对比不同情况下的参数,我们可以发现: - Num Free Slots < Min Num Slots:说明数据包有积压,可能是流量突然增加,或者应用程序性能不够,需要持续观察。
- Num Free Slots = 0 AND Tot Pkt Lost > 0:这就表明存在丢包情况,原因是缓冲区不够,而且应用程序性能也不足。这种情况下,需要马上增加Slots数量,还要给应用程序分配更多的CPU核心。对于流量突增和应用程序重启时的丢包问题,适当调大Slots能有效缓解。
- Tot Read < Tot Insert:意味着应用程序读包的速度跟不上数据包插入的速度,也就是应用程序性能不足,需要增加应用程序的CPU核心数量。
- Tot Read ≈ 0 OR在某个值处变化很慢:大概率是应用程序卡死了,需要重启应用程序。
- Slot相关参数:
- 应用程序层面“大揭秘”:在前面几个层面发现问题并调整后,还是有大量丢包现象,尤其是某种镜像源的流量。继续深挖,又发现了两个问题:
- 流量的负载均衡:zeek和suricata都可以配置多个CPU核心(多进程/线程模式),还能选择不同的PF_RING模式来解析数据包。但arkime虽然使用多线程,从数据包捕获框架角度看,只用到了1个进程。所以我们重点分析zeek和suricata。
- 流量大小和包速率:在我们的场景中,单台服务器接收的流量最高能达到3.8 Gbps,部分流量还会突然增加。不同的包速率和流量大小,丢包情况也不一样,不过这个层面相对容易理解,就不深入分析了。
- 数据包封装协议:这部分比较复杂。按照封装协议来分,有3种情况:无封装、VXLAN封装、GENEVE + VXLAN双层封装。
- 无封装的流量,可以使用五元组模式处理。
- VXLAN封装的流量,能采用内部五元组模式。
- GENEVE + VXLAN双层封装就麻烦了,PF_RING本身不支持GENEVE协议解封。因为业务的特殊需求,同一笔FLOW的请求包和响应包会通过GENEVE封装在两个不同的来源IP上,再用VXLAN封装,这样就找不到合适的PF_RING模式了。不过,有厉害的小伙伴通过修改PF_RING源码,实现了GENEVE解封,这样就能用内部五元组模式解决问题。但还是有部分服务器上的流量无法实现负载均衡,这时候就得考虑流量组成了。
- 流量组成:通过抓包观察,发现有些流量源同时包含定期高频长链接流量和随机流量,这就导致原始无封装流量不均衡。这种情况比较少见,是由业务类型决定的。如果条件允许,可以考虑拆分流量,比如设置过滤规则,或者把一台大流量的镜像源分给多台流量镜像目标。
- 应用程序性能:我们的单台服务器上会跑多个应用程序,在保证成本不变甚至降低的前提下,还要保证NTA有高质量的产出,这就得考虑每个应用程序自身的性能消耗了。这会涉及很多因素,像不同云平台的配置、服务器自身配置、加载的规则数量和复杂程度等。虽然我没有详细的数据,但在我们当前环境下,观察单台服务器的丢包率,发现性能消耗从高到低依次是:Zeek > Suricata > Arkime 。所以,我们给Zeek分配了更多的CPU核心,结果真的帮我们节约了不少成本。
- 流量的负载均衡:zeek和suricata都可以配置多个CPU核心(多进程/线程模式),还能选择不同的PF_RING模式来解析数据包。但arkime虽然使用多线程,从数据包捕获框架角度看,只用到了1个进程。所以我们重点分析zeek和suricata。
三、“对症下药”:丢包问题解决方案汇总
- 组件重启丢包:可能是应用程序性能不足。可以按照流量大小和应用程序性能消耗情况,合理分配CPU核心数。
- 突增流量丢包:原因可能是PF_RING缓冲区不够。可以增加PF_RING Slots数量,或者把单镜像源分配给多个镜像目标,拆分流量。
- 流量增长丢包:原始流量负载不均是常见原因。可以通过流量过滤规则,按照业务类型拆分流量。
- 特殊流量持续丢包:如果是因为PF_RING解析封装协议失败(比如GENEVE协议),可以对PF_RING进行二次开发。
在处理高性能网络分析组件丢包问题的过程中,需要从多个方面进行排查和分析。每个层面的因素都可能相互影响,只有全面考虑,才能找到最有效的解决方案。希望我的这些经验能给大家提供一些参考,要是你们在实际工作中还有其他好的方法,欢迎一起交流!