Redis/Codis性能瓶颈揭秘:网卡软中断的影响与优化

目录

现象回顾

问题剖析

现场分析

解决方案

总结与反思

[1.调整中断亲和性(IRQ Affinity):](#1.调整中断亲和性(IRQ Affinity):)

[2.RPS(Receive Packet Steering)和 RFS(Receive Flow Steering):](#2.RPS(Receive Packet Steering)和 RFS(Receive Flow Steering):)


近期,我们的一位客户在生产环境中遭遇了广告业务访问超时的问题,尤其是在晚间高峰时段,这严重影响了业务运行。尽管客户经过一整天的努力,仍未能定位问题的根本原因,因此向我们寻求协助。通过我们的共同努力和深入分析,我们最终锁定了性能瓶颈------网卡软中断。现在,让我们一同回顾这次解决性能挑战的全过程。

现象回顾

在晚高峰期间,广告业务相关接口大量超时,服务日志中频繁出现访问Codis超时的错误记录。服务访问Codis的超时时间设定为200毫秒,但在问题时段,这一时间限制被频频突破。

问题剖析

通过监控数据,发现出问题时Codis的QPS(每秒请求数)明显降低,而连接数却显著上升。连接数增加可能有两方面原因:一是访问Codis的时延增大,导致业务连接池中的连接不够用,需要新建连接;二是业务流量突增,导致访问Codis的量变大,连接数不足,同样需要新建连接。然而,从QPS的监控数据来看,并没有出现QPS增长的趋势,因此可以排除业务流量突增的原因。

进一步分析发现,问题主要集中在IP为192.168.16.77的服务器上。这台服务器上的Codis-server(Redis)响应时间明显增加,达到了十几到二十毫秒,并且该服务器的内存使用也有明显上升。猜测此次事故可能与该服务器或网络层面有关。

然而,在检查服务器和网络层面的监控后,并未发现明显异常。同时,查看了该服务器上的Codis日志和系统日志,也均未发现异常记录。由于Codis的slowlog已被冲掉,无法确定问题发生时是否存在慢查询。此外,虽然业务服务日志中记录的超时Key都不是大Key,但仍然不能排除大Key对性能的影响

现场分析

在第二天晚高峰时段,问题再次出现。我们立即登录到服务器上执行top命令,发现软中断分布极不均衡,个别CPU上的软中断占用率已高达80%以上。这导致与Codis发生CPU争抢,使得Codis CPU使用率打满,响应时间大幅增加。

解决方案

迅速执行了均衡网卡软中断的脚本,将软中断均匀分布到各个CPU上,执行后,业务响应时间迅速恢复正常。

总结与反思

1.正常情况下,客户Redis和Codis服务器都会执行均衡网卡软中断的脚本。但在此次事件中,客户生产环境遗漏了对该服务器的操作。同时,由于之前业务量较小,即使存在软中断问题,也未达到性能瓶颈。因此,这个问题在之前并未暴露出来。

2.为了避免类似问题的再次发生,客户在监控系统中增加了软中断相关指标,并设置了阈值告警通知。

3.总结影响Redis性能的关键因素,为后续性能问题分析提供思路:

4.网卡软中断:

软中断是Linux内核处理网络数据包的重要机制。与硬中断相比,其优先级较低,主要用于处理耗时的网络数据包接收和发送任务。在网络硬件接收到数据包后,会先通过硬件中断将数据放入队列,随后由软中断进行处理。

在Redis服务器上,若遇到高网络负载,某个CPU的软中断占用率过高可能会影响系统整体性能。因此,均衡网卡软中断的负载对系统性能至关重要。软中断允许Linux内核在非抢占式环境中处理异步事件,如网络数据包的收发。当网卡接收到数据包,它会通过软中断信号通知CPU进行处理,包括数据复制、网络统计信息更新等操作。若网络流量大或处理效率不高,软中断可能会大量占用CPU资源,导致使用率显著上升。

因此,合理地均衡网卡软中断的负载是非常重要的,以下是两种常用均衡网卡软中断的方法,客户这里是采用了irqbalance服务自动调整中断亲和性,并使用第二种方式进行软中断均衡优化:

1.调整中断亲和性(IRQ Affinity)

可以通过调整中断亲和性,将中断处理分配到多个CPU上。可以使用irqbalance服务自动调整中断亲和性,或者手动设置/proc/irq/<irq号 /smp_affinity文件来指定中断处理的CPU。

/proc/interrupts文件在Linux系统中提供了有关中断(IRQ)的详细信息。这个文件的内容通常包括以下信息:

  • **中断编号:**每一行的开头是中断的编号(或名称),例如 0, 1, 2,或 LOC(本地中断),NMI(非屏蔽中断)等。

  • **CPU列:**接下来的几列显示每个CPU核处理该中断的次数。每个列对应一个CPU核,显示该核处理该中断的计数。这些计数器可以帮助你了解中断在不同CPU核之间的分布情况。

  • 中断类型:有时会有一个标识符来表示中断类型,比如 IR-IO-APIC 或 PCI-MSI,这表示中断的来源或类型。

  • **中断名称或设备:**最后一列通常显示与中断相关的设备或驱动程序名称。这可以帮助你识别哪个设备或驱动程序正在使用该中断。

例如,以下是一个典型的 /proc/interrupts 文件的输出示例:

复制代码
           CPU0       CPU1       CPU2       CPU3  0:         66          0          0          0   IO-APIC-edge      timer  1:          2          0          0          0   IO-APIC-edge      i8042  8:          1          0          0          0   IO-APIC-edge      rtc0  9:          0          0          0          0   IO-APIC-fasteoi   acpi 16:        123          0          0          0   IO-APIC-fasteoi   ehci_hcd:usb1 23:       4567          0          0          0   IO-APIC-fasteoi   eth0

此codis服务器16.77信息如下,网卡对应的中断号为86,87,88,89;采用irqbalance服务自动调整亲和性,分别使用CPU8,CPU10,CPU12,CPU14。

2. RPS (Receive Packet Steering)和 RFS(Receive Flow Steering)

RPS和RFS是Linux内核提供的机制,用于将网络数据包的处理分配到多个CPU上。可以在/proc/sys/net/core/rps_sock_flow_entries/sys/class/net//queues/rx-/rps_cpus以及/sys/class/net//queues/rx-/rps_flow_cnt中进行配置。

比如40核服务器设置如下:

复制代码
echo ff,ffffffff > /sys/class/net/<interface>/queues/rx-<n>/rps_cpusecho 4096 > /sys/class/net/<interface>/queues/rx-<n>/rps_flow_cntecho 131072 > /proc/sys/net/core/rps_sock_flow_entries其中:rps_cpus是一个位掩码,表示允许使用的CPU核,ff,ffffffff则表示40核全部允许使用rps_flow_cnt表示当前网络设备rps队列的流表数,需要设置为2的整数次幂,建议设置为4096,数值越大,同时所能处理的rps流越多。131072为4096*接收队列的数量

****************************************************************************************************

点开看看就知道了:DBdoctor-数据库性能诊断

相关推荐
2601_9638699512 小时前
【计算机毕业设计】基于 Spring Boot+Vue的手工体验馆管理系统的设计与实现
java·spring boot·后端
曹牧12 小时前
Java:BeanListHandler
java·数据库·oracle
ITenderL14 小时前
MySQL联合索引遇到范围查询
数据库·索引
白鸽(二般)19 小时前
MinIO Java Client API
java·开发语言
敲个大西瓜19 小时前
Redis一百道核心面试题
数据库·redis·缓存
阿里云大数据AI技术20 小时前
EMR Serverless Spark AI Function 的双维降本实践
人工智能·sql·spark
软萌萌的120 小时前
Java Spring Boot 修改yml配置&加载顺序规则
java·spring boot·python
IT小盘20 小时前
13-企业Prompt模板-角色任务约束与输出格式
java·前端·prompt
爱敲键盘的猴子20 小时前
Java并发编程 -- volatile
java·java并发
plainGeekDev1 天前
工厂模式 → Hilt
android·java·kotlin