本文共 2727 字,大约阅读时间需要 9 分钟。
简介: 针对数据库连接池到DRDS连接探活的优化
近期在给某专有云客户进⾏云产品应⽤性能优化分析时,发现了⼀个有趣的关于DRDS使⽤层⾯的问题,这⾥给⼤家分享⼀下。
使⽤过DRDS产品的同学都知道在DRDS中,未分库分表的数据表会存储在“0号库”上,对于这些表操作的SQL会被分发到“0号库”上执⾏。所以⼀般情况下,0号库所在实例的压⼒会⽐其它实例的压⼒稍⼤⼀些。近期分析该客户的数据库性能时,发现客户使⽤的DRDS下0号库所在的RDS实例的压⼒明显⽐其它RDS实例⾼出许多。
通过查看0号库所在的RDS实例的执⾏SQL发现,有⼤量的 SELECT 'x' 的查询语句。检查应⽤侧代码后发现,这个查询语句是应⽤侧连接池配置的连接探活SQL,所有的连接池实现⼏乎都有这个功能,可以通过探活SQL检测连接当前是否可⽤。
那么问题来了:答案⼀定是有⽤的,因为如果因⽹络闪断或其它原因导致的连接状态不可⽤,即使获取到了连接对象,也不能进⾏数据访问操作。所以这个检测是有必要的,但对于使⽤DRDS作为数据源的场景来说,⽬前配置的检测⽅式是存在问题的。
对于传统的数据库使⽤⽅式,客户端是直接连接到底层数据库的,如下图。探活SQL是直接发到连接的数据库执⾏,这种场景下使⽤ SELECT 'x' 检测客户端到数据库的连接是没有问题的。⽽对于使⽤DRDS作为数据源的场景来说,探活语句在发送到DRDS服务后,会被转发到0号库执⾏,这就意味着这个探活SQL实际上检测的是客户端-->DRDS-->0号库的链路是否正常。
这⼀点可以从DRDS上看 SELECT 'x' 的执⾏计划得到证实,如下:
实际上,这样的数据源连接检测是没有意义的。因为:
明⽩以上内容后,我们解决问题的⽅案就⽐较清楚了,实际上我们只需要让客户端连接池检测客户端到DRDS的连接状态即可。那有没有这样的检测⽅法呢?
答案当然是有的,经过与DRDS研发同学确认,将探活SQL修改为 SELECT 'x' FROM dual 即可。修改后,再次在DRDS查看执⾏计划,如下:⾄此,0号库压⼒过⾼的问题解决了,下⾯我们聊聊为什么会有⼤量的探活语句出现。
探活机制实际上是数据源连接池通⽤的⼀种检测机制,可以检测连接池内的连接对象是否真的可⽤。拿Druid连接池举例,探活SQL是通过数据源的 validationQuery 属性配置的。与之相关的配置属性还有:testOnBorrow testWhileIdle testOnReturn timeBetweenEvictionRunsMillis minEvictableIdleTimeMillis。官⽅解释如下:
⽂章前⾯描述的出现⼤量探活SQL的情况是因为应⽤将连接池的testOnBorrow设置成了true,所以在每次应⽤获取连接时,都会执⾏ validationQuery 配置的探活语句检测连接是否有效。虽然通过前⾯的优化步骤,已经降低了0号库的压⼒,使探活语句不下发到0号库执⾏。
但探活语句仍会在DRDS实例上执⾏,DRDS实例的压⼒并未减轻。通过上⾯对Druid数据源属性配置的说明可以了解到,如果将 testOnBorrow 或 testOnReturn 打开,会对系统性能有⼀定的影响,因为每次都会在获取连接时多执⾏⼀次查询来检测连接是否可⽤。因此推荐使⽤如下的配置:
这样设置完成后,只有在获取到“空闲连接”时,才会进⾏探活检测,⼤⼤降低了业务⾼峰时段的探活频率。同时,也可通过适当缩短minEvictableIdleTimeMillis 的值,兼顾由于⽹络闪断或其它原因导致的连接不可⽤的情况,减少业务出错的概率,在系统性能和可⽤性之间找到⼀个平衡点。
作者:刘维
本文为阿里云原创内容,未经允许不得转载