聊聊hikari连接池的isAllowPoolSuspension

发布时间:2019-11-19 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了聊聊hikari连接池的isAllowPoolSuspension脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

本文主要研究一下hikari连接池的isAllowPoolSusPEnsion属性

实例代码

    @test     public void testPoolSuspend() throws SQLException {         Connection conn = dataSource.getConnection();         System.out.PRintln("begin to suspend pool");         ((HikariDataSource)dataSource).suspendPool();         Connection conn2 = dataSource.getConnection();         System.out.println("finish");     }

suspend

begin to suspend pool  java.lang.IllegalstateException: HikarIPOol-1 - is not suspendable      at com.zaxxer.hikari.pool.HikariPool.suspendPool(HikariPool.java:372)     at com.zaxxer.hikari.HikariDataSource.suspendPool(HikariDataSource.java:326)     at com.example.demo.HikariDemoApplicationTests.testPoolSuspend(HikariDemoApplicationTests.java:37)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     at java.lang.reflect.Method.invoke(Method.java:497)     at org.junIT.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)     at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)     at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)     at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)     at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)     at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)     at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)     at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)     at org.junit.runners.ParentRunner.run(ParentRunner.java:363)     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)     at org.junit.runner.JUnitCore.run(JUnitCore.java:137)     at com.Intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithargs(JUnit4IdeaTestRunner.java:69)     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     at java.lang.reflect.Method.invoke(Method.java:497)     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
当没有设置的allow-pool-suspension=true时候,抛出java.lang.IllegalStateException: HikariPool-1 - is not suspendable

allow-pool-suspension=true

HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java

   /**     * Construct a HikariPool with the specified configuration.     *     * @param config a HikariConfig instance     */    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();        if (config.getMetricsTrackerFactory() != null) {          setMetricsTrackerFactory(config.getMetricsTrackerFactory());       }       else {          setMetricRegistry(config.getMetricRegistry());       }        setHealthCheckRegistry(config.getHealthCheckRegistry());        registerMBeans(this);        ThreadFactory threadFactory = config.getThreadFactory();        LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(config.getMaximumPoolSize());       this.addConnectionQueue = unmodifiableCollection(addConnectionQueue);       this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardPolicy());       this.closeConnectionExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());        this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeaKDEtectionThreshold(), houseKeepingExecutorService);        this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, HOUSEKEEPING_PERIOD_MS, MILLISECONDS);    }
如果isAllowPoolSuspension为ture,则suspendResumeLock是一个真实的SuspendResumeLock,否则是SuspendResumeLock.FAUX_LOCK

SuspendResumeLock

/**  * This class implements a lock that can be used to suspend and resume the pool.  It  * also provides a faux implementation that is used when the feature is disabled that  * hopefully gets fully "optimized away" by the JIT.  *  * @author brett Wooldridge  */ public class SuspendResumeLock {    public static final SuspendResumeLock FAUX_LOCK = new SuspendResumeLock(false) {       @override       public void acquire() {}        @Override       public void release() {}              @Override       public void suspend() {}        @Override       public void resume() {}    };     private static final int MAX_PERMITS = 10000;    private final semaphore acquisitionSEMaphore;     /**     * Default constructor     */    public SuspendResumeLock()    {       this(true);    }     private SuspendResumeLock(final boolean createSemaphore)    {       acquisitionSemaphore = (createSemaphore ? new Semaphore(MAX_PERMITS, true) : null);    }     public void acquire()    {       acquisitionSemaphore.acquireUninterruptibly();    }     public void release()    {       acquisitionSemaphore.release();    }     public void suspend()    {       acquisitionSemaphore.acquireUninterruptibly(MAX_PERMITS);    }     public void resume()    {       acquisitionSemaphore.release(MAX_PERMITS);    } }
FAUX_LOCK是一个空方法,false表示不创建信号量

suspend方法一次性消耗了MAX_PERMITS信号量,这个方法被调用之后,之后getConnection方法都获取不到连接,永远阻塞在suspendResumeLock.acquire();

resume方法一次性释放MAX_PERMITS信号量

HikariPool.getConnection

HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java

   /**     * Get a connection From the pool, or timeout after connectionTimeout milliseconds.     *     * @return a java.sql.Connection instance     * @throws SQLException thrown if a timeout occurs trying to oBTain a connection     */    public Connection getConnection() throws SQLException    {       return getConnection(connectionTimeout);    }     /**     * Get a connection from the pool, or timeout after the specified number of milliseconds.     *     * @param hardTimeout the maximum time to wait for a connection from the pool     * @return a java.sql.Connection instance     * @throws SQLException thrown if a timeout occurs trying to obtain a connection     */    public Connection getConnection(final long hardTimeout) throws SQLException    {       suspendResumeLock.acquire();       final long startTime = currentTime();        try {          long timeout = hardTimeout;          do {             PoolEntry poolEntry = connectionBag.borrow(timeout, MILLISECONDS);             if (poolEntry == null) {                break; // We timed out... break and throw exception             }              final long now = currentTime();             if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS &amp;& !isConnectionAlive(poolEntry.connection))) {                closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE);                timeout = hardTimeout - elapsedMillis(startTime);             }             else {                metricsTracker.recordBorrowStats(poolEntry, startTime);                return poolEntry.createProxyConnection(leakTaskFactory.schedule(poolEntry), now);             }          } while (timeout > 0L);           metricsTracker.recordBorrowTimeoutStats(startTime);          throw createTimeoutException(startTime);       }       catch (InterruptedException e) {          Thread.currentThread().interrupt();          throw new SQLException(poolName + " - Interrupted during connection acquisition", e);       }       finally {          suspendResumeLock.release();       }    }
可以看到getConnection是先获取信号量,最后不管获取成功还是超时,finally里头去释放这个信号量
这里的hardTimeout就是从连接池借用connection的超时时间

小结

isAllowPoolSuspension用来标记释放允许暂停连接池,一旦被暂停,所有的getConnection方法都会被阻塞。可能的用处就是用来实现chaosmonkey,模拟数据库连接故障。作者在github上的解释是可以用来做些配置修改:暂停连接池,修改连接池配置或dns配置,soft-evit既有连接,然后恢复连接池。

doc

脚本宝典总结

以上是脚本宝典为你收集整理的聊聊hikari连接池的isAllowPoolSuspension全部内容,希望文章能够帮你解决聊聊hikari连接池的isAllowPoolSuspension所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。