通过 tcpcopy(pf_ring) 对 BCM 5719 小包做的多组 benchmark

tcpcopy 在文档化、用户参与方式方面有很大的提升空间这个问题在之前已经专门说过。最终,在我们自己阅读代码的情况下,结合 pf_ring,坚持跑通了整个流程,用其对目前 BCM 5719 型号的网卡做了多组对比,结论见结尾。
使用 tcpcopy 做 benchmark,务必确定 tcpcopy 语法使用的正确性, 尽管互联网上绝大多数的文档以及官方文档都写的含糊不清。
比如,我们之前把过滤条件 -F "tcp and dst port 80" 写成了 -F "tcp and src port 80",造成的结果是在错误的基础上得出了一些奇葩的数据以及无法解释的现象,比如到 target server 的流量特别小,并且及其的不稳定,得到的 pps 也是非常的不稳定大到 400kpps/s,小到 20k  甚至 0。

这里列举我们测试环境使用的一组配置。
所有机器都是 RedHat 6.2 2.6.32-279.el6.x86_64,Tcpcopy 1.0 版本,PF_RING 6.0.1,BCM 5719,双网卡 bonding。另外,我们单台生产机器的流量都比较大,并且绝大多数都是 100B 以下的小包,所以对系统的要求还是比较高的。
为了避免后续的误解,先确定几个用语:
1. online server(OS): 即我们线上生产环境的机器
2. target server(TS): 是我们想做 benchmark 的那台机器,以测试其究竟能支撑多大的量
3. assistant server(AS): 是安装了 intercept 的机器
4. mirror server(MS): 通过 tcpcopy 的 mirror 工具把 OS 的流量复制到该台机器上

我们一共做了三大组 benchmark,每组下面包含若干小的 benchmark,包括:
1. tcpcopy + intercept
2. tcpcopy + intercept + tcpcopy mirror,加一个 mirror 是为了减少对 OS 的负载,这样 tcpcopy 在 MS 上运行
3. tcpcopy + intercept + 交换机 mirror,更直接的方式复制线上流量,保证对 OS 没有干扰,并且能保证 100% 全量复制 OS 的流量

Continue reading

PF_RING 对网络抓包性能的提升不仅仅是 30% – 40%

pf_ring 由于涉及的东西比较多,最初看的时候可能会云里雾里,不过多看几遍官方文档应该就能大致理解含义了。
安装的步骤可以看这里。 我建议还是自己跑一遍,这样能熟悉每个零部件的作用。要是实在没空,也可以直接用官方提供的 rpm, deb 安装。
这里提示下,除了编译出来的 pf_ring.ko 之外,如果你的 NIC 不支持 PF_RING™-aware driver,那么只能使用 mode 0,如果支持的话,可以使用 mode 1 以及 mode 2,三者在我们的系统上 benchmark 下来差距并不大,不过加载了 pf_ring.ko 跟不加载 pf_ring.ko 的差距那真是天壤之别了。基本目前主流的 Intel、Broadcom 的都支持(igb, ixgbe, e1000e, tg3, bnx2),注意,tg3 目前(10/18/2014)最新的稳定版本 6.0.1 并没有,需要使用 nightly builds 版本,PF_RING_aware/non-ZC-drivers/broadcom/tg3-3.136h,PF_RING_aware/non-ZC-drivers/2.6.x/broadcom/tg3/tg3-3.102 .2.6.x 目录下面的都是已经废弃的版本,就不要使用了。

