udp丢包
2012-05-01 17:41:02 turkeyzhou 阅读数 14825
  • TCP/IP/UDP Socket通讯开发实战 适合iOS/Android/...

    本课程适合中学员,适用于从事iOS/Android/嵌入式Linux网络通讯开发的学员。实战案例可用于无人机,安防,直播等。从Linux音频,视频采集,到TCP/IP UDP Socket基础概念,网络编程接口介绍,POSIX线程封装,私有协议定义,开发,服务器模型,客户端编程等详细实战讲解,整个过程,涵盖iOS,Android ,Mac OS嵌入式Linux网络编程核心的大量实用场景。让学员能够掌握相关知识,融汇贯通掌握网络通讯开发核心知识。 付费学员加入QQ群,可获得本人未来1~3年学习过程中的专业指导解答。第三节课第7分15秒有QQ群,欢迎付费学员加入探讨技术问题。

    14898 人正在学习 去看看 陈超

本文讨论的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缓冲区设的过大导致滚雪球的问题,大家可以参考http://km.oa.com/user/bisonliao/articles/show/75674中的介绍,有定量的计算方法,分析得很深入。

 

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%时就持续告警,留出充足的反应时间。

2017-03-20 10:07:14 wcg19921010 阅读数 6580
  • TCP/IP/UDP Socket通讯开发实战 适合iOS/Android/...

    本课程适合中学员,适用于从事iOS/Android/嵌入式Linux网络通讯开发的学员。实战案例可用于无人机,安防,直播等。从Linux音频,视频采集,到TCP/IP UDP Socket基础概念,网络编程接口介绍,POSIX线程封装,私有协议定义,开发,服务器模型,客户端编程等详细实战讲解,整个过程,涵盖iOS,Android ,Mac OS嵌入式Linux网络编程核心的大量实用场景。让学员能够掌握相关知识,融汇贯通掌握网络通讯开发核心知识。 付费学员加入QQ群,可获得本人未来1~3年学习过程中的专业指导解答。第三节课第7分15秒有QQ群,欢迎付费学员加入探讨技术问题。

    14898 人正在学习 去看看 陈超

      udp丢包是指在截获数据包后,linux内核的tcp/ip协议栈在udp数据包处理过程中的丢包,主要原因有两个:udp数据包格式或校验和错误和应用程序来不及处理udp数据包。

首先介绍通用的udp丢包检测方法,使用netstat命令,加-su参数。

# netstat -su

Udp:

    * packets received

    * packets to unknown port received.

    * packet receive errors

    * packets sent

    RcvbufErrors: *

    SndbufErrors: *

