关于数据库连接池:连接池-HikariPool-一-基础框架及初始化过程
后面做了n多筹备,包含同步队列、阻塞队列、线程池、周期性线程池等等,明天终于能够开始深入研究连接池了,从HikariPool开始。 连接池存在的起因和线程池大略相似,因为数据库连贯的获取是有开销的,频繁获取、敞开数据库连贯会带来不必要的开销,影响零碎性能。所以就有了数据库连接池。 数据库连接池技术提前创立好数据库连贯,并对数据库连贯进行池化治理:连贯创立好之后交给连接池,利用须要连贯的时候间接从连接池获取、而不须要创立连贯,应用完之后归还给连接池、而不是敞开连贯。从而缩小频繁创立、敞开数据库连贯锁带来的开销,极大进步零碎性能。 明天从HikariPool开始,从源码角度学习理解数据库连接池的实现原理。HikariPool是目前公认性能最好的数据库连接池,同时也是SpringBoot2.0当前的默认连接池,置信今后会有越来越多的公司和我的项目应用HikariPool连接池。 对于数据库连接池的根本认知先对数据库连接池的根本工作原理做个理解,不论是HikariPool、还是druid,所有的数据库连接池应该都是依照这个基本原理工作和实现的,带着这个思路去学习数据库连接池,防止盲人摸象。 数据库连接池肯定会蕴含以下根本逻辑: 创立连贯并池化:初始化的时候创立、或者是在利用获取连贯的过程中创立,连贯创立好之后放在连接池(内存中的容器,比方List)中保留。获取数据库连贯:接管了获取数据库连贯的办法,从连接池中获取、而不是创立连贯。敞开数据库连贯:接管了敞开数据库连贯的办法,将连贯偿还到连接池、而不是真正的敞开数据库连贯。连接池保护:连接池容量、连贯超时清理等工作。带着这个思路钻研HikariPool的源码,会有事倍功半的效用。 意识HikariPool的构造包含以下几个局部: ConcurrentBag & PoolEntryaddConnectionExecutorhouseKeeperTaskHikariProxyConnectioncloseConnectionExecutorConcurrentBag直译就是“连贯口袋”,就是放数据库连贯的口袋,也就是连接池。 ConcurrentBag有3个保留数据库连贯的中央(池): threadList:是一个ThreadLocal变量,保留以后线程持有的数据库连贯。sharedList:是一个CopyOnWriteArrayList,线程平安的arrayList,数据库连贯创立后首先进入sharedList。handoffQueue:是一个SynchronousQueue,数据库连贯创立、进入sharedList后,也会进入handoffQueue期待连贯申请。除此之外,ConcurrentBag还有一个比拟重要的属性waiters,记录向连接池获取数据库连贯而不得、期待的线程数。 PoolEntry连接池中存储的对象不是Connection,也不是Connection的代理对象,而是PoolEntry。 PoolEntry持有数据库连贯对象Connection,Connection在实例化PoolEntry前创立。PoolEntry创立的过程中会同时创立两个ScheduledFuture工作:endOfLife和keepalive。 endOfLife提交MaxLifetimeTask定时工作,在PoolEntry创立后的maxLifetime(参数指定)执行。MaxLifetimeTask会敞开以后连贯、同时依据须要创立新的连贯退出到连接池。 keepalive提交KeepaliveTask周期性工作,在PoolEntry创立后依照keepalive(参数设定)周期性执行,在以后连贯闲暇的状况下查看连贯是否可用(应用参数指定的ConnectionTestQuery进行测试),如果连贯不可用则敞开并从新创立连贯。 addConnectionExecutor增加数据库连贯的工作管理器。负责数据库连贯的创立以及退出到连接池中(sharedList和handoffQueue)。 留神addConnectionExecutor自身是一个线程池ThreadPoolExecutor,线程池容量为最大数据库连接数,HikariPool初始化的过程中会以多线程(corePoolSize=CPU内核数量)的形式疾速实现连贯创立和池化,之后失常状况下会以单线程(corePoolSize=1)的形式创立数据库连贯。 houseKeeperTask是一个周期性线程池ScheduledExecutorService,初始化的时候创立,定时(housekeepingPeriodMs)执行,清理掉(敞开)连接池中多余的(大于最小闲暇数)闲暇连贯,如果连接池中的连接数没有达到参数设置的数量(最大连接数、或者闲暇连贯没有达到最小闲暇连接数)则创立连贯。 HikariProxyConnectionHikariProxyConnection是数据库连贯Connection的扩大类,应用层通过getConnection办法获取到的数据库连贯其实不是不是数据库连贯Connection、而是这个扩大类HikariProxyConnection。 应用扩大类HikariProxyConnection、而不是原生的数据库连贯Connection的一个最直观的理由是,对于数据库连接池来说,连贯的敞开办法close不是要敞开连贯、而是要把连贯交还给连接池。应用扩大类(或者代理类)就能够很容易的重写其close办法实现目标,而如果间接应用原生Connection的话,就没方法管制了。 closeConnectionExecutor数据库连接池须要敞开的时候,通过closeConnectionExecutor线程池提交,敞开连贯后closeConnectionExecutor还负责调用fillPool(),依据须要填充连接池。 好了,HikariPool的根底构造理解完了,接下来要进入源码剖析了,次要包含: HikariPool的初始化获取数据库连贯 - getConnection办法敞开数据库连贯 - close办法HikariPool的初始化要开始剖析源码了。 HikariPool是实例化的时候在构造方法中实现初始化。代码尽管不是很多,然而内容很多,所以还是分段、一步一步剖析。 public HikariPool(final HikariConfig config) { super(config); this.connectionBag = new ConcurrentBag<>(this); this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK; this.houseKeepingExecutorService = initializeHouseKeepingExecutorService(); checkFailFast();首先调用super也就是PoolBase的构造方法,次要设置配置的相干参数,初始化DataSource(initializeDataSource,获取到数据库连贯的url、username、password等重要参数,创立DataSource)。 之后创立ConcurrentBag、实现ConcurrentBag的初始化(通过构造方法):创立handoffQueue、sharedList以及threadList。 接下来初始化houseKeepingExecutorService,也就是创立一个ScheduledThreadPoolExecutor,筹备接管houseKeep工作。 而后调用checkFailFast(),checkFailFast()的作用是在初始化连接池之前首先做一次疾速尝试:创立一个PoolEntry(通过createPoolEntry办法,稍后剖析源码),如果创立胜利则将其退出连接池后,返回,否则如果失败(数据库连贯创立失败)则一直尝试直到消耗完设置的初始化工夫initializationTimeout。 接着看初始化代码: if (config.getMetricsTrackerFactory() != null) { setMetricsTrackerFactory(config.getMetricsTrackerFactory()); } else { setMetricRegistry(config.getMetricRegistry()); } setHealthCheckRegistry(config.getHealthCheckRegistry()); handleMBeans(this, true); ThreadFactory threadFactory = config.getThreadFactory(); final int maxPoolSize = config.getMaximumPoolSize(); LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(maxPoolSize); this.addConnectionQueueReadOnlyView = unmodifiableCollection(addConnectionQueue); this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardOldestPolicy()); this.closeConnectionExecutor = createThreadPoolExecutor(maxPoolSize, poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy()); this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService); this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, housekeepingPeriodMs, MILLISECONDS);以上代码次要实现以下几件事件:MetricsTrackerFactory次要用来创立数据库连贯的统计分析工作。 ...