针对数据库链接池到DRDS链接探活的优化

简介: 针对数据库链接池到DRDS链接探活的优化

  1. 问题背景

========数据库

近期在给某专有云客户进⾏云产品应⽤性能优化分析时,发现了⼀个有趣的关于DRDS使⽤层⾯的问题,这⾥给⼤家分享⼀下。
使⽤过DRDS产品的同窗都知道在DRDS中,未分库分表的数据表会存储在“0号库”上,对于这些表操做的SQL会被分发到“0号库”上执⾏。因此⼀般状况下,0号库所在实例的压⼒会⽐其它实例的压⼒稍⼤⼀些。近期分析该客户的数据库性能时,发现客户使⽤的DRDS下0号库所在的RDS实例的压⼒明显⽐其它RDS实例⾼出许多。后端

图1:SQL语句平均每秒执行次数及事务数性能优化

  1. 缘由分析

========性能

经过查看0号库所在的RDS实例的执⾏SQL发现,有⼤量的 SELECT 'x' 的查询语句。检查应⽤侧代码后发现,这个查询语句是应⽤侧链接池配置的链接探活SQL,全部的链接池实现⼏乎都有这个功能,能够经过探活SQL检测链接当前是否可⽤。
那么问题来了:优化

  1. 为何只有0号库所在RDS上会有⼤量此类的语句?
    DRDS中不带表名的(⽐如 SELECT 'x')SQL和show命令都会被下发到0号库执⾏。
  2. 对于客户端来讲这种链接检测是否有⽤?

答案⼀定是有⽤的,由于若是因⽹络闪断或其它缘由致使的链接状态不可⽤,即便获取到了链接对象,也不能进⾏数据访问操做。因此这个检测是有必要的,但对于使⽤DRDS做为数据源的场景来讲,⽬前配置的检测⽅式是存在问题的。
对于传统的数据库使⽤⽅式,客户端是直接链接到底层数据库的,以下图。探活SQL是直接发到链接的数据库执⾏,这种场景下使⽤ SELECT 'x' 检测客户端到数据库的链接是没有问题的。ui

图2:客户端链接到数据库阿里云

⽽对于使⽤DRDS做为数据源的场景来讲,探活语句在发送到DRDS服务后,会被转发到0号库执⾏,这就意味着这个探活SQL实际上检测的是客户端-->DRDS-->0号库的链路是否正常。spa

图3:客户端经过DRDS链接到数据库线程

这⼀点能够从DRDS上看 SELECT 'x' 的执⾏计划获得证明,以下:对象

图4:执⾏结果1

实际上,这样的数据源链接检测是没有意义的。由于:

  • 第⼀,数据源后端实际上只检测了DRDS到0号库的链接状态,DRDS到其它分库的链接状态并未检测。但真正执⾏SQL时,DRDS是有可能将解析后的SQL下发到其它分库上执⾏的。
  • 第⼆,客户端探活SQL的做⽤主要是为了保证客户端链接池与数据源之间的链接是可⽤的。对于数据源背后的状况应该由数据源自己维护,即由DRDS自己到RDS的链接池保障链接可⽤性,⽽不该该经过客户端的探活功能来保证。
  1. 解决方法

========

明⽩以上内容后,咱们解决问题的⽅案就⽐较清楚了,实际上咱们只须要让客户端链接池检测客户端到DRDS的链接状态便可。那有没有这样的检测⽅法呢?
答案固然是有的,通过与DRDS研发同窗确认,将探活SQL修改成 SELECT 'x' FROM dual 便可。
修改后,再次在DRDS查看执⾏计划,以下:

图5:执⾏结果2

在应⽤侧修改链接池的探活SQL配置后,从0号库所在实例上看,已经看不到探活SQL的执⾏记录,⽽且从修改前和修改后0号库所在实例的压⼒来看,效果也⽐较明显,0号库的压⼒相⽐以前降低了⼤概80%左右。

图6:SQL语句平均每秒执行次数及事务数2

  1. 链接池参数配置

⾄此,0号库压⼒过⾼的问题解决了,下⾯咱们聊聊为何会有⼤量的探活语句出现。
探活机制其实是数据源链接池通⽤的⼀种检测机制,能够检测链接池内的链接对象是否真的可⽤。拿Druid链接池举例,探活SQL是经过数据源的 validationQuery 属性配置的。与之相关的配置属性还有:testOnBorrow  testWhileIdle testOnReturn  timeBetweenEvictionRunsMillis   minEvictableIdleTimeMillis。

官⽅解释以下:

  • testOnBorrow:申请链接时执⾏ validationQuery 配置的探活语句检测链接是否有效。
  • testWhileIdle:申请链接的时候检测,若是空闲时间⼤于timeBetweenEvictionRunsMillis ,执⾏ validationQuery 检测链接是否有效。
  • testOnReturn:归还链接时执⾏ validationQuery 检测链接是否有效。
  • timeBetweenEvictionRunsMillis:有两个含义 1)Destroy线程检测链接的间隔时间,若是链接空闲时间⼤于等于 minEvictableIdleTimeMillis 则关闭物理链接。
    2)testWhileIdle 的判断依据,详细看 testWhileIdle 属性的说明。
  • minEvictableIdleTimeMillis:链接保持空闲⽽不被驱逐的最⼩时间。

⽂章前⾯描述的出现⼤量探活SQL的状况是由于应⽤将链接池的testOnBorrow设置成了true,因此在每次应⽤获取链接时,都会执⾏ validationQuery 配置的探活语句检测链接是否有效。虽然经过前⾯的优化步骤,已经下降了0号库的压⼒,使探活语句不下发到0号库执⾏。

但探活语句仍会在DRDS实例上执⾏,DRDS实例的压⼒并未减轻。经过上⾯对Druid数据源属性配置的说明能够了解到,若是将 testOnBorrow 或 testOnReturn 打开,会对系统性能有⼀定的影响,由于每次都会在获取链接时多执⾏⼀次查询来检测链接是否可⽤。所以推荐使⽤以下的配置:

  • testWhileIdle=true【若是得到的链接为“空闲链接”,则会进⾏探活检测,若是检测失败,会将此链接从链接池移除,尝试从新从链接池获取链接】
  • timeBetweenEvictionRunsMillis=60000【Destroy线程每隔1分钟对链接池内部的空闲时间>= minEvictableIdleTimeMillis的链接进⾏探活检测,若是检测失败,会将链接从链接池移除】
  • minEvictableIdleTimeMillis=60000【若是链接闲置1分钟,则认为此链接为“空闲链接“】

这样设置完成后,只有在获取到“空闲链接”时,才会进⾏探活检测,⼤⼤下降了业务⾼峰时段的探活频率。同时,也可经过适当缩短minEvictableIdleTimeMillis 的值,兼顾因为⽹络闪断或其它缘由致使的链接不可⽤的状况,减小业务出错的几率,在系统性能和可⽤性之间找到⼀个平衡点。

做者:刘维
原文连接 本文为阿里云原创内容,未经容许不得转载

相关文章
相关标签/搜索