从上面的输出中,可以看到有一行输出包含了"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、wmem_default和wmem_max的值,如果服务器的性能压力不大,对处理时延也没有很严格的要求,设置为1M左右即可。如果服务器的性能压力较大,对处理时延有很严格的要求,则须谨慎设置rmem_default 和rmem_max,如果设得过小,会导致丢包,如果设得过大,会出现滚雪球。



         修改rmem_default、rmem_max、wmem_default和wmem_max的值,需要在/etc/sysctl.conf文件中进行,执行sysctl -p即可生效。

       即当系统重新启动后,原来设置的参数值就会丢失,而系统每次启动时都会自动去/etc/sysctl.conf文件中读取内核参数,因此将内核的参数配置写入这个文件中,是一个比较好的选择。


  首先打开/etc/sysctl.conf文件,查看如下两行的设置值,这里是:
  kernel.shmall = 2097152
  kernel.shmmax = 4294967295 如果系统默认的配置比这里给出的值大,就不要修改原有配置。同时在/etc/sysctl.conf文件最后,添加以下内容:

  fs.file-max = 6553600 
  kernel.shmmni = 4096 
  kernel.sem = 250 32000 100 128 
  net.ipv4.ip_local_port_range = 1024 65000 
  net.core.rmem_default = 4194304 
  net.core.rmem_max = 4194304 
  net.core.wmem_default = 262144 
  net.core.wmem_max = 262144 
  这里的“fs.file-max = 6553600”其实是由“fs.file-max = 512 * PROCESSES”得到的,我们指定PROCESSES的值为12800,即为“fs.file-max =512 *12800”。

  sysctl.conf文件修改完毕后,接着执行“sysctl -p”使设置生效。
  [root@localhost ~]# sysctl -p 常用的内核参数的含义如下。
  kernel.shmmax:表示单个共享内存段的最大值,以字节为单位,此值一般为物理内存的一半,不过大一点也没关系,这里设定的为4GB,即“4294967295/1024/1024/1024=4G”。
  kernel.shmmni:表示单个共享内存段的最小值,一般为4kB,即4096bit.
  kernel.shmall:表示可用共享内存的总量,单位是页,在32位系统上一页等于4kB,也就是4096字节。
  fs.file-max:表示文件句柄的最大数量。文件句柄表示在Linux系统中可以打开的文件数量。
  ip_local_port_range:表示端口的范围,为指定的内容。
  kernel.sem:表示设置的信号量,这4个参数内容大小固定。
  net.core.rmem_default:表示接收套接字缓冲区大小的缺省值(以字节为单位)。
  net.core.rmem_max :表示接收套接字缓冲区大小的最大值(以字节为单位)
  net.core.wmem_default:表示发送套接字缓冲区大小的缺省值(以字节为单位)。

  net.core.wmem_max:表示发送套接字缓冲区大小的最大值(以字节为单位)。



     注:当加入iptable规则,在输入/输出/转发过程中不起作用时,则需要在/etc/sysctl.conf文件中,添加:

                     net.ipv4.ip_forward = 1

2018-08-08 10:34:45 nawenqiang 阅读数 3888
  • TCP/IP/UDP Socket通讯开发实战 适合iOS/Android/...

    本课程适合中学员,适用于从事iOS/Android/嵌入式Linux网络通讯开发的学员。实战案例可用于无人机,安防,直播等。从Linux音频,视频采集,到TCP/IP UDP Socket基础概念,网络编程接口介绍,POSIX线程封装,私有协议定义,开发,服务器模型,客户端编程等详细实战讲解,整个过程,涵盖iOS,Android ,Mac OS嵌入式Linux网络编程核心的大量实用场景。让学员能够掌握相关知识,融汇贯通掌握网络通讯开发核心知识。 付费学员加入QQ群,可获得本人未来1~3年学习过程中的专业指导解答。第三节课第7分15秒有QQ群,欢迎付费学员加入探讨技术问题。

    14898 人正在学习 去看看 陈超

在Linux 上,编写一个每秒接收 100万UDP数据包的程序究竟有多难?

丢包检查方法

  • 给每个UDP包编号,对比收发端的接收到的包。对于UDP协议层上的包,例如RTP包,可以从RTP包中读出包的序列号进行判断。
  • 抓包。发送端和接收端分别抓包。linux下可以使用tcpdump,windows下使用wireshark。
  • 第三种就是下面介绍的,通过查看系统的一些配置和使用命令来查问题的方法啦

 

1. UDP概念

   用户数据报协议(英语:User Datagram Protocol,缩写为 UDP),又称使用者资料包协定,是一个简单的面向数据报的传输层协议,正式规范为RFC 768

   在TCP/IP模型中,UDP为网络层以上和应用层以下提供了一个简单的接口。UDP只提供数据的不可靠传递,它一旦把应用程序发给网络层的数据发送出去,就不保留数据备份(所以UDP有时候也被认为是不可靠的数据报协议)。UDP在IP数据报的头部仅仅加入了复用和数据校验(字段)。

2. UDP丢包问题分析

由于UDP协议只提供数据的不可靠传输,数据包发出去后就不管了,数据包在网络的传输过程中都可能丢失。甚至即使数据包成功到达了接收端节点,也不意味着应用程序能够收到,因为要从网卡到达应用程序还需要经历很多阶段,每个阶段都可能丢包。

上图描述了一种应用程序接受网络数据包的典型路径图。

