稳,从数据库连接池 testOnBorrow 看架构设计 | 京东云技术团队

news/2024/6/18 5:01:34 标签: 数据库, 京东云, java, 架构设计

本文从 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);
}

java_100">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);
    }
}

作者:京东物流 杨攀

来源:京东云开发者社区


http://www.niftyadmin.cn/n/455071.html

相关文章

N卡几千块的“智商税”,这下终于要没了

关于 CPU 显卡搭配&#xff0c;有句话大家肯定听过&#xff1a;「 i卡配iU、A卡配AU、N卡配 Fxxk U」 。 小白不要误会&#xff0c;这句话只是大家在喷N卡的定价问题。 拿刚刚过去的剁手节对比&#xff0c;AMD 这边旗舰显卡 RX 7900XT、XTX 价格直接跌到了 5/6000 出头。 而 …

Elasticsearch(十一)搜索---搜索匹配功能②--range查询和exists查询

一、前言 继上一节学习了ES的搜索的查询全部和term搜索后&#xff0c;此节将把搜索匹配功能剩余的2个学习完&#xff0c;分别是range搜索和exists搜索 二、range范围搜索 range查询用于范围查询&#xff0c;一般是对数值型和日期型数据的查询。使用range进行范围查询时&…

2023-05-20 青少年软件编程(C语言)等级考试试卷(三级)解析

2023-05-20 青少年软件编程(C语言)等级考试试卷(三级)解析T1、找和为K的两个元素 在一个长度为n(n < 1000)的整数序列中,判断是否存在某两个元素之和为k。 时间限制:1000 内存限制:65536 输入 第一行输入序列的长度n和k,用空格分开。 第二行输入序列中的n个整数,用…

浅聊一下system()函数与popen()函数

浅聊一下system()函数与popen()函数 文章目录 浅聊一下system()函数与popen()函数1.system()函数2.popen()函数3.区别总结&#xff1a; 1.system()函数 system()函数先fork一个子进程&#xff0c;在这个子进程中调用/bin/sh -c来执行command指定的命令。/bin/sh在系统中一般是…

CTFshow-pwn入门-前置基础pwn29-pwn31

什么是PIE 由于ASLR是一种操作系统层面的技术&#xff0c;而二进制程序本身是不支持随机化加载的&#xff0c;便出现了一些绕过方法&#xff0c;例如ret2plt、GOT劫持、地址爆破等。于是&#xff0c;人们于2003年引入了位置无关可执行文件&#xff08;Position-Independent Ex…

商品价格监控|如何做产品竞品分析?

电商平台已经成为了很多品牌企业不可或缺的销售渠道之一&#xff0c;那么&#xff0c;在大环境的驱使下&#xff0c;品牌应如何做好竞品监控与竞品分析以明确自身价格在市场中是否具有竞争力也成为品牌发展过程中的重要一环。 一、品牌通常会从哪几个角度来分析竞品&#xff1…

D. Pairs of Segments(最大不相交区间数量)

Problem - D - Codeforces 给定一个由n个线段组成的数组[[l1,r1],[l2,r2],…,[ln,rn]]&#xff0c;其中每个线段用左右端点表示。如果存在至少一个x满足l1≤x≤r1且l2≤x≤r2&#xff0c;则称线段[l1,r1]和[l2,r2]相交。 如果k为偶数&#xff0c;并且可以将该数组的元素分成k/…

Python 常用内置函数与匿名函数的应用

目录 一、前言二、常用内置函数2.1 max()2.2 enumerate()2.3 map()3.4 reduce()2.5 filter()2.6 sorted() 一、前言 我们知道&#xff0c;Python 函数总体可分为两类&#xff0c;一类是标准函数&#xff0c;一类是匿名函数。其中标准函数中又可细分为内置标准函数、自定义标准…