稳,从数据库连接池 testOnBorrow 看架构设计
本文从 Commons DBCP testOnBorrow 的作用机制着手,管中窥豹,从一点去分析数据库连接池获取的过程以及架构分层设计。
以下内容会按照每层的作用,贯穿分析整个调用流程。
1️⃣框架层 commons-pool
The indication of whether objects will be validated before being borrowed from the pool.
If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another.
testOnBorrow 不是 dbcp 定义的,是commons-pool 定义的。commons-pool 详细的定义了资源池使用的一套规范和运行流程。
/**
* Borrow an object from the pool. get object from 资源池
* @see org.apache.commons.pool2.impl.GenericObjectPool#borrowObject(long)
*/
public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
PooledObject<T> p = null;
// if validation fails, the instance is destroyed and the next available instance is examined.
// This continues until either a valid instance is returned or there are no more idle instances available.
while (p == null) {
// If there is one or more idle instance available in the pool,
// then an idle instance will be selected based on the value of getLifo(), activated and returned.
p = idleObjects.pollFirst();
if (p != null) {
// 设置 testOnBorrow 就会进行可用性校验
if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
boolean validate = false;
Throwable validationThrowable = null;
try {
// 具体的校验实现由实现类完成。
// see org.apache.commons.dbcp2.PoolableConnectionFactory
validate = factory.validateObject(p);
} catch (final Throwable t) {
PoolUtils.checkRethrow(t);
validationThrowable = t;
}
if (!validate) {
try {
// 如果校验异常,会销毁该资源。
// obj is not valid and should be dropped from the pool
destroy(p);
destroyedByBorrowValidationCount.incrementAndGet();
} catch (final Exception e) {
// Ignore - validation failure is more important
}
p = null;
}
}
}
}
return p.getObject();
}
2️⃣应用层 commons-dbcp
dbcp 是特定于管理数据库连接的资源池。
PoolableConnectionFactory is a PooledObjectFactory
PoolableConnection is a PooledObject
/**
* @see PoolableConnectionFactory#validateObject(PooledObject)
*/
@Override
public boolean validateObject(final PooledObject<PoolableConnection> p) {
try {
/**
* 检测资源池对象的创建时间,是否超过生存时间
* 如果超过 maxConnLifetimeMillis, 不再委托数据库连接进行校验,直接废弃改资源
* @see PoolableConnectionFactory#setMaxConnLifetimeMillis(long)
*/
validateLifetime(p);
// 委托数据库连接进行自我校验
validateConnection(p.getObject());
return true;
} catch (final Exception e) {
return false;
}
}
/**
* 数据库连接层的校验。具体到是否已关闭、是否与 server 连接可用
* @see Connection#isValid(int)
*/
public void validateConnection(final PoolableConnection conn) throws SQLException {
if(conn.isClosed()) {
throw new SQLException("validateConnection: connection closed");
}
conn.validate(_validationQuery, _validationQueryTimeout);
}
3️⃣基础层 mysql-connector-java
Returns true if the connection has not been closed and is still valid.
这个是 java.sql.Connection 定义的规范。具体实现根据对应数据库的driver 来完成。使用某种机制用来探测连接是否可用。
/**
* 调用 com.mysql.jdbc.MysqlIO, 发送ping 请求,检测是否可用
* 对比 H2 数据库,是通过获取当前事务级别来检测连接是否可以。但是忽略了 timeout 配置,毕竟是 demo 数据库
*/
public synchronized boolean isValid(int timeout) throws SQLException {
if (this.isClosed()) {
return false;
} else {
try {
this.pingInternal(false, timeout * 1000);
return true;
} catch (Throwable var5) {
return false;
}
}
}
参考:MySQL 的连接时长控制--interactive_timeout和wait_timeout_翔云123456的博客-CSDN博客
总结
- commons-pool 定义资源的完整声明周期接口,包括:makeObject、activateObject、validateObject、passivateObject、destoryObject。资源池管理对象,通过实现这些接口即可实现资源控制。参考:org.apache.commons.pool2.PooledObjectFactory
- 在校验过程中,牵涉到很多时间,包括资源池对象的创建时间、生存时间、数据库连接的超时时间、Mysql 连接空闲超时时间等。不同层为了服务可靠性,提供不同的时间配置。校验也是层层递进,最终委托到最底层来判断。
- 校验过程中,对于连接也会由是否已关闭的校验(isClosed() )。包括PoolableConnection#isClosed, Connection#isClosed, Socket#isClosed。 同样也是层层保障,确保整个架构的可靠。
- 定义一套完整严谨的规范和标准,比实现一个具体的功能或者特性要求更高 。commons-pool 和 jdbc 定义了规范,commons-dbcp 和 mysql-connector-java 完成了具体的实现。有了规范和接口,组件和框架的对接和兼容才变为可能。
more 理解高可用
在阅读 MySQL Driver 源码过程中,有个点要特别记录下。以 MySQL Driver 创建连接为例,用重试连接实现可用性,这就是高可用。
高可用不是一个口号,也不是复杂的概念和公式。能够实实在在体系化的解决一类问题就是架构的目的。结合上述的架构分层,如果解决问题的方案通用性好,并且实现很优雅,就是好的架构。
// autoReconnect
public void createNewIO(boolean isForReconnect) throws SQLException {
synchronized (getConnectionMutex()) {
// jdbc.url autoReconnect 指定为 true,识别为 HighAvailability。emmm.....
if (!getHighAvailability()) {
connectOneTryOnly(isForReconnect, mergedProps);
return;
}
// maxReconnects 默认为 3,重试失败的提示就是: Attempted reconnect 3 times. Giving up.
connectWithRetries(isForReconnect, mergedProps);
}
}
作者:京东物流 杨攀
来源:京东云开发者社区
稳,从数据库连接池 testOnBorrow 看架构设计的更多相关文章
- 主流Java数据库连接池分析(C3P0,DBCP,TomcatPool,BoneCP,Druid)
主流数据库连接池 常用的主流开源数据库连接池有C3P0.DBCP.Tomcat Jdbc Pool.BoneCP.Druid等 C3p0: 开源的JDBC连接池,实现了数据源和JNDI绑定,支持JDB ...
- 微信小程序全面实战,架构设计 && 躲坑攻略(小程序入门捷径教程)
最近集中开发了两款微信小程序,分别是好奇心日历(每天一条辞典+一个小投票)和好奇心日报(轻量版),直接上图: Paste_Image.png 本文将结合具体的实战经验,主要介绍微信小程序的基础知识.开 ...
- 打开黑盒:从 MySQL架构设计出发,看它是如何执行一条 SQL语句的
1.把MySQL当个黑盒子一样执行SQL语句 我们的系统采用数据库连接池的方式去并发访问数据库,然后数据库自己其实也会维护一个连接池,其中管理了各种系统跟这台数据库服务器建立的所有连接 当我们的系统只 ...
- php 设计数据库连接池
摘要 之前总是以脚本面向过程的方式写PHP代码,所以很大程度上来说,既不规范,也不安全,更不容易维护.为了代码的重用,准备写一套自己的工具库,这样的话,以后写项目的时候就可以很轻松的进行使用啦. 今天 ...
- 一文看懂 Netty 架构设计
本文重点分析 Netty 的逻辑架构及关键的架构质量属性,希望有助于大家从 Netty 的架构设计中汲取营养,设计出高性能.高可靠性和可扩展的程序. Netty 的三层架构设计 Netty 采用了典型 ...
- 从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计
使用微信小程序开发已经很长时间了,对小程序开发已经相当熟练了:但是作为一名对技术有追求的前端开发,仅仅熟练掌握小程序的开发感觉还是不够的,我们应该更进一步的去理解其背后实现的原理以及对应的考量,这可能 ...
- 数据库连接池设计和实现(Java版本)
1 前言 数据库连接池是目前系统开发必须面对和考虑的问题,原理并不复杂,主要是减少重复连接数据库的代价:在系统中创建预期数量的数据库连接,并将这些连接以一个集合或类似生活中的池一样管理起来,用到的时候 ...
- 从腾讯QQgame高性能服务器集群架构看“分而治之”与“自治”等分布式架构设计原则
转载:http://space.itpub.net/17007506/viewspace-616852 腾讯QQGame游戏同时在线的玩家数量极其庞大,为了方便组织玩家组队游戏,腾讯设置了大量游戏室( ...
- 从一般分布式设计看HDFS设计思想与架构
要想深入学习HDFS就要先了解其设计思想和架构,这样才能继续深入使用HDFS或者深入研究源代码.懂得了"所以然"才能在实际使用中灵活运用.快速解决遇到的问题.下面这篇博文我们就先 ...
- python数据库连接池设计
一.背景: 传统访问资源,一般分为一下几个步骤: 1.实例数据驱动对象与链接资源.2.实例操作资源游标.3.获取资源.4.关闭链接资源. 根据以上步骤,我们可以很简单使用这个原始方法来访问资源为我们业 ...
随机推荐
- IBM Cloud Computing Practitioners 2019 (IBM云计算从业者2019)Exam答案
Cloud Computing Practitioners 2019 IBM Cloud Computing Practitioners 2019 (IBM云计算从业者2019)Exam答案,加粗的为 ...
- Java设计模式 —— 桥接模式
10 桥接模式 10.1 桥接模式概述 Bridge Pattern: 将抽象部分与它的实现部分解耦,使得两者都能够独立变化. 桥接模式是一种很实用的结构型模式,如果系统中某个类存在两个独立变化的维度 ...
- Active Record 活动记录
ActiveRecord活动记录类 一.声明AR类(模型层) namespaceapp\models; useyii\db\ActiveRecord; classCustomer extends Ac ...
- 【JavaSE】网络编程
1. 网络编程概述 网络编程的目的:直接或者间接地通过网络协议与其他计算机实现数据交换,进行通讯. 网络编程两个主要的问题: ①如何精准地定位网络上的一台或多台主机,并定位主机上的特定应用 ②找到主机 ...
- FreeSWITCH添加iLBC编码及转码
操作系统 :CentOS 7.6_x64 FreeSWITCH版本 :1.10.9 一.安装ilbc库 从第三方库里下载指定版本: git clone https://freeswitch.org/s ...
- BAT 基础语法
命令 //功能 echo //标准输出命令 在CMD窗口中 显示echo 后的内容 @ //关闭当前行的 回显 回显:源代码在 CMD 窗口中再次显示 pasue // 暂停程序 的执行 ...
- AI降临,前端启用面壁计划
作者:京东零售 郑炳懿 开篇: "在我们有生之年,你觉得会看到AI兵临城下的那一天吗?就像电影黑客帝国里面演的一样",Barry从红色的烟盒里取出一根烟发问道. "不可能 ...
- day05-优惠券秒杀01
功能03-优惠券秒杀01 4.功能03-优惠券秒杀 4.1全局唯一ID 4.1.1全局ID生成器 每个店铺都可以发布优惠券: 当用户抢购时,就会生成订单,并保存到tb_voucher_order这张表 ...
- 关于页面重定向https安全漏洞和服务器SSH加密算法漏洞
1.HTTP 严格传输安全 nginx配置 add_header Strict-Transport-Security "max-age=63072000; includeSubdomains ...
- 笔记十:线程间的通信(pthread_exit()和pthread_join())
linux高级编程之线程间的通信(pthread_exit()和pthread_join()) 1.线程终止 如果进程中的任一线程调用了exit._Exit或者_exit,那么整个进程就会终 ...