首先,NIC(网卡)接收和处理网络数据包。网卡有自己的硬件数据缓冲区,当网络数据流量太大,大到超过网卡的接收数据硬件缓冲区,这时新进入的数据包将覆盖之前缓冲区的数据包,导致丢失。网卡是否丢包取决于网卡本身的计算性能和硬件缓冲区的大小。

其次,网卡处理后把数据包交给操作系统缓冲区。数据包在操作系统阶段丢包主要取决于以下因素:

  • 操作系统缓冲区的大小
  • 系统的性能
  • 系统的负载
  • 网络相关的系统负载

最后,当数据包到达应用程序的socket缓冲区,如果应用程序不能及时从socket缓冲区把数据包取走,累积的数据包将会超出应用程序socket缓冲区阀值,导致缓冲区溢出,数据包丢失。数据包在应用程序阶段丢包主要取决于以下因素:

  • 应用程序缓冲区大小
  • 应用程序处理数据包的能力,即如何尽可能快的从缓冲区取走数据包

3. 针对UDP丢包问题,进行系统层面和程序层面调优

3.1 诊断

n  网卡缓冲区溢出诊断

在Linux操作系统中,通过ethtool eth2查看网卡信息,可以通过netstat -i –udp <NIC> 命令来诊断网卡缓冲区是否溢出,RX-DRP列显示网卡丢失的数据包个数。

For example: netstat -i –udp eth1

  MTU     Met   RX-OK       RX-ERR       RX-DRP  RX-OVR  TX-OK       TX-ERR TX-DRP  TX-OVR   Flgeth1   
  1500       0      1295218256      0                 3            0          7598497      0                 0          0       BMRU

上图的输出显示3个数据包被网卡丢掉

可以通过增大网卡缓冲区来有效减少网卡缓冲区溢出。

RX errors: 表示总的收包的错误数量,这包括 too-long-frames 错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等。 


RX dropped: 网卡缓冲区溢出。 


RX overruns: 表示了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO 大于 kernel 能够处理的 IO 导致的,而 Ring Buffer 则是指在发起 IRQ 请求之前的那块 buffer。很明显,overruns 的增大意味着数据包没到 Ring Buffer 就被网卡物理层给丢弃了,而 CPU 无法及时的处理中断是造成 Ring Buffer 满的原因之一,上面那台有问题的机器就是因为 interruprs 分布的不均匀(都压在 core0),没有做 affinity 而造成的丢包。 


RX frame: 表示 misaligned 的 frames。

 

n  操作系统内核网络缓冲区溢出诊断

在Linux操作系统中可以通过cat /proc/net/snmp | grep -w Udp命令来查看,InErrors 列显示当操作系统UDP队列溢出时丢失的UDP数据包总个数。

[root@TENCENT64 /usr/local/games/udpserver]# cat /proc/net/snmp | grep -w UdpUdp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrorsUdp: 859428331 12609927 166563611 151449 166563611 0

有如下几种方法可以有效减缓操作系统缓冲区溢出:

1)     增大操作系统内核网络缓冲区的大小

2)     在数据包路径图中直接绕过操作系统内核缓冲区,通过使用用户空间栈或一些可以            绕过内核缓冲区的中间件 (e.g. Solarflare's OpenOnload).

3)     关闭未使用的网络相关的应用和服务使操作系统的负载降到最低

4)     系统中仅保留适当数量的工作的网卡,最大效率的合理化利用网卡和系统资源

 

n  应用程序socket缓冲区溢出诊断

在Linux操作系统中可以通过cat /proc/net/snmp | grep -w Udp命令来查看,RcvbufErrors 列显示当应用程序socket缓冲区溢出时丢失的UDP数据包总个数。

[root@TENCENT64 /usr/local/games/udpserver]# cat /proc/net/snmp | grep -w UdpUdp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrorsUdp: 859428331 12609927 166563611 151449 166563611 0

有如下几种方法可以有效减缓应用程序socket缓冲区溢出:

1)    接受缓冲区尽可能快地处理接受到的数据包(e.g.通过使用NIO的方式来异步非阻塞接受UDP数据包或者提高接受UDP数据包线程的优先级)

2)    增大应用程序接受socket缓冲区大小,注意这个受限于全局socket缓冲区大小,如果应用程序的socket缓冲区大于全局socket缓冲区将没有效果。

