linux 系统 UDP 丢包问题分析思路

linux 系统 UDP 丢包问题分析思路

在开始之前,我们先用一张图解释 linux 系统接收网络报文的过程。 首先网络报文通过物理网线发送到网卡 网络驱动程序会把网络中的报文读出来放到 ring buffer 中,这个过程使用 DMA(Direct Memory Access),不需要 CPU 参与 内核从 ring buffer 中读取报文进行处理,执行 IP 和 TCP/UDP 层的逻辑,最后把报文放到应用程序的 socket buffer 中 应用程序从 socket buffer 中读取报文进行处理 在接收 UDP 报文的过程中,图中任何一个过程都可能会主动或者被动地把报文丢弃,因此丢包可能发生在网卡和驱动,也可能发生在系统和应用。 之所以没有分析发送数据流程,一是因为发送流程和接收类似,只是方向相反;另外发送流程报文丢失的概率比接收小,只有在应用程序发送的报文速率大于内核和网卡处理速率时才会发生。 本篇文章假定机器只有一个名字为 eth0 的 interface,如果有多个 interface 或者 interface 的名字不是 eth0,请按照实际情况进行分析。 NOTE:文中出现的 RX(receive) 表示接收报文,TX(transmit) 表示发送报文。 确认有 UDP 丢包发生 要查看网卡是否有丢包,可以使用 ethtool -S eth0 查看,在输出中查找 bad 或者 drop 对应的字段是否有数据,在正常情况下,这些字段对应的数字应该都是 0。如果看到对应的数字在不断增长,就说明网卡有丢包。 另外一个查看网卡丢包数据的命令是 ifconfig,它的输出中会有 RX(receive 接收报文)和 TX(transmit 发送报文)的统计数据: ~# ifconfig eth0 ... RX packets 3553389376 bytes 2599862532475 (2.3 TiB) RX errors 0 dropped 1353 overruns 0 frame 0 TX packets 3479495131 bytes 3205366800850 (2.9 TiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ... 此外,linux 系统也提供了各个网络协议的丢包信息,可以使用 netstat -s 命令查看,加上 --udp 可以只看 UDP 相关的报文数据: [root@holodesk02 GOD]# netstat -s -u IcmpMsg: InType0: 3 InType3: 1719356 InType8: 13 InType11: 59 OutType0: 13 OutType3: 1737641 OutType8: 10 OutType11: 263 Udp: 517488890 packets received 2487375 packets to unknown port received. 47533568 packet receive errors 147264581 packets sent 12851135 receive buffer errors 0 send buffer errors UdpLite: IpExt:

CityHash 与 MurmurHash 哈希算法

CityHash 与 MurmurHash 哈希算法

MurMurHash MurMurHash由Austin Appleby在2008年发明,与其它流行的哈希函数相比,对于规律性较强的key,MurMurHash的随机分布特征表现更良好,Redis,Memcached,Cassandra,HBase,Lucene中都使用到了这种hash算法。另外,Guava工具包提供了MurMurHash算法实现,Guava中的BloomFilter实现也用到了MurMurHash算法,Redis的java客户端Jedis中也使用到了此算法。MurmurHash是一种经过广泛测试且速度很快的非加密哈希函数。存在多种变体,名字来自两个基本运算,即multiply和rotate(尽管该算法实际上使用shift和xor而不是rotate)。 MurmurHash3可以产生32位或128位哈希,旧版本MurmurHash2产生32位或64位值,MurmurHash2A变体添加了Merkel-Damgard构造,以便可以逐步调用它。MurmurHash64A针对64位处理器进行了优化,针对32位处理器进行MurmurHash64B优化。MurmurHash2-160生成160位哈希,而MurmurHash1已过时,实现规范的实现是用C++实现的,但是有多种流行语言的有效移植,已被很多开源项目采用。 具有良好的分布性,适用于机器学习用例,例如特征哈希和随机投影,布隆过滤器中也有应用。MurMurHash3 128 位版本的速度是 MD5 的十倍。MurMurHash3 生成 32 位哈希的用时比生成 128 位哈希的用时要长。原因在于生成 128 位哈希的实现受益于现代处理器的特性。32 位哈希值发生碰撞的可能性就比 128 位的要高得多,当数据量达到十万时,就很有可能发生碰撞。 CityHash CityHash算法由Google公司于2013年公布,有两种算法:CityHash64 与 CityHash128。它们分别根据字串计算64和128位的散列值。这些算法不适用于加密,但适合用在散列表等处。 Google一直在根据其数据中心常用的CPU对算法进行优化,结果发现对大多数个人计算机与笔记本同样有效益。尤其是在64位寄存器、指令集级的并行,以及快速非对其内存存取方面。 该算法的开发受到了前人在散列算法方面的巨大启发,尤其是Austin Appleby的MurmurHash。 CityHash的主要优点是大部分步骤包含了至少两步独立的数学运算,现代CPU通常能从这种代码获得最佳性能。 CityHash缺点:代码较同类流行算法复杂。Google希望为速度而不是为了简单而优化,因此没有照顾较短输入的特例。 总体而言,CityHash64与CityHash128是解决经典问题的全新算法。在实际应用中,Google预计CityHash64在速度方面至少能提高 30%,并有望提高多达两倍。此外,这些算法的统计特性也很完备。 MurmurHash3 VS CityHash CityHash是Google

