稳,从数据库连接池 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); } }
作者:京东物流 杨攀
来源:京东云开发者社区

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Spring源码核心剖析 | 京东云技术团队
前言 SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只是在AOP的基础上将能力集成到SpringIOC中,使其作为bean的一种,从而我们能够很方便的进行使用。 一、SpringAOP的使用方式 1.1 使用场景 当我们在日常业务开发中,例如有些功能模块是通用的(日志、权限等),或者我们需要在某些功能前后去做一些增强,例如在某些方法执行后发送一条mq消息等。 如果我们将这些通用模块代码与业务代码放在一块,那么每个业务代码都要写这些通用模块,维护成本与耦合情况都十分严重。 因此,我们可以将此模块抽象出来,就有了”切面“的概念。 1.2 常用方式 AOP的使用方式相对比较简单,首先我们需要完成业务代码 @Service public class AopDemo implements AopInterface{ public Student start(String name) { System.out.println("执行业务逻辑代码....."); ...
- 下一篇
【OneOS学习笔记】设备驱动模型中的I2C
简介 OneOS 在各类外设的基础上抽象出了设备驱动模型,本文将围绕驱动模型来分析I2C驱动的实现过程。 I2C驱动以STM32为例,主要分析驱动模型中各层之间的调用关系。 OneOS设备驱动模型见OneOS 官网(https://os.iot.10086.cn)文档驱动部分。 I2C驱动总概 I2C驱动框架如下图所示: 从图中可以看出用户可以直接访问设备统一接口和I2C设备框架层的API。 驱动为I2C设备提供的API见下表: API 层 os_device_find 管理层 os_i2c_transfer 框架层 os_i2c_client_write 框架层 os_i2c_client_read 框架层 os_i2c_client_write_byte 框架层 os_i2c_client_read_byte 框架层 os_i2c_master_send 框架层 os_i2c_master_recv 框架层 对于不同芯片,管理层提供设备操作接口,框架层提供I2C这类设备通用的接口,驱动层提供具体芯片的I2C设备驱动程序。 STM32系列芯片I2C驱动实现过程: 设备注册: OneO...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2配置默认Tomcat设置,开启更多高级功能