一般的应用也不大用到 pf_ring,不过如果是一些 IDS、snort 之类的系统,就派上用场了。我们的情况有点特殊,某条产品线由于前端的机器网卡比较弱(BCM5719),再加上发过来的绝大多数都是 75B 以下的小包,导致 rx_discards 以每秒数 k 的恐怖值增加。最初想抓包看看发过来的都是什么样结构的包,结果普通的 tcpdump 就完全没法用了,传统的 BPF(libpcap) 抓包相比简直是弱爆了。下面两张图,一张是通过 ntopng(也是使用的传统的 pcap)分析的包的大小,跟 iptraf 结果一致,一个只抓到了 2% 不到的包:-(


有需求就有动力了,后来研究了下 pf_ring,情况立马变好转了。看看下面两个对比就知道了。

加载了 pf_ring 的:
$ sudo /var/tmp/pfring/PF_RING-6.0.1/userland/tcpdump-4.1.1/tcpdump   -i bond1 -n -c 1000000 -w tmp
tcpdump: listening on bond1, link-type EN10MB (Ethernet), capture size 8192 bytes
1000000 packets captured
1000000 packets received by filter
0 packets dropped by kernel

使用传统 libpcap 抓包的:
$ sudo tcpdump   -i bond1 -n -c 1000000 -w tmp
tcpdump: listening on bond1, link-type EN10MB (Ethernet), capture size 65535 bytes
1000000 packets captured
1722968 packets received by filter
722784 packets dropped by kernel
12139 packets dropped by interface

所以说,pf_ring 对抓包的提升不仅仅是官方宣传的 30%-40% 的提升,更是一种技术对另外一种技术的革新,以及实际生产效率的大幅度提升。
另外,广告下 ntop.org 这个网站,上面有不少有意思的玩意儿,ntop, ntopng,再比如代替 OpenDPI 的 nDPI。我曾经玩过 OpenDPI,没几天官方就不更新了,这东西最重要的是实时的分析目前主流的协议,好在 nDPI 站在巨人肩膀上发扬光大了。提醒一下,这个也仅仅做娱乐只用,如果要实打实的,还是去买设备。

resolv.conf 的超时(timeout)与重试(attempts)机制

/etc/resolv.conf 有两个默认的值至关重要,一个是超时的 timeout,一个是重试的 attempts,默认情况下,前者是 5s 后者是 2 次。
这个估计很多工程师都不是很在意,一般情况下,使用默认的值倒没什么大问题,特殊情况我会在最后说明。

要测试,不要使用 dig, host, nslook 这类工具,因为他们并没有调用 resolver 的库,可以使用 getent 来测试。上面提到的只是一些诊断的工具,对于日常的应用来说,包括 web server、mail client、db 以及各种 app server 等等,任何使用 glibc resolver 都需要经过 resolv.conf 文件。

对于 libresolv 来说,只认 resolv.conf 的前三个 nameserver,所以写的再多也没什么意义。正常情况下,resolver 会从上至下进行解析,每个 nameserver 等待 timeout 的时间,如果一直到第三个都没结果,resolver 会重复上面的步骤 (attempts – 1) 次。

为了真正理解,例如下面这个场景:
search test.example.com example.com  
nameserver 192.168.0.1  
nameserver 192.168.0.2

假设 192.168.0.1 不返回结果(可能根本就不是台 DNS),我们假设需要解析 "www.devel",而这个仅仅在 www.devel.example.com 里面有记录,下面是整个执行的步骤:
1. "www.devel" on 192.168.0.1, wait until timeout (default 5 secs)
2. "www.devel" on 192.168.0.2, get reply: no such hostname
3. "www.devel" on 192.168.0.1, wait until timeout (default 5 secs)
4. "www.devel" on 192.168.0.2, get reply: no such hostname
5. "www.devel.test.example.com" on 192.168.0.1, wait until timeout (default 5 secs)
6. "www.devel.test.example.com" on 192.168.0.2, reply no such hostname
7. "www.devel.test.example.com" on 192.168.0.1, wait until timeout (default 5 secs)
8. "www.devel.test.example.com" on 192.168.0.2, reply no such hostname
9. "www.devel.example.com" on 192.168.0.1, wait until timeout (default 5 secs)
10. "www.devel.example.com" on 192.168.0.2, reply with IP address

默认情况下是 5s 超时,我做了两个简单的测试,把 resolv.conf 的前三个 nameserver 全部换成不存在的 1.1.1.1, 2.2.2.2, 3.3.3.3,然后可以观察下面 strace 跟踪的结果,对于 ping 以及 getent 来说,已经算是上层的应用结果了。
1. strace -t getent hosts baidu.com
2. strace ping baidu.com

把 timeout 设置为 1s 的结果可以看下面这个测试结果:
strace -t ping baidu.com(options timeout:1)

对于生产有什么意义了?
对于任何的代码,不管何种形式的(HTTP 的也好,DB 的连接也罢),只要是一端对另外一端的连接,都应该加上超时重试以及异常处理的。上面其实一共涉及三个点:
1. 超时,目前绝大多数的 API 都支持这类参数,包括我们线上用的 grequestsMySQLdb 等等
2. 重试,对于代码层面同样重要,跟上面类似
3. 异常处理,好的代码对于无法连接或者连接超时等问题应该及时的抛出异常打 log,而不是什么都没有,否则会加大问题定位的工作量,后期维护起来也会异常的麻烦。

这里有个有意思的脚本能检测最佳的 DNS。

最后,记得 dig, nslook 只会解析 resolv.conf 的内容,而不会解析 hosts 里面内容,所以如果想让 dig 解析 hosts 里面的内容,可以通过 dnsmasq 实现。

ref:
https://access.redhat.com/solutions/21420
http://serverfault.com/questions/562079/adjusting-how-long-linux-takes-to-fail-over-to-backup-dns-server-listed-in-resol

50M 流量搞死 BCM57xx(NetXtreme I Server) 网卡

BCM 网卡质量渣的问题已经延续好多年了,12 年我写过一篇《BCM 5709 网卡》的博客记录 BCM 驱动的各种问题。
最近我们又遇到因为 BCM 扛不住小包(small packet)导致 nic 狂 drop 的问题,即使升级到最新的版本依然不行。当然这个很大一部分责任归结于我们,在产品上线之初没有做一个这方面的调研。
为什么 BCM 网卡会有这么多关注?目前主流的服务器厂商默认情况下都是 ship 的 broadcom 的网卡,市场占有率最大的 Dell,HP 无一都不是跟他们合作的,如果要使用其他品牌比如 Intel igb,大部分情况下需要单独采购,并且成本相比 Broadcom 会高出不少。这里是官方的价格列表(1, 2)。  
在正常情况下,BCM 的也能凑活着用,并不会引起很大的问题,比如跑的是一些正常服务。但是如果大量的小包,BCM 就彻底废了,尤其遇到只有 4 个队列的 BCM5719。所以,我标题写的并不是那么准确,仅仅是为了强调下其性能的巨大弱势。

上一篇博客我推荐了几款做发包测试的工具,通过他们,可以很明显的对比出差异。对于网卡的性能测试,收发包的性能跟带宽的吞吐相比更加重要,当然二者还是要看适用的场景。
以发 64B 的小包为例,BCM 的在 200Kpps/s 的时候就都废了,相比之下,同样的环境,I350 在 600Kpps/s 的时候仅仅有很少的丢包,准确的说是伴随着 rx_fifo_errors 的 overruns,各个厂家实现的方式不大一样,反映到 OS 层面就比较麻烦了,有的是 dropped 有的是 overruns。

下面两张图是我们某台接受大量小包(~70B)的服务器,可以看到,200Kpps/s 时候表现就一塌糊涂了,导致系统的 rt 非常大甚至直接 timeout。

50M 就能搞死一台 BCM5719/20 机器的说法毫不夸张。

12 月 06 日统计分析数据延时的技术背景分析

2014 年 12 月 06 日,由于一台 Kafka 机器磁盘问题,导致友盟的统计分析业务的数据出现了延时。下面我会从技术的角度给大家分享一下当时问题发生的背景、处理过程以及事后。

18:15 PM: 我们收到前端 4xx 增多的报警,对比正常时段,4xx/200 的比例由正常的 0.5% 以下上升到了 1.5% 左右。收到报警后我们立马介入现场排查问题,确认了包括每秒接受日志数量在内的核心指标并无大的异常,暂且判定为了非紧急事故。

19:06 PM: 我们开始疯狂的收到报警,查看了我们实时的 dashboard,发现 4xx 已经由原先的 ~400 req/s 飙升到了 ~10k req/s,200 也开始直线下降。同时,我们收到前端接受日志的 logtorrent 服务(基于 Finagle 实现)的 file descriptor 已经由原先的 ~7k 飙升到了几乎系统 fs.file-max 的极限。

19:07 PM: 报警显示,出问题的这条链路的入口带宽在有 20% 充足富裕的情况下被全部打满。导致我们几乎不能从主 VPN 登录我们的线上机器,于是执行了 plan B,经过我们备用的一条链路,最终登录上了我们的线上机器。
根据之前的经验,这类问题很可能是 logtorrent 承受不住某个时间点巨大的突发请求而造成的,经过再三的确认,我们发现并不是这个问题,并且经过不断的升级改造以及水平扩展,目前我们后端的一组 logtorrent 扛过 100k req/s 请求是完全没问题的,出问题的时间点,总请求只有不到 60k req/s 。

19:47 PM: 经过轮番的查看,我们发现某台 Kafka 机器的 latency 异常波动,并且数值相比正常的水准大大增加。
我们知道,Kafka 有非常良好的 fault-tolerance 机制,也就是说,在理想的 fail fast 的情况下,根据你 replica 的设置,可以宕掉任意数量不等的机器。但是,最坏的情况,不幸的被我们命中了,这种「要挂不挂」的状态导致了出问题的 Kafka 机器的 produce/consume 都受到了极大的影响。

19:53 PM: 在重启了出问题的 Kafka 机器,情况没有好转的情况下,我们直接停掉了这台机器。但是情况依然没有好转。因为雪崩效应,导致前面的 logtorrent 耗尽了系统资源无法再继续处理请求,一次 DDoS 攻击就这样形成了。

19:58 PM: 分批重启了 logtorrent,将系统资源加以释放,服务暂且恢复。

Continue reading