解决 packets.go123 closing bad idle connection EOF

6 min read

问题

从连接池中拿到的是一个空闲连接,但是这个链接已经被mysql服务器中断了

中断的原因大概是sleep时间太长了,超过了wait_timeout设置的时间

如果是这种情况,那么解决办法比较简单,就是对于连接有效时长的控制,最直接的变量是: maxLifetime ,它可以用 SetConnMaxLifetime 设置连接的有效时长。

当 <= 0 时,连接永久保存,默认值时 0 。

如果设置了 maxLifetime 会开启连接自动清理,定时检查空闲连接池中的连接,超期的关闭连接。

也有可能是golang驱动包的bug,这个就需要升级驱动包来解决了,据说1.5之后的,基本不会遇到这个问题,可以尝试使用go get -u进行升级(go get -u github.com/go-sql-driver/mysql

SetConnMaxLifetime 方法

现在让我们来看一下SetConnMaxLifetime()方法,它设置了连接可重用的最大时间长度。如果您的SQL数据库也实现了最大的连接生存期,或者(例如)您希望在负载均衡器后面方便地切换数据库,那么这将非常有用。

您可以这样使用它:

// 初始化连接池
db, err := sql.Open("postgres", "postgres://user:pass@localhost/db")
if err != nil {
    log.Fatal(err)
}

// 设置连接的最大生命周期为一小时。
// 设置为0的话意味着没有最大生命周期,连接总是可重用(默认行为)。
db.SetConnMaxLifetime(time.Hour)

在这个例子中,我们的所有连接将在第一次创建后1小时“过期”,并且在它们过期后无法重用。但是注意:

  • 这并不能保证连接将在池中存在完整的一小时;很可能由于某种原因连接将变得不可用,并且在此之前自动关闭。
  • 一个连接在创建后仍可以使用一个多小时,只是说一个小时后不能再被重用了。
  • 这不是空闲超时。连接将在第一次创建后1小时后过期,而不是1小时后变成空闲。
  • 每秒自动运行一次清理操作以便从池中删除“过期”连接。

理论上,ConnMaxLifetime越短,从零开始创建连接的频率就越高。