1. 连接池相关技术调研

1.1. 池化技术

1.1.1. 池化技术概述

池化是一种通过复用来提升软件系统性能的的软件技术。
其原理是,通过复用对象来减少创建对象、垃圾回收的开销,这样能够减少资源对象的创建次数,提高程序的性能,特别是在高并发下这种提高更加明显。
使用池化技术缓存的资源对象有如下共同特点:

  • 对象创建时间长
  • 对象创建需要大量资源
  • 对象创建后可被重复使用

池化技术应用:

  • 线程池
    • JDK中ThreadPoolExecutor
    • Tomcat中的线程池
  • 内存池
  • 连接池
    • HttpClient连接池
    • JDBC连接池 (C3P0、BoneCP、DBCP等)
    • Redis 连接池 (jedis)
    • 等等

1.1.2. commons-pool2 包

commons-pool2是一个广泛使用的对象池组件,由apache基金会开源,当前最新版本是Version 2.8.0
核心类:

  • PooledObjectFactory:工厂类,负责具体对象的创建、初始化,对象状态的销毁和验证
  • ObjectPool:实现对对象存取和状态管理的池实现;如:线程池、数据库连接池
  • PooledObject:池化对象,是需要放到ObjectPool对象的一个包装类。添加了一些附加的信息,比如说状态信息,创建时间,激活时间,关闭时间等
  1. ObjectPool的核心数据结构:
  2. * private final Map<T, PooledObject<T>> allObjects 存储所有的对象(不含销毁的对象)
  3. * private final LinkedBlockingDeque<PooledObject<T>> idleObjects 后者用于存储空闲的对象,供borrow
  1. // commons-pool2的使用demo
  2. public static void main(String[] args) {
  3. // 创建池对象工厂
  4. PooledObjectFactory<Resource> factory = new MyPoolableObjectFactory();
  5. GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
  6. // 最大空闲数
  7. poolConfig.setMaxIdle(5);
  8. // 最小空闲数
  9. poolConfig.setMinIdle(1);
  10. // 最大池对象总数
  11. poolConfig.setMaxTotal(20);
  12. // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
  13. poolConfig.setMinEvictableIdleTimeMillis(1800000);
  14. // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
  15. poolConfig.setTimeBetweenEvictionRunsMillis(1800000 * 2L);
  16. // 在获取对象的时候检查有效性, 默认false
  17. poolConfig.setTestOnBorrow(true);
  18. // 在归还对象的时候检查有效性, 默认false
  19. poolConfig.setTestOnReturn(false);
  20. // 在空闲时检查有效性, 默认false
  21. poolConfig.setTestWhileIdle(false);
  22. // 最大等待时间, 默认的值为-1,表示无限等待。
  23. poolConfig.setMaxWaitMillis(5000);
  24. // 是否启用后进先出, 默认true
  25. poolConfig.setLifo(true);
  26. // 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
  27. poolConfig.setBlockWhenExhausted(true);
  28. // 每次逐出检查时 逐出的最大数目 默认3
  29. poolConfig.setNumTestsPerEvictionRun(3);
  30. // 创建对象池
  31. final GenericObjectPool<Resource> pool = new GenericObjectPool<Resource>(factory, poolConfig);
  32. for (int i = 0; i < 21; i++) {
  33. new Thread(new Runnable() {
  34. @Override
  35. public void run() {
  36. try {
  37. // 注意,如果对象池没有空余的对象,那么这里会block,可以设置block的超时时间
  38. Resource resource = pool.borrowObject();
  39. System.out.println(resource);
  40. Thread.sleep(3000);
  41. pool.returnObject(resource);
  42. } catch (Exception e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }).start();
  47. }
  48. }

1.1.3. Alibaba-Druid

阿里巴巴数据库事业部出品,为监控而生的数据库连接池。号称是Java语言中最好的数据库连接池,能够提供强大的监控和扩展功能。
Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
同时Druid不仅仅是一个数据库连接池,它包括三个部分:

  • 基于Filter-Chain模式的插件体系。
  • DruidDataSource 高效可管理的数据库连接池。
  • SQLParser

Druid的功能:

  • 替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
  • 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
  • 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
  • SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
  • 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。