C/C++ 語言測量時間函數,評估程式執行效能方法整理

C/C++ 語言測量時間函數,評估程式執行效能方法整理

這裡整理了 C/C++ 中各種測量時間的函數與用法,並提供完整的範例程式碼,讓程式開發者方便測量程式執行速度。 這裡我蒐集了一些在 C/C++ 中常見的程式執行速度測量方式,因為時間的量測方式與細節非常多,這裡只是簡單寫一些常用的方式與範例。 程式中的時間 在測量程式執行所花費的時間前,必須先認識一下時間的測量方式,不同的測量方法會得到不同的結果,其意義也不同。 Wall-Clock Time Wall-clock time 顧名思義就是真實世界的時間,相當於以牆上的時鐘為依據所計算出來的時間,這個時間會牽涉到校時、時區以及夏令時間之類的問題,詳細說明請參考維基百科的 Wall-clock time 說明。 由於 wall-clock time 並不是單調遞增(monotonic)的數值,所以它不是一個穩定的時間依據,只能做為參考用,若需要非常精準的量測程式效能,不建議使用這種時間。 CPU Time CPU time 是指程式真正使用 CPU 在執行的時間,而這個時間又可以細分為兩種: user time:程式本身執行的時間(user space)。 system time:作業系統層級執行的時間(kernel space)。 詳細說明請參考維基百科的 CPU time 與 User space 說明。 對於多執行緒(multithreading)的程式,其 CPU time 就是每條執行緒的執行時間總和,所以平行化的程式其 CPU time 可能會比 wall-clock time 還要長。 C 語言範例 這是一個利用蒙地卡羅演算法計算 pi 的範例: #include <stdlib.h> #include <stdio.h> #include <math.h> double pi(int n) { srand(5); int count = 0; double x, y; for (int i = 0; i < n; ++i) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; if (x * x + y * y <= 1) ++count; } return (double) count / n * 4; } int main() { double result = pi(1e8); printf("PI = %f\n", result); } 使用 gcc 編譯: gcc -o pi pi.c 若使用比較舊的 gcc 編譯器,要加上 -std=c99 參數: gcc -std=c99 -o pi pi.c 以下我們將以這個程式為例,介紹測量程式執行時間的方法。 Linux time 指令 在 Linux 中有一個 time 指令可以直接測試程式的執行時間(CPU time): time ./pi PI = 3.142172 real 0m2.210s user 0m2.209s sys 0m0.001s time 指令的輸出分為 user time、system time 以及實際上所花費的時間。 如果在系統上同時有其他的程式也在使用 CPU 時,結果會有些差異。我先使用 stress 讓 CPU 滿載: stress --cpu

RPS与RFS实现分析

RPS与RFS实现分析