3)    把应用程序或接受线程指定到CPU专用的核上

4)    提高应用程序的io优先级(e.g.使用nice或ionice命令来调节)

5)    关闭所有未使用的网络相关的应用和服务使操作系统的负载降到最低

3.2 调优

n  网卡缓冲区调优

Linux下运行ethtool -g <NIC> 命令查询网卡的缓冲设置,如下:

ethtool -g etheth1

Pre-set maximums:

RX:             4096RX Mini:        0RX Jumbo:       0TX:         4096

Current hardware settings:

RX:             256RX Mini:        0RX Jumbo:       0TX:             256

       通过命令ethtool -G d<NIC> rx NEW-BUFFER-SIZE可以设置RX ring的缓冲区大小,改变会立即生效不需要重启操作系统或刷新网络栈,这种变化直接作用于网卡本身而不影响操作系统,不影响操作系统内核网络栈但是会影响网卡固件参数。更大的ring size能承受较大的数据流量而不会丢包,但是因为工作集的增加可能会降低网卡效率,影响性能,所以建议谨慎设置网卡固件参数。

n  操作系统内核缓冲区调优

运行命令sysctl -A | grep net | grep 'mem\|backlog' | grep 'udp_mem\|rmem_max\|max_backlog'查看当前操作系统缓冲区的设置。如下:

[root@TENCENT64 /usr/local/games]# sysctl -A | grep net | grep 'mem\|backlog' | grep 'udp_mem\|rmem_max\|max_backlog'net.core.netdev_max_backlog = 1000net.core.rmem_max = 212992net.ipv4.udp_mem = 188169       250892  376338

增加最大socket接收缓冲区大小为32MB:

sysctl -w net.core.rmem_max=33554432

增加最大可分配的缓冲区空间总量,数值以页面为单位,每个页面单位等于4096 bytes:

sysctl -w net.ipv4.udp_mem="262144 327680 393216"

增加接收数据包队列大小:

sysctl -w net.core.netdev_max_backlog=2000

修改完成后,需要运行命令 sysctl –p 使之生效

n  应用程序调优

      要减少数据包丢失,应用程序必须尽可能快从缓冲区取走数据,可以通过适当增大socket缓冲区和采用异步非阻塞的IO来快速从缓冲区取数据。

// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

 

4. 其他减少丢包策略

      UDP发送端增加流量控制,控制每秒发送的数据包,尽量避免由于发送端发包速率过快,导致UDP接收端缓冲区很快被填满从而出现溢出丢包。测试采用google提供的工具包guava。RateLimiter类来做流控,采用了一种令牌桶的流控算法,RateLimiter会按照一定的频率往桶里扔令牌,线程拿到令牌才能执行,比如你希望自己的应用程序QPS不要超过1000,那么RateLimiter设置1000的速率后,就会每秒往桶里扔1000个令牌。

       采用流控后每秒发指定数量的数据包,而且每秒都会出现波谷波峰,如果不做流控,UDP发送端会全力发包一直在波峰附近抖动,大流量会一直持续,随着时间的增加,UDP发送端生产的速率肯定会超过UDP接收端消费的速率,丢包是迟早的。

5. 真实测试数据

n  机器类型

发送端和接收端均采用C1类型机器,配置如下:

C1

Intel(R) Xeon(R) CPU X3440 @ 2.53GHz:8

8G

500G:7200RPM:1:SATA

NORAID

接收端网卡信息如下:

[root@TENCENT64 /usr/local/games]# ethtool eth1                     Settings for eth1:        Supported ports: [ TP ]        Supported link modes:   10baseT/Half 10baseT/Full                                 100baseT/Half 100baseT/Full                                 1000baseT/Full         Supports auto-negotiation: Yes        Advertised link modes:  10baseT/Half 10baseT/Full                                 100baseT/Half 100baseT/Full                                 1000baseT/Full         Advertised pause frame use: Symmetric        Advertised auto-negotiation: Yes        Speed: 1000Mb/s        Duplex: Full        Port: Twisted Pair        PHYAD: 1        Transceiver: internal        Auto-negotiation: on        MDI-X: on        Supports Wake-on: pumbg        Wake-on: g        Current message level: 0x00000007 (7)        Link detected: yes[root@TENCENT64 /usr/local/games]# ethtool -g eth1Ring parameters for eth1:Pre-set maximums:RX:             4096RX Mini:        0RX Jumbo:       0TX:             4096Current hardware settings:RX:             256RX Mini:        0RX Jumbo:       0TX:             256

