分类: LINUX
2014-05-12 11:36:32
http://blog.csdn.net/turkeyzhou/article/details/7526081
本文讨论的udp丢包是指网卡接收到数据包后,linux内核的tcp/ip协议栈在udp数据包处理过程中的丢包,主要原因有两个:
1) udp数据包格式错误或校验和检查失败
2) 应用程序来不及处理udp数据包
对于原因1),udp数据包本身的错误很少见,应用程序也不可控,本文不讨论。
首先介绍通用的udp丢包检测方法,使用netstat命令,加-su参数。
# netstat -su
udp:
380408160 packets received
17 packets to unknown port received.
62314 packet receive errors
397718604 packets sent
从上面的输出中,可以看到有一行输出包含了"packet receive errors",如果每隔一段时间执行netstat -su,发现行首的数字不断变大,表明发生了udp丢包。
下面介绍一下udp丢包的常见原因:
1) linux内核socket缓冲区设的太小
通过 cat /proc/sys/net/core/rmem_default 和cat /proc/sys/net/core/rmem_max可以查看socket缓冲区的缺省值和最大值。rmem_default和rmem_max设置为多大合适呢?如果服务器的性能压力不大,对处理时延也没有很严格的要求,设置为1M左右即可。如果服务器的性能压力较大,或者对处理时延有很严格的要求,则必须谨慎设置rmem_default 和rmem_max,如果设得过小,会导致丢包,如果设得过大,会出现滚雪球。socket缓冲区设的过大导致滚雪球的问题,大家可以参考中的介绍,有定量的计算方法,分析得很深入。
2) 服务器负载过高,占用了大量cpu资源,无法及时处理linux内核socket缓冲区中的udp数据包,导致丢包
一般来说,服务器负载过高有两个原因:收到的udp包过多;服务器进程存在性能瓶颈。如果收到的udp包过多,就要考虑扩容了,从日常运营的经验来看,公司现有的B5机器,在业务逻辑不复杂(简单的打包解包和内存hash等操作)、不超过网卡流量限制的情况下,每秒可以处理25万个udp包。至于如何提高服务器的性能,属于高性能服务器的设计和实现范畴,功力有限,不敢在这里班门弄斧,自己平时使用最多也就是三板斧:top+strace+ltrace,先使用top查看cpu内核态时间和用户态时间的比例,如果内核态时间占大头,就用strace查看主要的系统调用有哪些;如果如果用户态时间占大头,就用ltrace查看主要的库函数调用有哪些。找到性能瓶颈后,想办法优化系统架构和业务逻辑,减少不必要的系统调用和库函数调用。从以往的经验来看,很容易犯的一个错误是调用不必要的memset或memcpy操作一大片内存,当请求量小的时候,发现不了问题,一旦突发的请求过来,触发大量的memset或memcpy操作,占用了cpu资源,导致丢包和滚雪球,让人措手不及,所以系统上线前,一定要做好压力测试,通过压力测试找出性能瓶颈,将危险消灭在萌芽状态。
3) 磁盘IO忙
服务器有大量IO操作,会导致进程阻塞,cpu都在等待磁盘IO,不能及时处理内核socket缓冲区中的udp数据包。如果业务本身就是IO密集型的,要考虑在架构上进行优化,合理使用缓存降低磁盘IO。这里有一个容易忽视的问题:很多服务器都有在本地磁盘记录日志的功能,由于运维误操作导致日志记录的级别过高,或者某些错误突然大量出现,使得往磁盘写日志的IO请求量很大,磁盘IO忙,导致udp丢包。对于运维误操作,可以加强运营环境的管理,防止出错。如果业务确实需要记录大量的日志,可以使用内存log或者远程log。
4) 物理内存不够用,出现swap交换
swap交换本质上也是一种磁盘IO忙,因为比较特殊,容易被忽视,所以单列出来。
只要规划好物理内存的使用,并且合理设置系统参数,可以避免这个问题。
5) 磁盘满导致无法IO
没有规划好磁盘的使用,监控不到位,导致磁盘被写满后服务器进程无法IO,处于阻塞状态。公司的监控中心对机器的磁盘使用率有监控,使用率超过95%会通知机器负责人处理。但是如果机器负责人错过了告警,或者没有及时处理告警,仍然会导致磁盘被写满。最根本的办法是规划好磁盘的使用,防止业务数据或日志文件把磁盘塞满,同时加强监控,例如开发一个通用的工具,当磁盘使用率达到80%时就持续告警,留出充足的反应时间。
wxbcrefut2015-10-22 17:46:21
wxbcrefut:谢谢楼主分享,最近也遇到这种问题,我在虚机里测试(配置为8核16G内存),1s接受2W条数据丢包就特别严重,我还没有处理只是接受而已,不知道问题出在哪,求指教
我是用java写的,代码大概如下:
//初始化udp
val socketAddress = new InetSocketAddress(\"192.168.1.161\", 9999)
val datagramSocket = new DatagramSocket(socketAddress)
datagramSocket.setSoTimeout(0)
datagramSocket.setReceiveBufferSize(8 * 1024)
&n
被截断了~~~~~ 加上
while (true) {
var buffer: Array[Byte] = new Array[Byte](500)
var packet: DatagramPacket = new DatagramPacket(buffer, buffer.length)
datagramSocket.receive(packet)
queue.put(packet)
}
wxbcrefut2015-10-22 15:33:11
谢谢楼主分享,最近也遇到这种问题,我在虚机里测试(配置为8核16G内存),1s接受2W条数据丢包就特别严重,我还没有处理只是接受而已,不知道问题出在哪,求指教
我是用java写的,代码大概如下:
//初始化udp
val socketAddress = new InetSocketAddress(\"192.168.1.161\", 9999)
val datagramSocket = new DatagramSocket(socketAddress)
datagramSocket.setSoTimeout(0)
datagramSocket.setReceiveBufferSize(8 * 1024)
&n