您的位置:首页 > 数据库 > MySQL

聊聊数据库(MySql)连接吧,你真的清楚吗?

2016-03-13 22:02 405 查看

前言


说到数据库连接,这个大家都很熟悉了。但是熟悉一般来自于下面三种情况

* 刚开始学编程的时候,老师就说用完的数据库连接一定要关闭,不然会有严重的后果。

* 编程一段时间后,大家都说要用连接池来优化数据库连接。

* 编程几年后,老大们说要考虑一台服务器mysql的并发连接数与负载等。

所以不停留在听说的层面,深入去学习与研究下mysql的连接机制与.net mysql驱动对连接的管理也挺有必要的。


本文会用到哪些工具

vs建立一个web项目,测试连接的建立与回收

navicate for mysql(可以看到mysql的连接数的实时监控)

nuget安装mysql.data.dll,.net mysql的驱动

**.net reflector* 反编译查看mysql驱动的源码

fiddler友情客串,测测并发

打开navicate for mysql->选择“工具”->服务器监控->勾选要监控的服务器

就可以看到这个服务器的实时连接情况,每隔5秒刷新一次。

每打开一个连接多一个,打开数据库的时候对一个,打开查询的时候也会多一个



如图的:1463 1465 1466就是刚才打开的。

一.先说说mysql的最大连接数

在navicate中查询:
show variables like '%max_connections%';


可以看到默认的数值为:
max_connections:151


为了便于测试我们修改my.ini文件中的max_connections参数,修改为10。一定要重启mysql服务才能生效



然后我们运行web项目,当打开页面的时候执行。注意这里注释了关闭连接语句:



这时我们在chrome中访问页面,当打开第8个页面时出现:
Too many connections
的异常。



为什么时第8个呢:因为之前说了打开数据库以及查询占了3个,所以8+3>10。自然就报mysql异常了。

我们看看服务器的监控:



都连接了2000多秒,还在一直连着,导致其他请求无法建立连接。这就是不释放连接的最直接的后果。

下面我们来手动结束那些没有被关闭的连接(右击连接->结束进程或者停止vs运行)。

接下来测试正常情况,取消连接关闭的注释

二.你关闭连接的时候,连接真的关闭了吗?

我们发现访问网页后,服务器中多了一个连接,进程id为1479。但是明明执行了
connection.Close()
,但结果好像不是我们预料的那样。

等待几十秒后发现随着访问的结束,这个连接的闲置时间为109秒没有被关闭掉。



但当我们重新打开一个网页后,发现



这个连接的闲置时间被重置了为0了。

这种现象跟mysql并没有太多原因,这是由mysql 的.net驱动控制的。当我们调用
connection.Close()
时,与mysql建立的socket连接被没有真正的关闭掉,而是被保留并置为空闲状态。

当新的请求连接过来后,会直接使用这个连接而不会建立新的socket连接。这是mysql驱动自带的连接池功能,来优化性能与资源。

我们来翻下mysql.data的源代码:



大部分情况下我们调用
connection.Close()
只是调用:
this.SetState(ConnectionState.Close,true)
,改变一下连接的状态而已。并非真的关闭

真正的关闭时调用
CloseFully()




mysql驱动申请的连接真正关闭是通过超时实现的。经过测试如果闲置300秒左右,这个连接就会被彻底关闭了

所以交互流程图是这样的:



三.断网了怎么办?

正常情况下自然是好,但是如果:



这时候出现的状况就比未手动关闭数据库连接还要严重,程序已经失去控制权了。会出现一批处于空闲中的数据库连接无法被正常释放掉。如果网络时好时坏,就有可能是一批接一批的。

所以mysql服务内部也有一个超时机制,当一个socket连接长期空闲的时候mysql服务端会强制关闭这个连接。如果等mysql的超时机制来处理的问题,

超时时间通过:
show global variables like '%timeout%';




如上图所示的
wait_timeout
就是控制等待空闲超时的参数,默认为28800秒也就是8小时

四.连接符中配置的Min Pool Size=?;Max Pool Size=?;驱动是如何管理的?

通常在配置连接字符串的使用连接池,如我们配置

var connection = new MySqlConnection(@"Data Source=*;port=3306;                                         User ID=*;Password=*;                                         database=spring;Persist Security Info=false;                                         Connect Timeout=30;Min Pool Size=2;Max Pool Size=5;");


首先Min Pool Size=2;

运行项目后,会一次多出两个连接,如下图:



而且这两个连接只要iis没有回收,不会被销毁



任何请求过来后。只要这两个连接有空闲,就不会创建新的连接

接着Max Pool Size=5;

如果
Min Pool Size
设置的数量不够用,也就是并发量大与2的时候,那么mysql驱动就会申请更多的连接。

我们来实际测试一下,使用fiddler我们来模拟下“瞬间的大量请求”:

打开fiddler->浏览器中请求网页->在filddler找到那个请求->按住shift->点击菜单中的Replay->输入50->点击ok

这样就会异步同时发出50个请求。





我们看下服务器的监控信息:



这时就会同时创建5个连接,因为2个不够 5个最大,所以只能创建5各连接供使用,后面的请求只能等其他请求释放连接以后才能进入处理。

如果你在连接关闭前设置:
Thread.Sleep(5000)
,让连接延迟5秒再关闭。就能明显的感觉到大量数据库请求阻塞,因为没有额外的连接来处理请求了。

那是不是实际场景中,之前讲的
max_connections
Max Pool Size
都设置最大好了?

当然不是,服务器的性能有限啊。你设置最大,高并发的时候连接限制倒是没有,但整个服务器估计就挂了。

继续刚才的Max Pool Size,申请的五个连接,如果闲置300秒左右。有3个会被回收掉,只会保留
Min Pool Size
生成的2个。请看截图



也就是连接符中设置的
Min Pool Size
会永久的生成两个连接在那里,不会被关闭。
Max Pool Size
只在
Min Pool Size
不够的时候生成,用完(闲置超时后)会被关闭掉

程序中无论多少并发请求,mysql驱动提供给当前应用的连接数都不会超过
Max Pool Size
。这样看起来
Max Pool Size
也有保护服务器不被拖垮的作用

未完待续……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: