《记 RDS MySQL 的一个大坑》 中,我提到遇到 User juxxxxxxxxxx already has more than 'max_user_connections' active connections…… 这样的错误,最终通过在循环中使用 Thread.Sleep,降低 CRUD 操作的频率,让连接数下降至不到原来的一半,从而解决了这个棘手的问题,有兴趣的朋友可以点击链接回顾一下

今天又看了一下添加 Thread.Sleep 后,程序运行时的 IOPS 和 连接数:

运行结果:连接数:300,运行时间:68 分钟,IOPS:7

昨天在博客园中发出上篇文章后,热心的朋友(@沈赟@不知道风往哪儿吹)对此问题提出了宝贵的意见和想法,激发了我对此问题继续深究的决定。

下午经过几个小时的分析和测试,终于找到了该问题的真正原因和更好的解决方法,在此做个补充。

真正的原因在于:使用 MySQL 官方提供的 MySql.Data 作为驱动程序连接 MySQL 数据库的时候,默认使用了连接池,才引发了这个问题。错怪了阿里云(上篇中提到怀疑阿里云改了 MySQL 底层做了限制),在此对自己的不严谨表示诚恳的道歉,凡事要自己多思考多研究多求证,不可轻易怀疑权威的力量,切记切记!!!

下面聊一聊该问题出现的真正原因和更优的解决方法。

MySQL 连接池

根据官方介绍:MySQL Connector/NET 中(即 MySql.Data 中)连接池的工作的机制是,当客户端配置 MySqlConnection 时,连接池通过保持一组与服务器的本地连接使其处于活动状态,随后,如果打开一个新的 MySqlConnection 对象,它将从连接池中创建连接,而不是重新创建一个新的本地连接。这样便可以重用数据库连接,避免了频繁创建、释放连接引起的大量性能开销,这有助于缩短响应时间、统一管理、提高运行性能等等。

在软件开发中,大多数情况下,数据库连接都有重用的可能,即便永不重用,连接池也有自己的回收机制在适当的时候释放资源,这有点像带有过期时间的缓存数据,也像 .NET 的 GC 回收机制。正因为在大多数情况下,它可以提高运行的性能,也有完善且可配置的回收机制。所以在没有提供任何连接池选项的情况下,MySQL Connector/NET 默认启用连接池,也就是说,创建 MySqlConnection 时使用下面的连接字符串:

server=xxx;port=3306;userid=myuserid;password=pwd123;database=db125;charset=utf8;

等同于使用:

server=xxx;port=3306;userid=myuserid;password=pwd123;database=db125;charset=utf8;Pooling=true;

而我原来的代码中恰好用的就是前者,也就是说默认启用了连接池。

为什么使用连接池反而出问题了

上面说到连接池有那么多的好处,为什么我用了连接池反倒出问题了呢?我们来看一下

连接对池资源的利用情况:

官方文档:

Connector/NET runs a background job every three minutes and removes connections from pool that have been idle (unused) for more than three minutes. The pool cleanup frees resources on both client and server side. This is because on the client side every connection uses a socket, and on the server side every connection uses a socket and a thread.

译文:

Connector/NET 每三分钟运行一次后台作业,从连接池中删除闲置(未使用)超过三分钟的连接。连接池清理会释放客户端和服务器端的资源。这是因为在客户端,每个连接使用一个套接字,而在服务器端,每个连接都使用一个套接字和一个线程。

上一篇中有介绍过我的程序的基本情况,这里有必要再补充一下关键的使用场景:

我们的 MySql 服务实例有很多台,每台实例上有很多个数据库,只有其中一台 MySql 服务实例出现了超出 max_user_connections 的异常,这台实例最大的连接数限制在 600,但是这台实例上的数据库就有 700 多个。

聪明的朋友看到这里,估计已经明白为什么使用了连接池会出现问题了。为什么呢?就因为上面提到的连接池每三分钟运行一次清理操作呗。循环语句执行的速度是很快的,有的小库瞬间就执行完了,但是在连接池中却保持了一个连接,还没有到每隔三分钟的资源回收时间(这也是我在上篇中添加了 Thread.Sleep 后连接数减少的原因)。当这台实例的 600 个连接被全部占满时,再连接同一实例上另一个连接池中没有缓存的数据库时,就报了超出 max_user_connections 的异常。

解决方法

怎么解决呢?最简单的解决方法就是,判断请求的是这台 MySql 服务实例时,不使用连接池,这样就会在调用 MySqlConnection 的 Close 方法时,立即释放客户端和服务端所占用的资源。因此,在数据库连接字符串中加上 Pooling=false,改成下面这样:

server=xxx;port=3306;userid=myuserid;password=pwd123;database=db125;charset=utf8;Pooling=false;

然后发布到服务器上进行测试,查看一下程序运行时的 IOPS 和 连接数:

惊不惊喜,意不意外,嚯嚯嚯~~~

