内容简介:在分布式系统中,用连接池缓存住连接,来节省连接反复销毁和创建的成本,是一种很常见的做法。但是在高可用的分布式系统中,”切换”是一个非常普遍的操作,切换就会造成连接池失效的问题。TCP 虽说是”有连接的”,但这个连接实际上是一个虚拟连接。客户端用一段内存保存连接的五元组(源端口,源IP,目的端口,目的IP,协议),服务端也保存一个这样的五元组,双方就认为有这么一个连接了,可以通过这个连接收发。但是假如客户端保存有这个五元组,服务器因为某种原因将这个五元组删掉了,就会造成客户端单方面认为有这么一个连接,而服务器
在分布式系统中,用连接池缓存住连接,来节省连接反复销毁和创建的成本,是一种很常见的做法。但是在高可用的分布式系统中,”切换”是一个非常普遍的操作,切换就会造成连接池失效的问题。
TCP 虽说是”有连接的”,但这个连接实际上是一个虚拟连接。客户端用一段内存保存连接的五元组(源端口,源IP,目的端口,目的IP,协议),服务端也保存一个这样的五元组,双方就认为有这么一个连接了,可以通过这个连接收发。
但是假如客户端保存有这个五元组,服务器因为某种原因将这个五元组删掉了,就会造成客户端单方面认为有这么一个连接,而服务器不承认(反过来也有这个问题,但是服务器丢失连接的情况更加普遍也更加严重)。当客户端想使用这个连接向服务器发送请求的时候,会被服务器拒绝。
保持一个连接池的做法会使这个问题更加严重,因为连接用完之后不会马上销毁,等待下一次使用,这段时间天知道会发生什么。比如说应用连接数据库这种情况,一般会有连接池保持和数据库的连接。假如 DB 重启了、DB 端因为超时或者其他什么原因把连接关闭了(即把内存的五元组删掉)、DB 出现故障,从一个IP迁移到另一个IP了,都会造成客户端连接池中的连接不可用,这个时候客户端通过这些”坏连接”向DB发送请求,就会失败。(多久时间会返回失败也是一个问题,这受 socketTimeout 参数和 Linux 系统参数影响,具体可见这篇 Datebase timeouts .)
除了DB之外,像 Nginx 保持向后端应用的连接等负载均衡设备通常也有这种问题,只不过有的组件自身选好了方案处理掉了,有的是暴露出来选项让你自己设置。本文讨论处理这种问题的几种思路。
一、失败了就是败了,重建就是
这是成本最低的方式,连接池的实现一般都会包括如果连接不可用,就删除并重建。影响是会失败一些请求(数量=连接池的数量)。
当然有些时候我们是可以预测需要切换DB的,有条件的话可以将业务切换走,然后再切换DB。业务回切之前先对应用发送一波压测流量,用假的业务流量刷掉不用的连接。
二、主动保持
之前在博客中介绍过 TCP Keepalive,可以正好解决这种场景。就是设置一个定时器,定时检查连接是否还可用。
对于 TCP 来说,由于这是一个基于流的协议,所以可以发送一段长度为0的片段来检验是否能收到 ACK。对于 MySQL 来说,要看驱动程序的实现,比如如果实现了 ping 函数 可以使用 ping;如果没有 ping 可以使用 SELECT 1。对于 redis 来说也有 ping 命令。Jboss 提供的 background-validation 参数,就是这个原理。
一般来说这个方案是复杂度低,并且比较有效的。缺点是当分布式的连接池巨大的时候,比如上千台机器的话,每台 DB 要承受测活的连接数是 机器数 * 连接池大小,资源消耗是很大的。
三、使用较小的 idle timeout 和 小连接池
连接池一般都提供设置两个参数:
- idle timeout:当 idle 时间超过之后,会主动回收;
- min connections:连接池最小要保持多少连接;
通过设置 idle timeout,可以保证没有连接是开头说的那种很长时间没用过的连接,因为都会回收掉了。
但是这里会存在一个问题:min connections 要保证连接池有多少个连接,假如设置的是10,平时只用5的话,那么因为 idle timeout 参数会回收5个连接,导致连接池会新建5个新连接。过一段时间,因为有一些用不到又会被回收,就造成了在反复创建连接。
假如采取另一种策略:回收 idle timeout 的连接但是保证连接数要大于 min connections,假如连接数不大于 min connections,那么即使 idle timeout 也不回收。这样可以解决上面的问题,但是会造成无法保证 connection pool 里面的连接都是新鲜的,回到我们最初的问题了。
所以这种方案其实又要做一个 trade off,如果能保证连接需求的比较稳定,需要的连接数总是大于 min connections 又不至于大太多,倒是可以用在这种方案。
四、每次使用之前检查一次
顾名思义,每次使用连接之前先检查一下这个连接是否可用。成本太高一般不用,对客户端来说会增加延迟,对DB来说会增加压力。
实现的话,可以看下 DBCP 的 TestOnBorrow 。
五、HAProxy
HAProxy 并不能说是一个思路,只是一个现成的工具,它是一个正向代理,实现了连接的测活和切换。HAProxy 的原理我还没研究,但是应该不出这几种思路。甚至是可以让你选的,毕竟它配置项目那么多。
HAProxy 怎么用呢?考虑有多个应用连接多个数据库的场景,从原来的直接连接变成通过 HAProxy 连接。当需要切换的时候,应用不需要感知 DB IP 的变化,而是 HAProxy 更改后端 DB 的 IP,从而对应用透明了,应用只需要一个 DB 集群的 URL 就可以了。
App 直接连接 DB
App 通过 HAProxy 连接 DB
另一方面,也节省了 DB 的连接数。
以上所述就是小编给大家介绍的《连接池中的连接失效的几种处理方案》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- golang thrift client pool 解决 server 重启连接失效
- 行间距失效问题
- 前端实现设置缓存数据定时失效
- 5分钟探究Spring事务失效原因
- Andorid内Aspectj切面失效分析
- Xcode 代码提示失效以及引发的感想
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Everything Store
Brad Stone / Little, Brown and Company / 2013-10-22 / USD 28.00
The definitive story of Amazon.com, one of the most successful companies in the world, and of its driven, brilliant founder, Jeff Bezos. Amazon.com started off delivering books through the mail. Bu......一起来看看 《The Everything Store》 这本书的介绍吧!