社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
WEB开发
linux   NoSql   Redis   MQ   Bootstrap   DATABASE   js   其他Web框架   Jquery   NGINX   peewee   web工具   Git   zookeeper   bottle   tornado   MongoDB   IE  
机器学习
机器学习算法  
Python88.com
公告   社区推广   反馈  
产品
短视频  
运营
印度
印度  
Python社区  »  DATABASE

用 MHA 做 MySQL 读写分离,频繁爆发线上生产事故后,泪奔分享 Druid 连接池参数优化实战

IT牧场 • 2 周前 • 25 次点击  

点击上方 IT牧场 ,选择 置顶或者星标

技术干货每日送达


前言

最近利用 MHA 做好 Mysql 读写分离后,时不时有用户反馈后台发布文章时,报程序“通用异常",经问题排查,里面涉及应用JDBC连接池参数及Mysql参数调整问题。

问题回顾

异常日志描述:

从异常信息反映来看,问题关键有两点

  1. 数据库连接池超时设置大于wait_timeout

  2. 日志提示,可以通过验证数据库连接或者设置:autoReconnect=true 来避免此异常

从以上两点可以推测

  • 第一、应用程序数据库连接池超时参数设置有问题

  • 第二、安装Mysql数据库时,对于Mysql的内在参数wait_timeout没有做实际场景的优化处理

问题定位

wait_timeout参数说明:

wait_timeout具体含义是服务器关闭非交互连接之前等待活动秒数。MySQL缺省配置情况下,wait_timeout的初始值是28800秒,也就是8小时。如果wait_timeout超时时间设置过大,在MySQL管理系统里会产生大量的SLEEP进程无法及时释放,会导致服务器系统性能下降;同时该参数设置过小,会导致Mysql处理某些事务未处理,连接不可用状态。

也就是说如果在wait_timeout设置期间内,数据库连接Connection一直处于空闲等待状态,mysql内部会自动关闭此连接,而应用程序无法感知到,依然认为连接池合法持有该连接。当应用端再次用该连接来进行数据库操作时,就产生上述异常错误。

应用端Druid数据库连接池参数设置代码如下:

发现连接池有个MaxWait参数设置过大:60000毫秒

druidDataSource.setMaxWait(60000)

然后在CSDN上,发现有个同行碰到同样的问题:

发现数据库等待超时时间(wait_timeout)是28800,也就是8小时,而应用程连接池参数max-wait: 30000,所以导致项目判定该链接可用,而mysql判定该连接不可用导致连接失败。

解决办法

根据上面的分析思路,我们排查了Mysql生产库,发现默认Mysql超时时间(wait_timeout)也是28800,但是应用层连接池MaxWait参数设置成60000,于是我把MaxWait参数设置成10000,小于Mysql超时时间(wait_timeout):28800 ,在测试环境等待8小时后,报错消失了。

其他扩展思路(来源网络):

  • 思路一:在jdbc-url后添加 &autoReconnect=true,使用后无效,查的该方案只适用于Mysql4之前的版本有效

  • 思路二:将mysql回收空闲连接的时间变长,mysql默认回收时间是8小时,可以在mysql 目录下的my.ini中增加下面配置,将时间改为1天。单位是秒,最大好像是24天。此配置会拖累数据库性能,弃用该方案。

  • 思路三:配置druid链接池,使用 validation-query test-on-borrow: true test-while-idle: true 三种属性,每次获取数据库连接时判断该连接是否可用。同时设置druidDataSource.setPhyTimeoutMillis 参数:连接最大存活时间,默认是-1(不限制物理连接时间),从创建连接开始计算,如果超过该时间,则会被清理。       

druidDataSource.setPhyTimeoutMillis(15000)

参考例子

目前项目中趋于稳定的数据库连接池参数优化实战,Druid 代码如下:

private void configDruidParams(DruidDataSource druidDataSource) {            druidDataSource.setMaxActive(20);            druidDataSource.setInitialSize(1);            // 配置获取连接等待超时的时间            druidDataSource.setMaxWait(10000);            druidDataSource.setMinIdle(1);            // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒            druidDataSource.setTimeBetweenEvictionRunsMillis(60000);            // 配置一个连接在池中最小生存的时间,单位是毫秒 超过这个时间每次会回收默认3个连接            druidDataSource.setMinEvictableIdleTimeMillis(30000);            // 线上配置的mysql断开闲置连接时间为1小时,数据源配置回收时间为3分钟,以最后一次活跃时间开始算            druidDataSource.setMaxEvictableIdleTimeMillis(180000);            // 连接最大存活时间,默认是-1(不限制物理连接时间),从创建连接开始计算,如果超过该时间,则会被清理            druidDataSource.setPhyTimeoutMillis(15000);            druidDataSource.setValidationQuery("select 1");            druidDataSource.setTestWhileIdle(true);            druidDataSource.setTestOnBorrow(false);            druidDataSource.setTestOnReturn(false);            druidDataSource.setPoolPreparedStatements(true);            druidDataSource.setMaxOpenPreparedStatements(20);            druidDataSource.setUseGlobalDataSourceStat(true);            druidDataSource.setKeepAlive(true);            druidDataSource.setRemoveAbandoned(true);            druidDataSource.setRemoveAbandonedTimeout(180);            try {                druidDataSource.setFilters("stat,slf4j");                List filterList = new ArrayList<>();                filterList.add(wallFilter());                druidDataSource.setProxyFilters(filterList);            } catch (SQLException e) {                e.printStackTrace();            }        }

干货分享

最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!

001:《Java并发与高并发解决方案》学习笔记;002:《深入JVM内核——原理、诊断与优化》学习笔记;003:《Java面试宝典》004:《Docker开源书》005:《Kubernetes开源书》006:《DDD速成(领域驱动设计速成)》007:全部008:加技术群讨论

近期热文

LinkedBlockingQueue vs ConcurrentLinkedQueue解读Java 8 中为并发而生的 ConcurrentHashMapRedis性能监控指标汇总最全的DevOps工具集合,再也不怕选型了!微服务架构下,解决数据库跨库查询的一些思路聊聊大厂面试官必问的 MySQL 锁机制

关注我

喜欢就点个"在看"呗^_^

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/74394
 
25 次点击  
分享到微博