type
status
date
slug
summary
tags
category
icon
password
基于对DOT/DOH进行性能测试过程中遇到的几个问题进行总结
背景
每一个版本都会对dnproxy代理服务进行一次性能测试,主要的测试指标为:
- 使用长链接时,doh、httpdns的QPS
- 使用短链接时,doh、httpdns的QPS
- 开启缓存与未开缓存时,doh、httpdns的QPS
测试使用的打压工具为:wrk
使用的命令如下:
相关参数:
-t8:指定wrk使用的线程数为8
-c4000:指定建立的TCP连接数为4000个
-d 20: 指定打压的持续时间为20s
-H "Connection: close": 加上该header表示使用短链接,否则默认wrk使用长链接
打压结束后会输出如下信息:

其中最重要的指标就是Requests/sec即qps。
问题一:新机器测QPS上不去
当时测试反馈使用dnsproxy在新物理机(16核)进行打压时QPS处于2w且CPU占用只有130%不到,不应该只有这么低的表现。由于dnsproxy这个程序并未进行任何代码的改动,之前是能够到达15w左右的QPS,所以先排除是代码修改引入的性能不佳问题,那么初步猜测可能是网络层面出现了什么问题。
在TCP进行三次握手的时候,linux内核会维护两个队列,分别是:
- 半连接队列,也称 SYN 队列;
- 全连接队列,也称 accept 队列;
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。
其中这两个队列在linux的系统参数中有对应的默认值,分别为:
全连接的的最大值由
somaxconn决定半连接的最大值由上面两个参数共同决定,计算方式和条件比较多感兴趣可自己查询
会不会是队列设置的太小导致的打压时很多tcp连接溢出后被丢弃了?
为了验证猜想,我们首先在服务端查看dnsproxy服务实际使用到的全连接队列是多少,使用
ss -lnt查看处于LISTEN状态的对应端口的Recv-Q及Send-Q。- Recv-Q:当前全连接队列的大小,也就是当前已完成三次握手并等待服务端
accept()的 TCP 连接;
- Send-Q:当前全连接最大队列长度,下面的输出结果说明监听5353端口的 TCP 服务,最大全连接长度为4096;
进行wrk持续打压发现,receive值一直没有超过其最大值
查看是否存在队列溢出丢弃的情况,使用
nestat -s |grep 'overflowed'发现并没有持续的正常,所以排除服务端连接队列参数过小导致的问题会不会是客户端就没有建立那么多连接数?
使用ss -s 查看客户端和服务端的TCP连接数发现,和wrk设置的2000连接数相差不大,排除客户端的问题。
会不会是网卡收包量或者路由器的问题?
首先使用
tcpdump - i zeth0 port 5353 -w dnsproxy.pcap进行抓包,然后使用wireshark打开进行分析,这里分享几个技巧:- 点击左下角的小圆点,wireshark会快速分析列出可能存在的问题,此时主要关注warning部分,如下面图所示可以看出存在两个需要关注的问题:
- This frame is a (suspected) out-of-order segment
- D-SACK Sequence
展开起列表点击其中一条我们就定位到对应的行,发现存在大量的Retransmission以及Dup ACK说明出现了包大量重传的问题,那就可能出现了网络拥塞。
我们进一步去验证起网卡收包流量情况,使用
sar -n dev 1 100 |grep zeth0 统计网卡的发送及接受流量。使用能够正常打压上去的物理机和有问题的机器进行对比,发现有问题的机器收包流量只有2m/s,是存在问题的。于是尝试使用换一个网卡直连的方式进行测试,发现流量正常了,QPS也上去了。
问题二: 长连接QPS上得去,短连接QPS上不去
测试在使用
-H "Connection: close"进行短连接测试发现QPS又比之前的值差了不少,使用的压力机和测试机都和测试长连接使用的是相同的,所以排除上面我们说的网卡、队列的问题影响,会不会是长短连接机制引起?因为使用短连接,那么每一次请求就会有3次握手和4次挥手的流程。
为了找出具体的问题,我又尝试用另一条机器对测试机进行打压测试,发现该机器使用wrk进行打压的数据就比较正常,那问题就确定是压力机侧引起的。
我们都知道TCP 连接是基于五元组的,那么对于客户端来说,源 IP、目的 IP、目的端口、 协议,这四个元素都不会变化,唯一会变的就是自己的源端口了
会不会是端口范围太小导致的?
查看系统设置的端口范围
发现端口范围也挺大的,那台能够正常打压上去的压力机也是这个范围,所以应该不是这个参数的问题。
会不会是连接状态的问题
在查看一下压力机连接数处于各个状态的数量
在筛选出5353端口使用的连接数
发现处于异常的机器有2.8w个连接是处于TIME-WAIT状态,并且一直没有释放掉,而正常的机器会只有1w不到的TIME-WAIT也不会随着打压一致变高,于是在对两个机器配置进行对比。
发现在有问题的机器上
net.ipv4.tcp_tw_recycle = 1这个参数没有被设置,先解释一下这两个参数的含义
- net.ipv4.tcp_tw_reuse = 0 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
- net.ipv4.tcp_tw_recycle = 0 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
从字面意思分析可能就是因为处于TIME-WAIT连接数太多且没有快速回收导致端口不够用,短连接进行建连上不去。于是在新环境添加上该参数后,结果报错了...
该配置参数竟然无法使用,
查看了一下linux的版本内核
发现这两台机器版本差异比较大,查看相关资料才得知Linux 从4.12内核版本开始移除了该参数设置,感兴趣的可以自行去查看具体的原因。那无法使用这个参数,有没有其他参数可以控制处于TIME-WAIT的连接数最大值呢?果然,linux提供了相关的设置参数,那就是:
net.ipv4.tcp_max_tw_buckets将该参数设置为一个比较小的值进行测试
进行测试后发现QPS就正常了,同时处于TIME-WAIT的连接数也不到1000,终于解决了这个问题!
- 作者:Ryan Wu
- 链接:https://hexo.fridaylab.top/article/b4a0374c-5ebd-47da-998f-f368889a354e
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。