Druid线程池中的连接什么时候会关闭?
Druid线程池帮我们实现了应用程序和数据之间的长连接管理,一个线上变更引起了我的疑问,如果我们数据库切换到备用集群,怎么变更?
数据库连接,一般都是域名连接,现在将域名和IP的绑定关系变了,更新ngix,通过域名能找到新的Ip,然后期望通过新IP连接数据库。此时应用程序中的数据库连接池中还保持老IP的连接,这样会造成新的连接走到新数据库,老的连接走到老数据库。
为了解决这个问题,我们当时的操作是手动将老的数据库kill了,使连接池中的老的连接失效重连到新的IP,这样操作,目标是实现了,但是风险很大,如果kill了老数据库后新的数据库不能用咋办?业务都停了,连接池中的老的连接失效重连,这个过渡时间能持续好久,我们业务是否能接受,这都是风险!
欢迎小伙伴们提供思路!!!
下面是我翻看Druid的清除连接的源码整理出来的几个点,注意看源码中的几处注释
1.DruidDataSource.shrink(boolean checkTime)方法中异步线程 DestroyTask 对无效的Collection做清除
public void shrink(boolean checkTime) {final List<DruidConnectionHolder> evictList = new ArrayList<DruidConnectionHolder>();try {lock.lockInterruptibly();} catch (InterruptedException e) {return;}try {final int checkCount = poolingCount - minIdle;final long currentTimeMillis = System.currentTimeMillis();for (int i = 0; i < poolingCount; ++i) {DruidConnectionHolder connection = connections[i];if (checkTime) {## 连接不管是否空闲,存活phyTimeoutMillis后强制回收,用于Destroy线程清理连接的时候的检测时间,如果不配置默认等于-1,也就是此处不检查if (phyTimeoutMillis > 0) {long phyConnectTimeMillis = currentTimeMillis - connection.getTimeMillis();if (phyConnectTimeMillis > phyTimeoutMillis) {evictList.add(connection);continue;}}long idleMillis = currentTimeMillis - connection.getLastActiveTimeMillis();if (idleMillis < minEvictableIdleTimeMillis) {break;}if (checkTime && i < checkCount) {evictList.add(connection);} else if (idleMillis > maxEvictableIdleTimeMillis) {## 连接的最大存活时间,如果连接的最大时间大于 maxEvictableIdleTimeMillis ,则无视最小连接数强制回收evictList.add(connection);}} else {if (i < checkCount) {evictList.add(connection);} else {break;}}}int removeCount = evictList.size();if (removeCount > 0) {System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);poolingCount -= removeCount;}} finally {lock.unlock();}for (DruidConnectionHolder item : evictList) {Connection connection = item.getConnection();JdbcUtils.close(connection);destroyCount.incrementAndGet();}
}
2.DruidDataSource.public int removeAbandoned() 方法中异步线程 DestroyTask 对无效的Collection做清除
public int removeAbandoned() {int removeCount = 0;long currrentNanos = System.nanoTime();List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>();synchronized (activeConnections) {Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator();for (; iter.hasNext();) {DruidPooledConnection pooledConnection = iter.next();if (pooledConnection.isRunning()) {continue;}long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);## 通过datasource.getConnontion() 取得的连接必须在removeAbandonedTimeout这么多秒内调用close()要不我就弄死你.(就是conn不能超过指定的租期);removeAbandonedTimeoutMillis=默认300 * 1000 5分钟if (timeMillis >= removeAbandonedTimeoutMillis) {iter.remove();pooledConnection.setTraceEnable(false);abandonedList.add(pooledConnection);}}}if (abandonedList.size() > 0) {for (DruidPooledConnection pooledConnection : abandonedList) {synchronized (pooledConnection) {if (pooledConnection.isDisable()) {continue;}}JdbcUtils.close(pooledConnection);pooledConnection.abandond();removeAbandonedCount++;removeCount++;.....................}}return removeCount;}
3.DruidDataSource. public DruidPooledConnection getConnecltionDirect(long maxWaitMillis) :检查空闲连接是否有效,如果连接无效关闭连接,再新建一个可用连接
if (isTestWhileIdle()) {final long currentTimeMillis = System.currentTimeMillis();final long lastActiveTimeMillis = poolableConnection.getConnectionHolder().getLastActiveTimeMillis();final long idleMillis = currentTimeMillis - lastActiveTimeMillis;long timeBetweenEvictionRunsMillis = this.getTimeBetweenEvictionRunsMillis();if (timeBetweenEvictionRunsMillis <= 0) {timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;}## 获取连接的时候,检查连接的空闲时间,如果空间时间大于配置的时间,检测连接是否还有效,如果连接无效关闭连接,无效连接关闭了后再新建一个可用连接if (idleMillis >= timeBetweenEvictionRunsMillis) {boolean validate = testConnectionInternal(poolableConnection.getConnection());if (!validate) {if (LOG.isDebugEnabled()) {LOG.debug("skip not validate connection.");}discardConnection(realConnection);continue;}}}
还有其它地方会关闭连接,如果空闲连接数量大于配置的数量,这个时候需要关闭多余的连接。未完待续。。。。。。。。。。
当时我们的操作方案:
回滚方案 |
||||
序号 |
步骤 |
操作人 |
时间 |
|
7 |
通过全局锁阻塞新集群数据写入,加锁成功后再进入下一步。 |
DBA |
10秒 |
|
8 |
记录新集群主库此时binlog的pos点。 |
DBA |
3秒 |
|
9 |
新集群主库日志刷盘。 |
DBA |
3秒 |
|
10 |
解析生成新集群已执行过的dml/ddl语句(解析范围从步骤4的pos起始点开始到步骤9的pos结束点结束) |
DBA |
以实际执行时间为准 |
|
11 |
将sql文件传回原集群主库并执行 |
DBA |
以实际执行时间为准 |
|
12 |
域名进行回切。 |
DBA |
以实际执行时间为准 |
|
13 |
迁移完成后验证: |
DBA |
10分钟 |
|
注: |
其中7到11步骤是为了保证新老集群数据一致性,如果对RTO比较在意,可以容忍小部分数据丢失,建议回退直接从12步开始执行 |
Druid线程池中的连接什么时候会关闭?相关推荐
- java 等待线程池结束_等待线程池中任务执行完毕做优雅关闭
背景 在Java开发中,如果涉及多线程,会经常使用到线程池,本期不额外讲述线程池本身相关的东西.考虑一种场景,如果我们提交给线程池的任务都相对比较耗时,而在任务启动运行后,如果后续有需求的变更,要重新 ...
- druid 线程池监控
druid 线程池监控 grafana 引入dashboard dashboard编号: 11157 配置 需要单独将 druid 线程池信息收集在 prometheus 中 引入依赖 <dep ...
- 但是尚未从池中获取连接_[转载]超时时间已到,但是尚未从池中获取连接!
估计是链接的人过多,而链接没有释放,你可以考虑再链接字符串中把链接池的数量设大些! 如:"server=localhost;user id=sa;password=;pooling=true ...
- C#如何判断线程池中所有的线程是否已经完成(转)
其 实很简单用ThreadPool.RegisterWaitForSingleObject方法注册一个定时检查线程池的方法,在检查线程的方法内调用 ThreadPool.GetAvailableThr ...
- [.Net线程处理系列]专题二:线程池中的工作者线程
目录: 一.上节补充 二.CLR线程池基础 三.通过线程池的工作者线程实现异步 四.使用委托实现异步 五.任务 六.小结 一.上节补充 对于Thread类还有几个常用方法需要说明的. 1.1 Susp ...
- 一个线程池中的线程异常了,那么线程池会怎么处理这个线程?
一个线程池中的线程异常了,那么线程池会怎么处理这个线程? 参考文章: (1)一个线程池中的线程异常了,那么线程池会怎么处理这个线程? (2)https://www.cnblogs.com/fangua ...
- EF 4.1中内部经常提交的 exec sp_reset_connection 的用途原来是为了重用池中的连接...
sp_reset_connection 的作用 当您使用连接池连接到 SQL Server 时,SQL Server 将调用 sp_reset_connection 存储过程来重用之前池中的连接. ( ...
- 【Android 异步操作】线程池 ( Worker 简介 | 线程池中的工作流程 runWorker | 从线程池任务队列中获取任务 getTask )
文章目录 一.线程池中的 Worker ( 工作者 ) 二.线程池中的工作流程 runWorker 三.线程池任务队列中获取任务 getTask 在博客 [Android 异步操作]线程池 ( 线程池 ...
- 线程池中阻塞队列的作用?为什么是先添加列队而不是先创建最大线程?线程池中线程复用原理
1.一般的队列只能保证作为一个有限长度的缓冲区,如果超出了缓冲长度,就无法保留当前的任务了,阻塞队列通过阻塞可以保留住当前想要继续入队的任务.阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使 ...
最新文章
- 单片机彩灯移动实验_用S7-1200 PLC实现循环彩灯的控制,含源程序
- CVPR 2021 | 超越卷积,自注意力模型HaloNet准确率实现SOTA
- 记录,一些jar包的作用
- 从0到1建立一张评分卡之模型建立
- RvaToFileOffset 内存偏移转成文件偏移(滴水课后作业)
- springboot优雅停机
- 在大促中什么影响了数据库性能
- android compile使用方法,自己创建一个android studio在线依赖compile
- linux扩容根目录空间_Linux系统扩容根目录磁盘空间的操作方法
- 区块链企业级解决方案 ( Hyperledger )
- 用glew,glfw,FreeImage实现opengl学习笔记6坐标变换
- vue拦截器刷新登陆页面_vue页面跳转拦截器
- 高等数学公式【上册+下册】
- 好用的倒计时APP 可以同时开多个倒数计时器的便签
- 摄像头云台的设计,组装与使用方法
- (转)一位计算机牛人的心得,谈到计算机和数学,很实用
- 我的汉字输入法编码方案
- 容联携手火星时代教育 促进线上线下一体化
- 从程序中学习UKF-SLAM(二)
- STM32F105配置为USB设备时