稳,从数据库连接池 testOnBorrow 看架构设计

数据库,连接池,testonborrow,架构设计 · 浏览次数 : 138

小编点评

**框架层:commons-pool** 1️⃣ `BorrowObject()` 函数: - 负责从数据库连接池中获取对象。 - 通过 `validateObject()` 方法检查对象是否可用。 - 如果对象不可用,则将其从池中移除并返回。 - 如果对象可用,则将其放到 `idleObjects` 中等待可用。 **应用层:commons-dbcpdbcp** 1️⃣ `validateObject()` 方法: - 负责对数据库连接对象进行验证。 - 检查连接是否有效,包括检查连接是否打开、是否与服务器连接可用等。 **基础层:mysql-connector-java** 1️⃣ `isValid()` 方法: - 在指定的时间内检查连接是否有效。 - 通过 `pingInternal()` 方法发送 ping 请求,检测连接是否可用。 - 如果连接关闭或不可用,则返回 `false`。 - 如果连接正常,则返回 `true`。 **总结** **架构分层设计** - 框架层提供抽象接口,让应用层不直接与数据库连接池交互。 - 应用层与基础层通过`validateObject()`方法进行交互。 - 基础层与数据库连接池通过`isValid()`方法进行交互。

正文

本文从 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 看架构设计相似的内容:

稳,从数据库连接池 testOnBorrow 看架构设计

本文从 Commons DBCP testOnBorrow 的作用机制着手,管中窥豹,从一点去分析数据库连接池获取的过程以及架构分层设计。以下内容会按照每层的作用,贯穿分析整个调用流程。

从工具到实践:如何在GitHub上保障开源项目安全?

1998年,Christine Peterson创造了 “开源软件”这个词。她解释道:“这是刻意为之,为了让其他人更容易理解这个领域”。同年,O’Reilly组织了首届“开源峰会”。 开源软件受到更多人青睐原因在于,用户对软件拥有更多的控制权因为他们可以检查代码。对于长期项目来说,开源软件被认为是稳

[转帖]台积电3nm成功量产,稳了吗?

https://docs.pingcode.com/info/13836.html?p=13836 2023-01-19 资讯 21 原标题:台积电3纳米成功量产:未来与三星仍将决战鳍式场效晶体管(FinFET) 来源:曲博科技教室 台积电在2022Q4高调宣布量产3纳米鳍式场效晶体管制程,是由原本

这场世界级的攻坚考验,华为云GaussDB稳过

摘要:实践证明,华为云GaussDB完全经受住了这场世界级的攻坚考验,也完全具备支撑大型一体机系统迁移上云的能力,并积累了丰富的经验。 本文分享自华为云社区《这场世界级的攻坚考验,华为云GaussDB稳过》,作者: GaussDB 数据库 。 数字化时代,业务“在线”是每个企业的常态。作为企业经营管

postman导入请求到jmeter进行简单压测,开发同学一学就会

背景 这个事情也是最近做的,因为线上nginx被我换成了openresty,然后接入层服务也做了较大改动,虽然我们这个app(内部办公类)并发不算高,但好歹还是压测一下,上线时心里也稳一点。 于是用jmeter简单压测下看看,这里记录一下。 这次也就找了几个接口来压:登录接口、登录后获取用户信息接口

【AIGC】只要10秒,AI生成IP海报,解放双手!!!

众所周知,各大厂目前都在AIGC的领域探索实践,也有非常多的外部设计师制作了大量的AIGC相关授课,很多同学因为不清楚具体能得到什么价值或者收获而停止了脚步。今天我来为大家分享一下经过实际探索且落地的Stable diffusion的IP海报生成流程,内容很干请上车坐稳