最近连续解决两起连接泄漏的问题,期间阅读了大量开源源码,发现开源软件中设计的连接池,用的也都是一些常规手段,本文为大家揭开这层神秘的面纱。
概述大多数应用中应该都是用的TCP协议,TCP连接在建立阶段会经过3次握手,销毁阶段会经过4次握手。标准网络是分7层的,每一层都有各自的协议头,应用层拿到的有效数据,在整个报文中占比没这么大。TCP握手阶段的报文,对应用层来讲都是额外的负担。所以很多客户端都会设计连接池,来复用已建立的连接。减少创建连接带来的消耗。
连接池本身不复杂,如果不想做的通用,少量的代码就能够实现。下图是一个连接池中必要的组件。
上图各组件含义:
Client-客户端,屏蔽底层连接细节,使用它可以方便的与远端交互;比如RedisTemplate、HttpClient、KafkaProducer等。Connection Manager-连接管理器,Client内部在与远端交互时需要获得连接,连接既然是被复用的肯定是需要被管理起来,因此衍生出连接管理器的概念。Pool-缓冲池,用于存储连接的;里面分idle、in use。Validator-校验器,当应用负债较低的时候,连接池中的连接可能很久后才会被重新使用。有时候服务端会配置超时时间,连接空闲一段时间后会被服务端主动关闭,因此连接池中的连接可能已经无效了。获取空闲连接后,需要使用校验器进行校验,防止无效的空闲连接返回到上层。Cleaner-清理器,连接池一般会配置两个参数,分别为MinConnectionCount和MaxConnectionCount,类似java线程池中的核心线程数和最大线程数,用于应对闲时和忙时,减少资源浪费。经历过忙时后,不需要这么多连接资源了,因此需要有机制去清理闲置资源。Connection Factory-连接工厂,Connection Manager仅仅只负责管理职责,为了方便扩展,需要抽象出连接工厂这个概念,当连接池的资源不足,需要创建实际的连接时,由这个对象负责。 重点对象分析 connection wrapper
连接池的设计目标就是让使用者无感,如果底层的connection不进行包装,直接返回给上层使用,上层使用完后调用close方法就会销毁这个对象,使之无法得到复用。因此需要使用wrapper包装connection,并覆写close等方法进行拦截,让框架有机会去进行资源回收。
下面以Jedis的源码为例。



