本篇文章3768字,读完约9分钟

Ulb4是ucloud基于dpdk独立开发的高可用性四层负载均衡产品,其转发能力接近线速。Dpdk是一个高性能的开源数据平面开发工具包。Ulb4是用户应用的全球门户,在大流量多样化的情况下,保证用户业务的持续稳定非常重要,这也是ucloud网络产品团队的技术使命。特别是现有网络中单个ulb集群的带宽已经达到10g,包容量为830,000 pps,运行环境复杂。即使面对不可预料的因素(比如引发未知的bug),我们也应该尽力保证产品的正常运行,避免严重的影响。

UCloud 生产环境中负载均衡产品DPDK问题的解决

最近,在ulb4的在线环境中,我们发现了dpdk的异常现象。由于整个ulb产品是一个集群架构,这种异常现象并没有导致用户服务不可用。但是,为了保证用户服务在任何时候都有足够的稳定性,团队通过gdb、消息导出工具、生产环境的流量镜像等手段,从现有网络的gb级流量中捕获异常消息。,然后结合dpdk源代码分析,定位并修复由dpdk本身引起的错误。在此期间,用户业务没有受到影响,这进一步确保了数以万计的u cloud ulb实例的稳定运行。

UCloud 生产环境中负载均衡产品DPDK问题的解决

本文将从问题现象入手,阐述问题定位、分析和解决的全过程,希望能为ulb用户和dpdk开发者提供参考和启示。

问题背景

12月初,一个稳定的ulb4集群突然出现容灾,一台ulb4服务器因运行异常被自动移出集群。当时的现象是:

转发平面服务监控网卡接收方向的流量正常,但发送方向的流量为0。转发平面服务重启后,可以正常收发,集群中的其他机器偶尔也会出现异常情况。对于用户服务,会有少量的连接轻微抖动,然后迅速恢复。

UCloud 生产环境中负载均衡产品DPDK问题的解决

下面是整个问题的处理过程。在这个过程中,我们做了各种尝试,最后结合dpdk源代码完成了分析和解决。在后续工作中,我们还准备开放源代码并分享自己开发的消息导出工具。

UCloud 生产环境中负载均衡产品DPDK问题的解决

问题定位和分析

ulb4集群一直在稳定地工作,突然集群中的不同机器上出现了一个又一个相同的问题。机器恢复加入群集后,同样的问题会在一段时间后再次出现。根据我们的运行经验,初步推测是一些异常消息触发了程序错误。然而,面对gb级的流量,如何捕捉异常消息?我们如何在不影响业务的情况下找出问题?

UCloud 生产环境中负载均衡产品DPDK问题的解决

一、广发银行调试消息,发现疑点

