Chinaunix首页 | 论坛 | 博客
  • 博客访问: 480584
  • 博文数量: 53
  • 博客积分: 492
  • 博客等级: 下士
  • 技术积分: 866
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-14 15:12
文章分类

全部博文(53)

文章存档

2016年(1)

2015年(3)

2014年(17)

2013年(9)

2012年(7)

2011年(16)

我的朋友

分类: 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_defaultrmem_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查看主要的库函数调用有哪些。找到性能瓶颈后,想办法优化系统架构和业务逻辑,减少不必要的系统调用和库函数调用。从以往的经验来看,很容易犯的一个错误是调用不必要的memsetmemcpy操作一大片内存,当请求量小的时候,发现不了问题,一旦突发的请求过来,触发大量的memsetmemcpy操作,占用了cpu资源,导致丢包和滚雪球,让人措手不及,所以系统上线前,一定要做好压力测试,通过压力测试找出性能瓶颈,将危险消灭在萌芽状态。

 

3)        磁盘IO

    服务器有大量IO操作,会导致进程阻塞,cpu都在等待磁盘IO,不能及时处理内核socket缓冲区中的udp数据包。如果业务本身就是IO密集型的,要考虑在架构上进行优化,合理使用缓存降低磁盘IO。这里有一个容易忽视的问题:很多服务器都有在本地磁盘记录日志的功能,由于运维误操作导致日志记录的级别过高,或者某些错误突然大量出现,使得往磁盘写日志的IO请求量很大,磁盘IO忙,导致udp丢包。对于运维误操作,可以加强运营环境的管理,防止出错。如果业务确实需要记录大量的日志,可以使用内存log或者远程log

   

4)        物理内存不够用,出现swap交换

swap交换本质上也是一种磁盘IO忙,因为比较特殊,容易被忽视,所以单列出来。

    只要规划好物理内存的使用,并且合理设置系统参数,可以避免这个问题。

 

5)        磁盘满导致无法IO

    没有规划好磁盘的使用,监控不到位,导致磁盘被写满后服务器进程无法IO,处于阻塞状态。公司的监控中心对机器的磁盘使用率有监控,使用率超过95%会通知机器负责人处理。但是如果机器负责人错过了告警,或者没有及时处理告警,仍然会导致磁盘被写满。最根本的办法是规划好磁盘的使用,防止业务数据或日志文件把磁盘塞满,同时加强监控,例如开发一个通用的工具,当磁盘使用率达到80%时就持续告警,留出充足的反应时间。

阅读(5541) | 评论(2) | 转发(1) |
给主人留下些什么吧!~~

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