Linux中UDP服务丢包率过高排查思路
一、概述
在Centos7服务器中部署了基于Netty实现的UDP服务,用来采集日志。将数据发送到UDP服务端之后,没有复杂业务处理,直接写入本地的log文件中。经过监控分析,成功找出优化方案,将目标3000QPS每秒丢包率3%降至0.00002%,5000QPS也比较良好。
二、监控UDP消息每秒收发数据
1、使用 netstat -s -u 命令可以监控UDP服务统计信息
netstat -s -u命令,统计指标主要数据说明
- packets received:接收到的UDP数据包数量。
- packets to unknown port received:接收到未知端口的UDP数据包数量。
- packet receive errors:接收UDP数据包时发生的错误数量。
- packets sent:发送的UDP数据包数量。
- receive buffer errors:接收缓冲区错误的数量。
- send buffer errors:发送缓冲区错误的数量。
- InNoRoutes:无法路由的数据包数量。
- InMcastPkts:接收到的多播数据包数量。
- OutMcastPkts:发送的多播数据包数量。
- InBcastPkts:接收到的广播数据包数量。
- InOctets:接收到的总字节数。
- OutOctets:发送的总字节数。
- InBcastPkts:接收到的广播数据包数量。
主要关注packets received、acket receive errors、receive buffer errors三个指标
2、使用 netstat -uap 命令可以监控UDP服务统计信息
netstat -uap命令下的一些常见指标的含义:
- Proto: 表示网络协议类型,通常为UDP。
- Recv-Q: 表示接收队列的大小,即等待被应用程序读取的数据包数量。
- Send-Q: 表示发送队列的大小,即等待被网络发送的数据包数量
- Local Address: 表示本地地址和监听端口。
- Foreign Address: 表示远程地址和端口,如果有的话。
- State: 表示连接状态,对于UDP协议通常为"-".
- PID/Program name: 表示与该连接或监听端口相关联的进程ID和程序名称
基于业务,主要关注Recv-Q指标值来做分析
3、编写脚本记录每秒以上两种信息的变化
将netstat -s -u、netstat -uap命令返回监控信息保存到文本中,每秒保存一次
- 使用vi xx.sh命令创建脚本
#!/bin/bash
step=1
for (( i = 0; i < 60; i = (i+step) )); do
echo "$(date) $(netstat -uap)" >> /opt/udpSocket.txt
sleep $step
done
exit 0
#!/bin/bash
step=1
for (( i = 0; i < 60; i = (i+step) )); do
echo "$(date) $(netstat -s -u)" >> /opt/1.output.txt
sleep $step
done
exit 0
- 使用crontab -e 创建定时任务
* * * * * sh /opt/test.sh
* * * * * sh /opt/test1.sh
4、使用Jmeter进行UDP端口压测
三、分析保存的监控指标数据
-
将两个监控数据文件中,时间和packet receive errors、时间和Recv-Q进行分析,计算丢包数在发送样本的占比
-
使用Excel对两份数据建立数据透视图
-
packet receive errors指标错误数和receive buffer errors错误数一致,且发送条数减去日志文件写入条数等于packet receive errors错误数,初步得出结论缓冲区错误是丢包率过高的主要原因。
-
分析Recv-Q指标,数值持续保持峰值,很少有为0的时候,说明应用来不及读取接收缓冲区中的数据,接收缓冲区一直是满着的状态,更加证明Linux内核中默认socket接收缓冲区最大值满足不了当前的并发情况,需要增加缓冲区大小。
四、解决方案
- 增加用户态应用程序处理能力,使用零拷贝、IO多路复用、多线程绑定一个端口、增加应用程序UDP服务端中接收缓冲区的大小等措施。(例:【基于Netty实现Epoll机制的UDP接收服务】)
- 修改内核参数,增加内核层面接收缓冲区的大小。
(1). 使用sysctl net.core.rmem_default、sysctl net.core.rmem_max命令查看系统内核中套接字接收缓冲区默认大小
(2).临时有效方式:使用sysctl -w net.core.rmem_default=1048576、sysctl -w net.core.rmem_max=1048576命令修改接收缓冲区大小改为1MB
(3).永久有效方式:
打开终端,并使用 root 或具有管理员权限的用户登录。
编辑 /etc/sysctl.conf 文件,可以使用任何文本编辑器打开该文件。
在文件的末尾添加以下行来设置接收缓冲区大小:
net.core.rmem_default = <new_size>
net.core.rmem_max = <new_size>
其中,<new_size> 是你想要设置的新的接收缓冲区大小。
保存并关闭文件。
运行以下命令以使更改生效:
sudo sysctl -p
这将重新加载 /etc/sysctl.conf 文件中的配置,并使更改生效。
- 重新压测,计算丢包率。如果数据不理想,重复分析packet receive errors、和Recv-Q指标,分析Recv-Q指标每秒分布情况,看接收缓冲区是否够用。
五、内核中接收缓冲区大小的影响范围分析
使用netstat -anp 命令查看内核中接收缓冲区的个数,每个TCP、UDP都会有对应的一个接收缓冲区,假如应用程序中有使用tomcat,则内存使用范围在tomcat200最大线程 * 1MB+其他运行线程 *1MB,以本地虚拟机为例,默认有21个接收缓冲区,再加上tomcat的默认最大200线程,内核中接收缓冲区内存占用在200多MB。对其他业务影响不大。