连接数从异常到 300 到 5(RDS MySQL 的一个大坑•后记)的更多相关文章

  1. 记阿里云 RDS MySQL 的一个大坑

    花了一个下午的时间,终于把一个阿里云 RDS MySQL 的一个大坑填上了,解决方法令人匪夷所思!绝对会让各位看官感到大吃一惊,阿里云 RDS MySQL 居然有这样 xx 的大坑! 问题 最近应业务 ...

  2. RDS MySQL 连接数满情况的处理

    RDS MySQL 连接数满情况的处理 RDS MySQL 连接数满有2种情况 1. 空闲连接过多 原因: 应用使用长连接模式 - 对于长连接模式(比如Java应用),应用侧应该配置连接池.连接池的初 ...

  3. 实测:云RDS MySQL性能是自建的1.6倍

    1. 摘要 基于之前写的「云厂商 RDS MySQL 怎么选」的文章,为了进一步了解各云厂商在RDS MySQL数据库性能上的差异,本文将对自建MySQL.阿里云.腾讯云.华为云和AWS 的 RDS ...

  4. RDS MySQL InnoDB 锁等待和锁等待超时的处理

    https://help.aliyun.com/knowledge_detail/41705.html 1. Innodb 引擎表行锁等待和等待超时发生的场景 2.Innodb 引擎行锁等待情况的处理 ...

  5. RDS MySQL 空间问题的原因和解决

    来源:https://help.aliyun.com/knowledge_detail/41739.html RDS MySQL 空间问题的原因和解决 更新时间:2016-07-22 17:20:14 ...

  6. Configure Amazon RDS mysql to store Chinese Characters

    Configure Amazon RDS mysql to store Chinese Characters https://dev.mysql.com/doc/refman/5.7/en/chars ...

  7. RDS MySQL 全文检索相关问题的处理

    RDS MySQL 全文检索相关问题 1. RDS MySQL 对全文检索的支持 2. RDS MySQL 全文检索相关参数 3. RDS MySQL 全文检索中文支持 3.1 MyISAM 引擎表 ...

  8. RDS——mysql主从

    测试一:RDS主 RDS从   只需要创建一个RDS数据库实例   1.版本 RDS:5.6.21   2.操作步骤   选中被操作的数据--->点击实例操作---->创建只读副本---& ...

  9. 更改 AWS RDS mysql时区 -摘自网络

    AWS RDS AWS上搭建数据库的时候,不是DB on EC2就是RDS,但是选择RDS时,Timezone怎么处理? 「面向全球提供的AWS来讲理所当然的是UTC」,而RDS也不是例外.把服务器迁 ...

随机推荐

  1. 获取元素计算样式getComputedStyle()与currentStyle

    window.getComputedStyle()方法是标准化接口,返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有CSS属性的值. 私有的CSS属性值可以通过对 ...

  2. JS模拟百度分享侧边栏效果

    模拟百度分享侧边栏的弹出与滑入效果.当鼠标移入#div1分享侧边栏,#div1分享侧边栏区块匀速滑出直至其全部露出.当鼠标移除#div1分享侧边栏,#div1分享侧边栏区块匀速滑入隐藏,直至恢复初始位 ...

  3. fcntl函数用法——设置文件锁

    fcntl函数.锁定文件,设置文件锁.设置获取文件锁:F_GETLK .F_SETLK  .F_SETLKW文件锁结构,设置好用于fcntl函数的第三个参数.struct flock{    shor ...

  4. The Dos and Don'ts for Ceph for OpenStack

    Ceph和OpenStack是一个非常有用和非常受欢迎的组合. 不过,部署Ceph / OpenStack经常会有一些容易避免的缺点 - 我们将帮助你解决它们 使用 show_image_direct ...

  5. centos7下做内存盘的方法

    在找这个资料的时候,基本没几个能用的或者过时了的,或者是换了概念,做的不是需要的那种盘,只有少数文章有提到关键部分应该怎么去操作,现在还是自己总结一下 内存盘tmpfs和ramdisk的区别 这个在网 ...

  6. Spring第三天,详解Bean的生命周期,学会后让面试官无话可说!

    点击下方链接回顾往期 不要再说不会Spring了!Spring第一天,学会进大厂! Spring第二天,你必须知道容器注册组件的几种方式!学废它吊打面试官! 今天讲解Spring中Bean的生命周期. ...

  7. HotSpot类模型之ArrayKlass

    上一篇分析了 HotSpot类模型之InstanceKlass ,这次主要分析表示java数组类型的C++类. 1.ArrayKlass类 ArrayKlass继承自Klass,是所有数组类的抽象基类 ...

  8. PHP一些不一样的思路

    大多数来自p牛 SQL注入(left join) 源代码 <?php $link = mysqli_connect('localhost', 'root', 'root'); mysqli_se ...

  9. 面试半年,凭借这份JVM面试题,我终于拿到了字节跳动的offer!

    内存区域 虚拟机栈生命周期与线程相同,描述的是Java 方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧,用于存取局部变量表.操作数栈.动态链接.方法出口等信息本地方法栈与虚拟机栈作用相似,只 ...

  10. Folx使用教程:怎么通过设置标签分类下载内容

    很多Mac OS下载软件从网上下载各种各样的文件,一般默认都会存放在"下载"文件夹中.如果不是经常整理"下载"文件夹,久而久之,该文件夹会变得庞大而杂乱. 如果 ...