了解为什么整个程序没有外包的最好方法是进入程序来查看具体的执行过程。Gdb显然是dpdk用户模式程序的有用工具。我们在收缩程序的逻辑中设置断点,并通过反汇编命令检查这个函数的执行逻辑。拆卸后,有700多行。(在这个函数中调用的许多函数都是用inline来修饰的,这导致了汇编后的大量指令。(

UCloud 生产环境中负载均衡产品DPDK问题的解决

结合相应dpdk版本的源代码,一条指令被逐步执行。经过多次尝试,发现它每次都会直接返回下图所示的位置。

一般过程是i40e_xmit_pkts()在发现发送队列已满时调用i40e_xmit_cleanup()来清理队列。dpdk中的网卡在发送数据包后会写回一个特定的字段,指示消息已经发送,驱动程序可以通过查看该字段来知道消息是否已经发送。这里的问题是,驱动程序认为队列中的消息从未被网卡发送出去,后续的消息将不会加入队列并被直接丢弃。

UCloud 生产环境中负载均衡产品DPDK问题的解决

此时,已经找到了直接的原因,即网卡由于某种原因没有发送出数据包,或者没有正确地写回特定的字段,这导致驱动程序认为发送队列总是处于满状态,不能向发送队列添加后续消息。

UCloud 生产环境中负载均衡产品DPDK问题的解决

那么为什么队列已经满了呢?例外包是否相关?带着这个问题,我们做了第二次尝试。

第二,用一个按钮恢复网卡信息

队列已满,其后面的消息不能一直添加,这意味着队列中的消息一直被阻塞在那里。既然我们猜测可能有异常消息,那么异常消息是否仍在队列中?如果我们可以导出当前队列中的所有消息,我们就可以进一步验证我们的猜测。

UCloud 生产环境中负载均衡产品DPDK问题的解决

基于对dpdk的深入研究,我们按照以下步骤导出消息。

& # 65517;当我们查看i40e_xmit_pkts()函数时,我们会发现第一个参数是发送队列,因此我们可以获得队列的信息。

& # 65517;如下图所示,当断点刚刚进入时,检查寄存器信息以获得与函数对应的参数。

& # 65517;当我们打印这个队列中的消息时,我们发现没有符号信息。此时,我们可以加载编译期间生成的i40e_rxtx.o,如下图所示,以获取相应的符号信息。

UCloud 生产环境中负载均衡产品DPDK问题的解决

& # 65517;获得队列信息后,我们使用gdb的转储命令,按照队列中的顺序导出整个队列中的所有消息,并根据序列号给每个消息命名。

& # 65517;此时,导出的消息仍然是原始消息,因此我们无法使用wireshark方便地查看消息信息。因此,如下图所示,我们使用libpcap库编写了一个简单的小工具,将它转换成wireshark可以解析的pcap文件。

UCloud 生产环境中负载均衡产品DPDK问题的解决

果然,如下图所示,所有导出的消息都包含一个长度为26字节但全为零的消息。这条消息看起来很不正常,这似乎初步验证了我们的猜测:

为了在排除故障时提高导出消息的速度,我们编写了一个消息一键式导出工具,在出现异常时,可以一键导出所有消息,并将其转换为pcap格式。

在多次导出消息后,我们发现了一个规则:每次都会有一个长度为26字节但全为零的消息,并且在它前面会有一个长度相同的消息,并且每次源ip地址网段都来自同一个区域。

UCloud 生产环境中负载均衡产品DPDK问题的解决

第三,流量镜像,确认异常数据包

第二步的结论使整个调查向前迈进了一大步,但是队列包是由一系列程序处理的,这不是真正的原始业务消息。如果你不停止,直到你达到你的目标,你仍然需要去镜子捕捉包在关键时刻。因此,您紧急联系了网络运营和维护部门的同事,在当晚在交换机上配置端口镜像(port mirroring ),并将发送到ulb4群集的流量镜像到空空闲服务器以捕获数据包。当然,镜像服务器需要特殊配置,如下所示:

UCloud 生产环境中负载均衡产品DPDK问题的解决

1.将网卡混杂模式设置为收集镜像流量(ifconfig net 2 convertex)。

2.关闭gro函数(ethtool-knet2grooff),该函数用于收集最原始的消息,并防止linux的gro函数提前组装消息。

根据异常ip的地理特征,我们针对一些源ip段的流量。

参考命令:no hup tcpdump-inet 2-s0-w % y % m % d _ % h-% m-% s . pcap-g 1800 "原型创建(IP[54:4]&:0x 11223000)= 0x 11223000)或(IP[58:4]& amp;0x 11223000 = = 0x 11223000))”amp。

经过多次尝试,每一次努力都有回报,错误就出现了。经过层层剥离和筛选,发现以下信息:

这是一个ip片段消息,但奇怪的是第二个ip片段只有一个ip头。经过仔细比较,这两个消息合在一起就是导出队列消息中的两个相连的消息。最后26个字节与全零完全一致。

UCloud 生产环境中负载均衡产品DPDK问题的解决

我们知道,在tcp/ip协议中,如果一个ip消息的长度在传输过程中超过了mtu,它将触发ip分段,并被分割成几个小的分段消息进行传输。在正常情况下,所有切片都必须携带数据。然而,这种支离破碎的信息是不正常的。消息的总长度是20,这意味着只有一个ip报头,并且在它后面没有携带任何信息。这样的信息毫无意义。此消息在通过交换机后也用26字节的零填充,因为它的长度太短。

UCloud 生产环境中负载均衡产品DPDK问题的解决

至此,我们终于发现了这条异常消息,这基本上验证了我们的猜测。然而,有必要实际验证它是否是由这个异常消息引起的。(从整个消息的交互来看,这段消息最初被设置为不能分片的tcp消息,但是经过公共网络网关后,它被强制设置为允许分片,这种异常的分片形式出现了。(

UCloud 生产环境中负载均衡产品DPDK问题的解决

第四,解决方案

如果它确实是由这个异常消息引起的,那么只需要在收到数据包时检查这个异常消息并丢弃它。因此,我们修改dpdk程序并丢弃这些消息。作为验证,首先发布了一个在线服务器,经过一天的运行,没有出现异常的灾难恢复。现在问题的根本原因已经找到,正是这个异常消息导致dpdk工作异常,所以可以根据灰度在整个网络上发布。

UCloud 生产环境中负载均衡产品DPDK问题的解决

V.dpdk社区反馈

本着对开源社区负责的态度,我们准备好将bug同步到dpdk社区。在比较了最近的提交之后,我发现提交于11月6日,情况完全相同,如下所示:

IP _ frag:checkfragmentlongioffingpacket

在dpdk18.11的最新版本中,这一点已经得到了修正,这与我们的处理逻辑是一致的,并且异常消息也被丢弃。

审查和总结

在解决了所有问题后,我们开始重新报价。

一、ulb未能外包的原因概述

ulb4未能签约的整个生成过程如下:

1.dpdk接收片段消息中的第一个片段,并将其缓存以等待后续片段;

2.在第二段中,只有ip报头的异常片段到来,dpdk根据正常的消息处理逻辑对其进行处理,而不进行检查和丢弃,因此两段消息的rte_mbuf结构被链接在一起,形成一个链接的消息,并将其返回到ulb4;

UCloud 生产环境中负载均衡产品DPDK问题的解决

3.ulb4收到这样的消息后,ulb4直接调用dpdk的发送接口发送出去,因为整个消息的总长度没有达到需要分段的长度。

4.dpdk不检查该异常消息,而是直接调用相应的用户模式网卡驱动程序直接发送消息;

5.用户模式下的网卡驱动触发了网卡txhang当发送这种异常消息时;

6.触发txhang后,网卡不再工作,驱动队列中消息对应的发送描述符不再被网卡正确设置发送完成标志;

7.后续消息继续到达,开始在发送队列中累积,最后填满整个队列,当另一个消息到达时将被直接丢弃。

第二,为什么异常消息会触发网卡txhang

首先,让我们看看与在dpdk中发送消息的网卡相关的代码。

从上图可以看出,根据网卡的数据表正确设置相关字段是非常重要的。如果由于某种原因设置错误,可能会导致不可预知的后果(具体请参考网卡数据表)。

UCloud 生产环境中负载均衡产品DPDK问题的解决

如下图所示,对应的字段通常在对应网卡的数据表中描述,对应的数据结构一般在网卡驱动中对应。

在有了基本的了解之后,我们怀疑如果这种异常消息是直接在程序中手工构造的,会不会也导致网卡异常故障?

答案是肯定的。

如下图所示,我们使用这个代码片段形成一个异常消息,然后调用dpdk接口直接发送,很快网卡就会挂起。

第三,考虑硬件的直接操作

直接操作硬件是非常谨慎的。在传统的linux系统中,驱动程序通常处于内核状态,由内核管理,各种异常可以在驱动程序代码中处理,因此硬件很少会因为用户程序操作而无法工作。然而,由于其自身的用户驱动特性,dpdk可以在用户模式下直接操作硬件。同时,可以进行许多优化来提高性能。如果用户自己的程序处理问题,可能会导致网卡txhang的异常情况。

UCloud 生产环境中负载均衡产品DPDK问题的解决

第四,工具的价值

我们编写了一个一键导出dpdk驱动队列消息的工具,这样每次出现问题时,网卡驱动发送队列中的所有消息都可以快速导出,大大提高了故障排除的效率。在这个工具被优化后,它就可以在ucloudgithub上开源了,希望能帮助dpdk开发者。

UCloud 生产环境中负载均衡产品DPDK问题的解决

写在最后

作为一个开源套件,dpdk通常在稳定性和可靠性方面没有问题,但是实际的应用场景是不断变化的,一些特殊的情况可能会导致dpdk工作异常。虽然发生概率很小,但dpdk通常位于关键网关。一旦出现问题,即使是罕见的问题也会产生严重的影响。

UCloud 生产环境中负载均衡产品DPDK问题的解决

因此,技术团队了解其工作原理,分析其源代码,并结合具体现象逐步定位dpdk的问题,对提高整个dpdk程序的服务可靠性具有重要意义。值得一提的是,ulb4的高可用性集群架构在解决这一问题的过程中发挥了重要作用。当一台不可用时,群集中的其他机器可以继续向用户提供可靠的服务,这有效地提高了用户服务的可靠性。

UCloud 生产环境中负载均衡产品DPDK问题的解决

标题:UCloud 生产环境中负载均衡产品DPDK问题的解决

地址:http://www.hcsbodzyz.com/hcgy/2199.html