mysql 短连接压测遇到的问题及查找解决思路[终于找到原因了]

7 篇文章 0 订阅
5 篇文章 0 订阅
问题描述:
1. 100个并发短连接压测drds,出现客户端部分连接block住,一直是established状态
但是drds server的tcp连接确都已经断了。


问题分析查找:
1.server 8066 没有tcp连接
root@t01a03038 ~
# netstat -anpt | grep 8066 | grep 10.202.66.8 | grep ESTABLISHED

client确有5个tcp established 连接
root@t01a03035.dg.aliyun.com # netstat -anpt | grep 8066
tcp        0      0 10.202.66.8:49907           10.202.66.10:8066           ESTABLISHED 661/short_connectio
tcp        0      0 10.202.66.8:49902           10.202.66.10:8066           ESTABLISHED 661/short_connectio
tcp        0      0 10.202.66.8:49900           10.202.66.10:8066           ESTABLISHED 661/short_connectio
tcp        0      0 10.202.66.8:49903           10.202.66.10:8066           ESTABLISHED 661/short_connectio
tcp        0      0 10.202.66.8:49909           10.202.66.10:8066           ESTABLISHED 661/short_connectio

2.检查客户端pstree (有5个执行线程还在运行中)
root@t01a03035.dg.aliyun.com # pstree 661
short_connectio───5*[{short_connectio}]

3.检查客户端pstack (检查线程是否有死锁,看卡在哪里)
root@t01a03035.dg.aliyun.com # pstack 661
Thread 6 (Thread 0x5b31c940 (LWP 716)):
#0  0x0000003bc2cc5f3b in read () from /lib64/libc.so.6
#1  0x000000361bc82b75 in vio_read_buff () from /usr/lib64/mysql/libmysqlclient_r.so.16
#2  0x000000361bc83e99 in ?? () from /usr/lib64/mysql/libmysqlclient_r.so.16
#3  0x000000361bc84285 in my_net_read () from /usr/lib64/mysql/libmysqlclient_r.so.16
#4  0x000000361bc7e08a in cli_safe_read () from /usr/lib64/mysql/libmysqlclient_r.so.16
#5  0x000000361bc7f6bc in mysql_real_connect () from /usr/lib64/mysql/libmysqlclient_r.so.16
#6  0x0000000000400bd4 in init_connect ()
#7  0x0000000000400ce0 in run ()
#8  0x0000003bc38064a7 in start_thread () from /lib64/libpthread.so.0
#9  0x0000003bc2cd3c2d in clone () from /lib64/libc.so.6
Thread 5 (Thread 0x5e322940 (LWP 722)):
#0  0x0000003bc2cc5f3b in read () from /lib64/libc.so.6
#1  0x000000361bc82b75 in vio_read_buff () from /usr/lib64/mysql/libmysqlclient_r.so.16
....
都一样,卡在mysql vio的read()上了,这个是mysql客户端读网络数据的地方,说明,mysql 客户端在等待读
所有的线程都显示mysql client在read状态,但是server缺已经将tcp连接关闭了,这个就比较奇怪了。

4.需要抓包,查看每个线程连接的包
安装libpcap,安装tcpdump ,需要稍微高一点的版本,
我安装的是root@t01a03035.dg.aliyun.com # tcpdump --help
tcpdump: invalid option -- -
tcpdump version 4.4.0
libpcap version 1.4.0

因为低版本的tcpdump 不支持-B 参数,设置buffer_size
否则,会因为并发太高,导致tcpdump来不及从libpcap的buffer里面抓包而丢包

tcpdump -nnn "port 8066" -B 190000000 -s 2048 -X -tt -w a.cap
写的是binary的,需要重新读出来
tcpdump -r a.cap > 1.txt

观察4个hang住线程的临时端口的包:
13:19:16.073586 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [S], seq 2657237807, win 5792, options [mss 1460,sackOK,TS val 25239258 ecr 25215038,nop,wsc
ale 9], length 0
13:19:16.074259 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [S.], seq 1133617369, ack 2657237808, win 5792, options [mss 1460,sackOK,TS val 25215041 ecr
25239258,nop,wscale 9], length 0
13:19:16.074270 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [.], ack 1, win 12, options [nop,nop,TS val 25239259 ecr 25215041], length 0               
13:19:20.322898 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [S.], seq 1133617369, ack 2657237808, win 5792, options [mss 1460,sackOK,TS val 25219291 ecr
25239259,nop,wscale 9], length 0
13:19:20.322949 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [.], ack 1, win 12, options [nop,nop,TS val 25243508 ecr 25219291,nop,nop,sack 1 {0:1}], len
gth 0
13:19:26.372870 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [S.], seq 1133617369, ack 2657237808, win 5792, options [mss 1460,sackOK,TS val 25225341 ecr
25243508,nop,wscale 9], length 0
13:19:26.372916 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [.], ack 1, win 12, options [nop,nop,TS val 25249558 ecr 25225341,nop,nop,sack 1 {0:1}], len
gth 0


1. 客户端到sever 发送 sync包
2. server 收到包之后,也发送sync包
3. 客户端发送ack 包
4. server又发送了 sync包(这里之后出错了)

看样子分析是:tcp3次握手的最后一次从客户端发送ack到server,server不知道怎么回事,没有收到或则不认,认为客户端没有发送最后的ack过来,于是总共重试3次,就把tcp连接给关了,但是不知道什么原因,客户端还是在等待Server发送建立连接之后的数据包,所以一直卡在那里。下面是正常的mysql 建立连接的过程。

