橡皮擦擦

MySQL连接池的超时设定

Golang,MySQL

MySQL服务端连接池创建的连接默认保存8小时(wait_timeout配置项), 也就是说8小时内, 用这个连接去执行操作都是可以的.
如果超过8小时没人用这个链接, MySQL就会关掉这个链接.

超时配置参数

wait_timeout

一个连接会有idle(闲)以及open(忙)两种状态, 那么一个长期处于idle的链接,MySQL服务器就会想要关掉它.
这个”长期”指的是多久? 就是这个参数指定的时长.官方文档!

MaxLifetime

服务端自己也会关掉一些时间比较长/或者说比较”老”/比较”年龄大”的链接.
这个参数通过SetConnMaxLifetime设置, 假设你设置这个时间为1小时, 那么理论上一小时后, 这个连接就会被关闭.

请注意这个时间跟上面的时间并不是一个概念, MySQL关注的是这个链接idle多久了, idle够久了再关.
但是ConnLifeTime关注的是从创建开始->到现在, 时间到了就关.

ReadTimeout

启动MySQL命令行的时候会有一个参数叫做readTimeout,从发送请求开始, 如果到了时间还没拿到我要的数据, 那么就算超时
这个则针对一次请求, 强调请求响应的快与慢. i/o timeout的问题常见于网络拥堵的环境下

调整wait_timeout带来的表现

wait_timeout:使用一个被mysql断开的链接: 如下所示, 首先我们把wait_timeout设置成1, 也就是说任何连接只要idle时间超过1立刻被断开.
随后, 我们修改源码, 在获得数据库链接对象以后, 休眠10秒, 这个时候你拿到的就是一个已经被mysql断开的链接. 这种情况下会发生什么呢?

//调整mysql数据库设置
mysql > set global wait_timeout = 1
mysql > select @@global.wait_timeout
//服务器: $GOROOT/src/database/sql/sql.go
func(db* DB)query() {  
    dc,err := db.conn()   
    time.Sleep(10 * time.Second)  
    ...
}
packets.go:122: closing bad idle connection: EOF

packets.go:36: unexpected EOF 

panic: invalid connection

而上面的panic是我代码中的:rows,err := db.Query(), 也就是说在使用一个被服务器断开的链接的情况下,
会报错invalid connection , 至此, 我们已经知道了,
我们遇到的invalid connection到底是因为什么而出现的, 也知到”无效链接”,到底是什么东西无效了

调整SetConnMaxLifetime的表现

SetConnMaxLifetime:如果是自己断开的链接 SetConnMaxLifetime是指你的go程序自己断开链接, 需要多久.
我们尝试一下这种情况下会发生什么. 首先我们知道,在默认表现下, 你只要db := sql.Open()就能获得一个连接,
缓存起来,然后下次查询的时候用起来. 就像下面一样:

numFree = 0 # 这是你Open的时候, 刚开数据库, 还没有可用连接

Retry = 0   # 你准备开始查询了, 三次重试, 这是第一次

numFree = 1 # 诶? 你发现你有一个缓存的连接, 直接拿来用

现在我们改一改, 把SetConnMaxLifetime设置成1, 然后再睡10秒, 这样你通过Open缓存的连接就无效了, 这样会发生什么?

db.err := sql.Open()
db.SetConnMaxLifetime(1)
time.Sleep(10 * time.Second)
results,err := db.Query()
numFree = 0      # Open缓存一个

Retry = 0        # 开始查询

numFree = 0      # 超时, 无可用连接对象

here id = 239611 # 正确的输出

虽然已经超时了, 但是我们的服务端正确识别了已经被关闭的链接(毕竟也是你自己关的嘛), 在没有缓存连接的情况下,
服务端创建了一个新链接, 并使用起来, 没有报错.

结论: 我到底应该怎么办

让你的Go程序自己结束链接, 不要让服务器终端链接, 因为你自己中断链接至少是安全的.

令: SetConnMaxLifetime < wait_timeout

请输入图片描述
假设你的wait_timeout是8小时, 那么你的链接起步就能存活8小时(从头到尾idle),
那么你就设置SetConnMaxLifetime为7小时, 那你就一定能在MySQL中断之前, 自己先中断了

点我评论
打赏本文
二维码


45

文章

6

分类