RPS和RFS是google贡献的两个补丁,在2.6.35版本中,正式被合并入了内核。这两个补丁总体来说,并不算复杂,实际上很多网络设备厂商早已在自己的产品中,有了类似的应用。但这个涉及到厂商的主营业务,所以不会做任何开源。 前几天在画RPS和RFS的流程图时,发现关于RPS和RFS的实现分析并不多,大部分都是设置和性能对比。所以,今天就炒炒冷饭,聊聊RPS与RFS的实现。 下面是较为完整的RPS&RFS的流程图。 因为微信会压缩图片,看不清楚的同学还是请访问https://raw.githubusercontent.com/gfreewind/kernel_skb_path/master/kernel_skb_path.jpg。 首先,我们要看为什么要有RPS和RFS?在没有它们的年代,网卡触发了接收中断之后,由一个CPU进行处理硬中断,接着在软中断里将数据包向上传递给协议栈。也就是说,哪个CPU响应了网卡中断,就由哪个CPU对该数据包进行全部的处理工作。在单核的时代,这样是没有问题的,但随着多核时代的到来,这就要求硬件必须较为均衡的将中断分发给不同的CPU。这对硬件提出了要求,莫说普通的单队列网卡,就是多队列网卡,也经常碰到在某些主板上,多个队列的中断都被发给一个CPU处理。这时,就需要在软件上做进一步均衡,也就是RPS的目的。 RPS全称为Receive Packet Steering,以TCP报文为例,RPS根据三层协议的IP报文的源地址和目的地址,四层协议的源端口和目的端口,进行hash运算后,确定由哪个CPU处理该报文。这样就弥补了硬件的不足,即使硬中断负载不均,通过RPS再处理,尽力保证各CPU的负载均衡。 而RFS是在RPS基础上更进一步,其全称是Receive Flow Steering,顾名思义RPS只针对数据包,没有对会话做任何考虑,而RFS则尽力保证同一会话仍然由“上次”的CPU处理,这样可以保证cache的热度,提高cache的命中率。 RPS的设置,通过/sys/class/net/eth0/queues/rx-0/rps_cpus设置CPU掩码,每一位对应一个CPU ID,RPS会将数据包在这几个CPU之间进行分发。RFS则略为复杂,既要通过/proc/sys/net/core/rps_sock_flow_entries设置全局的表项大小,也要通过/sys/class/net/eth0/queues/rx-0/rps_flow_cnt设置网卡接收队列的表项大小。 下面将从源码角度,分析RPS和RFS的实现。get_rps_cpu是RPS和RFS处理的入口函数。本文不对其做全面的分析,只对几个重要的关键点做一些分享。 1. 数据包的hash运算 目前很多网卡支持了receive-hashing,即由硬件对数据包做hash运算,驱动会调用skb_set_hash设置结果。这时skb的l4_hash就被

JDK11-G1垃圾收集器

JDK11-G1垃圾收集器

G1垃圾收集器简介 G1垃圾收集器主要是为那些拥有大内存的多核处理器而设计的。它在以很高的概率满足垃圾收集的停顿时间的要求同时还可以达到很高的吞吐量,同时几乎不需要做什么配置。G1的目标是为应用提供停顿时间和吞吐量的最佳平衡,它的主要特性包含: 堆内存达到数十个G甚至更大,超过50%的堆内存都是存活的对象 对象分配和晋升的速度随时间变化非常大 堆中存在大量的内存碎片 可预测的停顿时间的目标在几百毫秒以内,不会存在长时间的停顿 在jdk11中,G1已经取代了CMS,是默认的垃圾收集器 在随后的章节会介绍G1收集器达到如此高性能和满足停顿时间目标的多种方式。 转载请标明出处:https://blog.csdn.net/goldenfish1919/article/details/82911948 启用G1 因为G1是默认的收集器,因此一般不需要做任何额外的操作就开启。你也可以用 -XX:+UseG1GC来明确开启(译者注:因为是JDK11)。 基础的一些概念 G1是一款分带、增量、并行、大部分时候并发、STW并且标记整理的收集器,在每一个STW停顿的时候,它都会监控停顿时间的目标。跟其他的收集器类似,G1把堆分成逻辑上的young区和old区。内存回收主要集中在young区,在这个区域的内存回收也是非常高效的,偶尔也会发生在old区。 为了提高吞吐量,有些操作总是STW的,还有一些操作在应用停止的情况下会花费更多的时间,比如一些对整个堆的操作,像全局的标记就是并行和并发来执行的。在空间回收的时候,为了让STW时间更短,G1是增量的分步和并行来回收的。G1是通过记录上一次应用的行为和GC的停顿信息来实现可预计的停顿时间的,可以利用这些信息来计算在停顿时间之内要做的工作的多少。比如:G1会首先回收那些可以高效回收的内存区域(也就是大部分都被填满垃圾的区域,这也是为啥叫G1的原因)。 G1大部分使用标记整理算法来回收内存:收集选中的内存区域中的存活对象,然后把他们拷贝到新的内存区域中,同时会对这些对象占用的空间进行压缩。回收完成以后,之前被存活对象占用的空间可以被应用用来重新分配对象。 G1并不是一个实时的垃圾收集器。长时间来看,它可以以很高的概率满足停顿时间的要求,但并不能绝对满足。 堆的结构 G1把整个堆分成很多相等大小的块(Region),每一个region都是一些连续的虚拟内存就如同图9-1所示。region是内存分配和回收的基本单元,在某个特定的时间点,一个region可能是空的(浅灰色表示),或者是分配到了某个区(generation)中,可能是young区或者old区。当

联系我们

联系电话

4000-640-466

联系邮箱

service@f-li.cn

办公地址

上海黄浦区外滩源1号

谢谢,您的信息已成功发送。
请填写信息。