博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
聊聊hikari连接池的isAllowPoolSuspension
阅读量:6581 次
发布时间:2019-06-24

本文共 9416 字,大约阅读时间需要 31 分钟。

本文主要研究一下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 pooljava.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
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 && !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

转载地址:http://ncino.baihongyu.com/

你可能感兴趣的文章
使用Redis构建文章投票网站(Java)
查看>>
见微知著 —— Redis 字符串内部结构源码分析
查看>>
Command './js-ant' failed to execute
查看>>
阿里云NFS NAS数据保护实战
查看>>
Spring cloud配置客户端
查看>>
产品研发项目管理软件哪个好?
查看>>
【阿里云北京峰会】一图看懂机器学习PAI如何帮助企业应用智能化升级
查看>>
ansible playbook使用总结
查看>>
Android API中文文档(111) —— MailTo
查看>>
Linux 中如何卸载已安装的软件
查看>>
thinkphp 3.2 增加每页显示条数
查看>>
oracle日常简单数据备份与还原
查看>>
我的友情链接
查看>>
黑马程序员__反射总结
查看>>
Scala学习笔记(5)-类和方法
查看>>
Quartz原理
查看>>
完全卸载oracle|oracle卸载|彻底卸载oracle
查看>>
垃圾收集基础
查看>>
Docker安装及基本命令
查看>>
控制namenode检查点发生的频率
查看>>