您的位置:首页 > 理论基础 > 计算机网络

一个TCP连接池的自我修养-如mysql-client、http-client、redis-client

2017-10-10 13:42 267 查看

问题:单服单天过亿请求中,出现0.0001%的500怎么回事?

日志中不定时出现
mysql gone away
connect timeout
,
reset by beer
等错,原因不明。

access-log同样不定时出现5xx错。

感觉MySQL运行正常,没压力,没慢查,sql使用主键查询–不知道问题在哪?

连接MySQL的代码使用keepalive。

这个时候,你是否怀疑过是连接库的问题?

一个TCP连接池的自我修养

keepalive特性,idle-connection可设定。

one retry 特性。

max-connection 设定。

read/write timeout 设定。

max-connection 特性是必需的

如果是mysql连接库,max-connection不设上限,要不就是造成后端的mysql连接过多,拖跨mysql。

如果是http连接库,就会造成服务应用大量并发请求在等待,不论阻塞、非阻塞同样会。即使像go语言,这样原生性非阻塞、轻并发语言。大量的等等请求,一样会有耗尽内存的风险。换是python、php一个线程就以M为单位内存计算的,并发更低。

所以必需带有合理的
setMaxConnection()
接口。

非常重要的容错

当连接池满载时,一个新线程请求一个新连接时,采用什么策略?
等待?
还是直接返回try-later?


read/write timeout 也是必需的

任何的TCP连接,都可能出现的读/写超时,对上层来说就是出错了,如果timeout很长,即直接阻塞了此线程或微线程。大量阻塞同样地引发内存风险,也不存在语言上的差别。所以,合理的timeout值,特别是read timeout,经常地出现一种,对方服务器处理慢,不能及时返回结果,而client端断开后,对方继续完成了工作,而client方以为没完成,而重发请求,如果没防重入,会造成数据不一致。 为什么重发?参考one-retry特性说明。

keepalive+ idle-connection 作为可选特性

追求高性能,TCP的keepalive,
连接重用
是必需的。

而idle-connection作为闲时保持最低的连接数量,当上层业务要使用时马上可用。

还有一种做法是 connection-keep-timeout, 即每个连接闲下来后,多长时间后自动关闭。

MySQL中就可以使用
set timeout=n;
显式设置每个连接的timeout值,否则使用服务端默认统一值。

one retry 特性,在keepalive打开时,必需加上

one-retry特性,并不是每个程序员都注意并知道的一个常规特性。

而此特性正是解决 我们项目中
0.0001% 5xx 问题
的关键。

一旦开启idle-connection特性后, TCP客端端会保持一定数量在连接在连接池中,上层要使用时返回一个连接。

而像MySQL的通信协议中是有Ping指令的,就是用于测试连接是否有效。所以当返回一个连接时,如果是MySQL,就可以用Ping测试一下,确保返回给上层的是可用连接。

原因是连接池中的连接不一定有效,即使你代码中监听了socket的close事件,但由于服务端可能使用了LVS这样的虚拟IP,很可能出现服务端单方面断开了TCP连接,客户端是没法感知(注:这里并不是说使用LVS就会有这种现象,只能用于举例说明,服务端可能使用了客户端无法感知的连接层)。除此以后,TCP断开时4次握手不完全,也是很正常的现象。

为了上层能获得一个可用连接池,没有ping协议的HTTP协议怎么办?

可以使用one-retry特性:

上层发送一个请求调用,由
连接池
执行, 如出现
reset by beer
mysql was gone away
情况的,可以
新建一次连接,重发一次请求
。我把这种行为称为
one-retry
, 上层不必感知。若重试的请求,也出来同样的错误,就应该向上层返回或异常了–视语言而定。

原文来自
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcp