在实际工作中充满了连接池的使用,如JDBC连接池、JDBC连接池、jedis中连接池、http连接池以及tcp连接池等等,几乎需要使用连接的地方都会出现连接池。

0 为什么使用连接池

每次连接都需要经历建立连接(connect)->通信->关闭连接(Close),连接过程中的connect和close比较消耗系统资源。互联网绝大部分应用都是高IO的,在并发量较高时,频繁的connect和close将会成为系统的瓶颈。

连接池一般是在系统启动时初始化一批连接,当需要通行时,将从建立好的连接中找出空闲的连接用于通信,使用完毕之后再将连接放回连接池中,这样就避免了反复connect和close,提升性能。

1 连接池实现的关键点

  • 初始化连接
 /**
     * 初始化连接池
     * @param min 连接池最小个数
     * @param max 连接池最大个数
     * @param connectFactory 连接对象工厂
     */
    private void initPool(int min,int max,ConnectFactory<Pooled<T>> connectFactory){
        for(int idx = 0;idx<min;idx++){
            conList.add(connectFactory.newInstance());
        }
        this.min = min;
        this.max = max;
        this.connectFactory = connectFactory;
    }
  • 租用连接
   /**
     * 租用连接池
     * @return
     */
    public synchronized T lease(){
        for(Pooled<T> conn:conList){
            if(!conn.isUsed()){
                return conn.getPooledObj();
            }
        }
        expanse(1);
        return lease();
    }

    /**
     * 扩展连接池大小
     * @param extra
     */
    private synchronized void  expanse(int extra){
        if(conList.size()+extra>max){
            throw new IllegalArgumentException("extra is too far");
        }

        for(int idx=0;idx<extra;idx++){
            conList.add(connectFactory.newInstance());
        }
    }
  • 归还连接
    public synchronized void giveBack(T con){
        for(Pooled<T> ele:conList){
            if(ele.getPooledObj()==con){
                ele.free();
            }
        }
    }

其他关键问题

上面代码只是一个demo,在生产环境使用还有许多问题需要解决:

  • 连接池动态监控
  • 连接的可用性检测
  • 负载均衡、故障转移
  • 连接池耗尽的处理策略
  • 连接池自动回收策略

2 现有实现

References

连接池原来这么简单(一分钟系列)