n  实际调优

接收端服务器调优后的参数如下:

[root@TENCENT64 /usr/local/games]# sysctl -A | grep net | grep 'mem\|backlog' | grep 'udp_mem\|rmem_max\|max_backlog'net.core.rmem_max = 67108864net.core.netdev_max_backlog = 20000net.ipv4.udp_mem = 754848       1006464 1509696

 发送端是否做发送流量控制在测试场景中体现

n  测试场景

场景1:发送100w+数据包,每个数据包大小512byte,数据包都包含当前的时间戳,不限流,全速发送。发送5次,测试结果如下:

测试客户端:

发100w个512字节的udp包,发100w数据包耗时4.625s,21wQPS

测试服务器端:

客户端发5次包,每次发包100w(每个包512字节),第一次服务端接受90w丢约10w,第二次服务端接受100w不丢,第三次接受100w不丢,第四次接受97w丢3w,第五次接受100w不丢

服务端记录日志:

 服务端操作系统接收UDP记录情况:(和日志记录结果完全一致)

       场景2:发送端增加流量控制,每秒4w数据包,每个数据包512byte,包含当前时间戳,发送时间持续2小时,测试结果如下:

1.Udpclient端,加入流量控制:

QPS:4W

datapacket:512byte,包含发送的时间戳

持续发送时长:2h

累计发包数: 287920000(2.8792亿)

CPU平均消耗: 16% (8cpu)

内存平均消耗: 0.3%(8G)

2.Udpserver端:

Server端接受前网卡记录的UDP 详情:

[root@TENCENT64 ~]# cat /proc/net/snmp | grep -w UdpUdp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrorsUdp: 1156064488 753197150 918758960 1718431901 918758960 0

Server端接受完所有的udp数据包后网卡记录的UDP详情:

[root@TENCENT64 ~]# cat /proc/net/snmp | grep -w UdpUdp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrorsUdp: 1443984568 753197150 918758960 1718432045 918758960 0

前后变化分析:

InDatagrams: (1443984568-1156064488)= 287920080

InErrors:0 (记录操作系统层面udp丢包,丢包可能是因为系统udp队列满了)

RcvbufErrors:0(记录应用程序层面udp丢包),丢包可能是因为应用程序socket buffer满了)

Server端日志情况:

总记录日志文件:276个,总大小:138G

日志总数: 287920000 (和udpclient发送数据包总量一致,没有丢包)

根据日志时间戳,简单计算处理能力:

time cost:(1445410477654-1445403277874)/1000=7199.78s

process speed: 287920000/7199.78 = 3.999w/s

 

CPU消耗: 平均46% (8cpu),要不停异步写日志,IO操作频繁,消耗比较多cpu资源

内存消耗: 平均4.7%(8G)

 

  场景3:发送端增加流量控制,每秒6w数据包,每个数据包512byte,包含当前时间戳,发送时间持续2小时,出现丢包,测试结果如下:

1.Udpclient端,加入流量控制:

QPS:6W

datapacket:512byte,包含发送的时间戳

持续发送时长:2h

累计发包数: 432000000 (4.32亿)

CPU平均消耗: 70% (8cpu)

内存平均消耗: 0.3%(8G)

2.Udpserver端:

Server端接受前网卡记录的UDP 详情:

[root@TENCENT64 ~]# cat /proc/net/snmp | grep -w UdpUdp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrorsUdp: 2235178200 753197150 918960131 1720242603 918960131 0

Server端接受完所有的udp数据包后网卡记录的UDP详情:

