HikariCP连接池分享
希望可以带着大家了解HikariCP连接池,并对线上问题给出解决思路和方案。然后可以自己去看一下HikariCP,个人感觉HikariCP实现的比较精巧,代码很值得一读,我这里会给出整体的设计和一些主流程,可以减少大家深入HikariCP的时间。
为什么分享HikariCP连接池?
线上问题:获取连接池失败?
结果:整个服务在一段时间不可用
引出了这些问题,是我想到的一些问题,也是我的解决问题的思路
1、什么是连接池?
2、为什么用连接池?
3、为什么用HikariCP连接池?
4、HikariCP连接池有什么特色?
5、系统怎么加载HikariCP连接池的?
6、一个获取Connection的过程是什么?
7、为什么获取连接池失败?连接池太小?怎么解决线上问题?
8、HikariCP连接池的实现原理(是怎么实现的?):
设计哲学
整体设计原理
源码
目录
-
什么是连接池
-
连接池的功能
-
Spring Boot 加载HikariCP的流程
-
HikariCP的设计
设计哲学
设计原理
核心源码
总结 -
线上问题解决思路
1、拆分业务
2、加大线程池
3、扩容
4、使用flexyPool -
回顾
什么是连接池
日常生活中我们买车,都是商家预先买一批,我们去买的时候直接交钱,就可以开回来家了,而不是等着我们买一辆车,商家去制造商那里制造一辆,然后运过来。在日常开发中最常用的是Java线程池(Tomcat线程池),创建和消费线程比较耗用资源,并且耗费时间,甚至有些情况下还会带来一定的副作用。因此有了连接池组件,可以预先在池子里建几个,等需要用的时候去取或者激活,用完之后放到池子复用,避免了大量的创建和销毁代价。就我们产品而言,类似的还有Redis连接池(LettucePool),HttpClient连接池(ConnPool)等。
连接池和线程池还是有一定区别的,但是思想是相同的,(都是避免关键资源大量的重复创建和销毁)为了效率和性能。池化思想还有内存池(Netty,Kafka),对象池(单例,享元模式)。
连接池的功能
或者说如果不用连接有什么问题,使用连接池之后有什么作用;
主要问题:
- 大量的连接池会对服务端造成比较大的压力,甚至会造成服务器内存溢出;
- 创建和销毁连接是比较耗时的;
- 频繁的创建连接会导致JVM的临时对象比较多,GC频繁;
- 对于客户端而言会出现大量的TIME_WAIT的TCP状态,调优会比较麻烦;(只Redis没有使用连接池,系统的TIME_WAIT就可以达到5到6千左右);
优点
- 资源的复用,减少了大量的创建和销毁代价;
- 系统响应速度会更快;
- 连接管理更加可控;
- 对服务端的连接有个上限,防止大量连接对服务端造成影响。
Spring Boot 加载HikariCP的流程
常用的连接池有 Tomcat JDBC Pool、 Druid、HikariCP
Tomcat Pool是Spring Boot 1.5默认的连接池,之前查Link模块问题的时候还遇到过,在Spring Boot2.0之后默认使用HikariCP:
系统配置:spring.datasource.type:com.zaxxer.hikari.HikariDataSource
DataSourceAutoConfiguration
DataSourceConfiguration
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"com.zaxxer.hikari.HikariDataSource",
"org.apache.tomcat.jdbc.pool.DataSource",
"org.apache.commons.dbcp2.BasicDataSource" };
public static Class<? extends DataSource> findType(ClassLoader classLoader) {
for (String name : DATA_SOURCE_TYPE_NAMES) {
try {
return (Class<? extends DataSource>) ClassUtils.forName(name,
classLoader);
}
catch (Exception ex) {
// Swallow and continue
}
}
return null;
}
HikariCP的设计
HikariCP是一个快速、简单、可靠的高效能的JDBC连接池组件。
设计哲学
简单,高效是HikariCP的设计哲学,简单是代码尽量精简,配置使用尽量易于使用;HikariCP的作者拒绝了很多的功能请求;简单就是大道至简。
设计原理
常用的配置:
spring.datasource.hikari.connection-timeout
spring.datasource.hikari.idle-timeout
spring.datasource.hikari.max-lifetime
spring.datasource.hikari.maximum-pool-size
spring.datasource.hikari.minimum-idle
连接池负责连接的分配、管理和释放;主要职责:
- 维护一个队列存放连接
- 支持最小连接数,最大连接数
- 每个连接数有个最大生存时间(数据库有个最大的wait_time)
- 维护最小连接数
- 线程安全的给上层业务提供连接,如果达到最大连接数会阻塞线程,支持超时
如何实现?
线程模型
- HouseKeeper
HouseKeeper任务的线程池houseKeepingExecutorService:
final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, threadFactory, new ThreadPoolExecutor.DiscardPolicy());
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
executor.setRemoveOnCancelPolicy(true);
1, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue(), threadFactory, handler
- PoolEntryCreator addConnectionExecutor
1 /*core*/, 1 /*max*/, 5 /*keepalive*/, SECONDS, new LinkedBlockingQueue<>(config.getMaximumPoolSize()), threadFactory, policy
- anonymous closeConnectionExecutor
1 /*core*/, 1 /*max*/, 5 /*keepalive*/, SECONDS, new LinkedBlockingQueue<>(config.getMaximumPoolSize()), threadFactory, policy
获取连接