六、MySQL连接池所受的限制#
数据库连接池的大小到底设置为多少,得根据业务流量以及数据库所在机器的性能综合考虑。
mysql连接数到配置在 my.cnf中,具体的参数是max_connections。
当业务流量异常猛烈时,很可能会出现这个问题:to many connections
对于操纵系统内核来说,当他接受到一个tcp请求就会在本地创建一个由文件系统管理的socket文件。在linux中我们将它叫做文件句柄。
linux为防止单一进程将系统资源全部耗费掉,会限制进程最大能打开的连接数为1024,这意味着,哪怕通过改配置文件,将mysql能打开的连接池设置为9999,事实上它能打开的文件数最多不会超过1024。
这个问题也好解决:
命令:设置单个进程能打开的最大连接数为65535
ulimit -HSn 65535
通过命令: 查看进程被限制的使用各种资源的量
ulimit -a core file size: 进程崩溃是转储文件大小限制 man loaded memort 最大锁定内存大小 open file 能打开的文件句柄数
这些变量定义在 /etc/security/limits.conf配置文件中。
七、关于失效的连接#
情况1: 客户端主动断开
如果是客户端主动将连接close(), 那往这些连接中写数据时会得到ErrBadConn的错误,如果此时依然可以重试,将会获取新的连接。
代码如下:
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) { var res Result var err error for i := 0; i < maxBadConnRetries; i++ { res, err = db.exec(ctx, query, args, cachedOrNewConn) if err != driver.ErrBadConn { break } } if err == driver.ErrBadConn { return db.exec(ctx, query, args, alwaysNewConn) } return res, err }
情况2: 服务端挂啦
因为这种数据库连接底层使用的是tcp实现。(tcp本身是支持全双工的,客户端和服务端支持同时往对方发送数据)依赖诸如:校验和、确认应答和序列号机制、超时重传、连接管理(3次握手,4次挥手)、以及滑动窗口、流量控制、拥塞避免,去实现整个数据交互的可靠性,协调整体不拥挤。
这时客户端拿着一条自认为是正常的连接,往连接里面写数据。然鹅,另一端端服务端已经挂了~,但是不幸的是,客户端的tcp连接根本感知不到~~~。
但是当它去读取服务端的返回数据时会遇到错误:unexceptBadConn EOF
八、连接的有效性#
- 思路1:
设置连接的属性: maxLifeTime
上面也说过了,当设置了这个属性后,DB会开启一条协程connectionCleaner,专门负责清理过期的连接。
这在一定程度上避免了服务端将连接断掉后,客户端无感知的情况。
maxLifeTime的值到底设置多大?参考值,比数据库的wait_timeout小一些就ok。
- 思路2:
主动检查连接的有效性。
比如在连接放回到空闲连接池前ping测试。在使用连接发送数据前进行连通性测试。