按照正常mysql登录的连接包如下:(从登录成功到close连接的过程)
13:19:10.437046 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [S], seq 2569166811, win 5792, options [mss 1460,sackOK,TS val 25233622 ecr 25209404,nop,wsc
ale 9], length 0
13:19:10.440036 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [S.], seq 1127980819, ack 2569166812, win 5792, options [mss 1460,sackOK,TS val 25209405 ecr
25233622,nop,wscale 9], length 0
13:19:10.440061 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [.], ack 1, win 12, options [nop,nop,TS val 25233625 ecr 25209405], length 0
13:19:10.440646 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [P.], seq 1:68, ack 1, win 12, options [nop,nop,TS val 25209408 ecr 25233625], length 67
13:19:10.440682 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [.], ack 68, win 12, options [nop,nop,TS val 25233626 ecr 25209408], length 0
13:19:10.440738 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [P.], seq 1:76, ack 68, win 12, options [nop,nop,TS val 25233626 ecr 25209408], length 75
13:19:10.443767 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [.], ack 76, win 12, options [nop,nop,TS val 25209409 ecr 25233626], length 0
13:19:10.443860 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [P.], seq 68:79, ack 76, win 12, options [nop,nop,TS val 25209409 ecr 25233626], length 11
13:19:10.443891 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [P.], seq 76:81, ack 79, win 12, options [nop,nop,TS val 25233629 ecr 25209409], length 5
13:19:10.443904 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [F.], seq 81, ack 79, win 12, options [nop,nop,TS val 25233629 ecr 25209409], length 0
13:19:10.444226 IP 10.202.66.10.8066 > t01a03035.dg.aliyun.com.55748: Flags [F.], seq 79, ack 82, win 12, options [nop,nop,TS val 25209412 ecr 25233629], length 0
13:19:10.444241 IP t01a03035.dg.aliyun.com.55748 > 10.202.66.10.8066: Flags [.], ack 80, win 12, options [nop,nop,TS val 25233629 ecr 25209412], length 0

1. c - > s sync 包
2. s -> c sync 包
3. c -s ack
4. s->c token p包
5. c->s ack
6. c->s 加密后用户名密码等数据 p包
7. s -> c ack
8. s -> c 认证包 p 包
9. c -> s ??这里发送什么数据?? p包
10. c-s  fin 包,请求关闭连接
11. s-c fin 包,关闭连接
12. c-s ack包

从现象来看,怀疑是操作系统的参数问题导致,因为对于drds server来说,最后一个ack包没有收到之前是还没有进入业务系统的。

于是检查了压测过程中drds 服务器的time_wait的连接,不是很多,最多的时候也就500个左右,查看fd个数
ulimit -n 有5000个,应该早足够
查看sysctl -a | grep tcp_tw
发现tcp_tw_reuse = 0
       tcp_tw_recycle = 0

为了加快time_wait端口的重用,修改这两个参数
vim /etc/sysctl.config
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1

sysctl -p保存生效
继续测试,问题如故。。。

----------------------
换个招,对比压测一下mysql
试验10次,没有一次出现,难道是mysql所在服务器和drds所在服务器的系统参数配置不一致导致??

将drds server 部署到mysql所在机器
执行。
问题如故。。。。!!!!!
现在基本可以确定是应用层的问题导致的了~~~~

----------------------------------------------------------------------------华丽的分割线-----------------------------------------------------------------------
参考这篇文章

drds nio 的sock bind:
this.serverChannel.socket().bind(new InetSocketAddress(port));
默认的使用的重载函数是没有int backlog这个参数:
  • backlog - requested maximum length of the queue of incoming connections. 


具体的原因就如我上面分析的,原因是并发压力太大,导致这个queue满了,并导致内核的overflow
Syncookies causes the server to send a SYN-ACK, but immediately forget about the connection. Then, on the client side, this huge number of SYN-ACK packets arrive, causing it to reply with a huge batch of ACK packets. Some of these packets get lost because some buffer somewhere overflows. I believe this problem is aggravated by the fact that my client load generator is running in a virtual machine, so there is extra batching and extra buffers where packets can get dropped. As a result: on the client, some connections are established, but the server has forgotten about them because of syncookies.

所以导致最后server 没有收到client 发送过来的最后一个ack包,于是重复发送3次到客户端之后,就认为失败结束了。而客户端认为连接已经建立成功了。
但是正常的一般的tcp协议,此时,mysql client 会发送业务的数据,发现server 不通会再次关闭该连接。但是mysql 协议是tcp连接建立以后,需要等待server 发送认证token,但是server因为连接都已经不存在,所以根本不会发送认证token,于是导致客户端一直傻等着。

具体的原因找到了,但是,没有找到解决的办法,暂时缓解该问题的办法是,增加backlog的长度。
        this.serverChannel.socket().bind(new InetSocketAddress(port),4096);

再次压测,100个并发已经不会出现这个问题了,但是200个偶尔会出现,300个几乎必现。

但是300个直接压mysql 会出现这个问题,所以,怀疑mysql 已经经过了某种优化。。。。

这个问题在应用层(不去修改mysql协议的情况下)已经很难解决了,所以,暂时得hold了。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值