[root@TENCENT64 ~]# cat /proc/net/snmp | grep -w UdpUdp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrorsUdp: 2667158153 753197150 918980378 1720242963 918980378 0

前后变化分析:

InDatagrams: (2667158153 -2235178200)= 431979953

InErrors: (918980378 -918960131)= 20247 (记录操作系统层面udp丢包,丢包可能是因为系统udp队列满了)

RcvbufErrors: (918980378 -918960131)= 20247 (记录应用程序层面udp丢包),丢包可能是因为应用程序socket buffer满了)

Server端日志情况:

总记录日志文件:413个,总大小:207G

日志总数: 431979753 (和网卡收到udp包总数一致,写日志文件没有丢包)

丢包情况:

Client端发送:432000000,

服务端网卡接受udp包总数:431979953,

日志记录:431979953,

udp网卡接受丢包:20247,

丢包率:1/20000

由于测试服务器硬盘资源有限,只测试了2个小时,随着发送和接受时间增长,丢包率可能会增大。

 

 总结:UDP发包在不做流控的前提下,发送端很快到达一个相对稳定的波峰值并一直持续发送,接收端网卡或操作系统缓冲区始终有限,随着发包时间不断增加,到某个时间点必定填满接收端网卡和系统的缓冲区,而且发送端的生产速率将远远超过接收端消费速率,必然导致丢包。发送端做了流量控制后,发送速率得到有效控制,不会一直持续高流量发送,每秒都会出现波谷波峰,有效缓解了接收端的压力,在合理发包速率的前提下,通过相关系统调优,基本可以保证不丢包,但要确保数据的高完整性,由于UDP协议的天生不可靠性,还是要在UDP协议基础上做相关扩展,增加数据完整性校验,方能确保业务数据的完整。

udp优化
2013-06-03 20:53:40 longhumen1214 阅读数 2603
  • TCP/IP/UDP Socket通讯开发实战 适合iOS/Android/...

    本课程适合中学员,适用于从事iOS/Android/嵌入式Linux网络通讯开发的学员。实战案例可用于无人机,安防,直播等。从Linux音频,视频采集,到TCP/IP UDP Socket基础概念,网络编程接口介绍,POSIX线程封装,私有协议定义,开发,服务器模型,客户端编程等详细实战讲解,整个过程,涵盖iOS,Android ,Mac OS嵌入式Linux网络编程核心的大量实用场景。让学员能够掌握相关知识,融汇贯通掌握网络通讯开发核心知识。 付费学员加入QQ群,可获得本人未来1~3年学习过程中的专业指导解答。第三节课第7分15秒有QQ群,欢迎付费学员加入探讨技术问题。

    14898 人正在学习 去看看 陈超

本文讨论的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缓冲区设的过大导致滚雪球的问题,大家可以参考http://km.oa.com/user/bisonliao/articles/show/75674中的介绍,有定量的计算方法,分析得很深入。

 

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%时就持续告警,留出充足的反应时间。


2014-06-27 13:26:27 kobejayandy 阅读数 6860
  • TCP/IP/UDP Socket通讯开发实战 适合iOS/Android/...

    本课程适合中学员,适用于从事iOS/Android/嵌入式Linux网络通讯开发的学员。实战案例可用于无人机,安防,直播等。从Linux音频,视频采集,到TCP/IP UDP Socket基础概念,网络编程接口介绍,POSIX线程封装,私有协议定义,开发,服务器模型,客户端编程等详细实战讲解,整个过程,涵盖iOS,Android ,Mac OS嵌入式Linux网络编程核心的大量实用场景。让学员能够掌握相关知识,融汇贯通掌握网络通讯开发核心知识。 付费学员加入QQ群,可获得本人未来1~3年学习过程中的专业指导解答。第三节课第7分15秒有QQ群,欢迎付费学员加入探讨技术问题。

    14898 人正在学习 去看看 陈超

本文讨论的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缓冲区设的过大导致滚雪球的问题,大家可以参考http://km.oa.com/user/bisonliao/articles/show/75674中的介绍,有定量的计算方法,分析得很深入。

 

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%时就持续告警,留出充足的反应时间。

没有更多推荐了,返回首页