mongoDB的连接池问题
1.引言
最近在优化后端接口的时候,因为不同接口都需要去操作数据库,这就产生了一个疑惑,我是应该一直连着还是连接并操作完数据库之后断开连接呢,然后每次需要操作数据库连接,然后关闭,这样有点尴尬,一个接口对应一次连接和断开,是不是有点憨憨的,但是如果我不断开,会不会导致连接池达到上限呢?
结论:应该操作数据库之后断开连接
2.问题分析
一般数据库操作都是追求安全的,也就意味着大概率使用TCP连接,一搜,果然是TCP。那么问题就来了TCP是长连接,你不断开他就一直连着。如果我们只看一次连接需要消耗的资源,不设置连接池的话,那么数据库不断开,一直连一直连,那么迟早会耗尽服务端的资源,为什么这么说呢,应为客户端远比服务端多的多(一般服务端就是一个内存还不如客户端的Linux系统)。所以连接池机制还是很有必要的
。
3.佐证
还是有点半信半疑,于是我去搜了搜后端数据库操作数据之后是否需要断开与数据库的连接?
。好巧不巧,遇到了Java老大哥里面的jdbc
,网上说jdbc
不需要断开连接,因为里面的finally会主动帮助断开连接,设置有些大佬还提到一些框架是能够主动帮助我们断开与数据库的连接的。这也就解释了为什么,很多时候都没有这个断开数据库连接的习惯。这些本质是框架自己完成的,即需要断开连接。
4.分析目标mongoDB
我这里的项目是使用koa框架,里面用的是mongoDB第三方依赖,官网中给出的实例代码如下:
可以看出需要主动断开连接,另外还有人用复杂一点的mongoose
连接数据库,嘿嘿,一搜发现mongoose
自带连接池,那就是也需要断开连接的,和jdbc
一样,它帮我们完成了。
5.实际测试
如果真的有连接限制,那么就如同大佬说的那样,连接过多会变慢,就像是很多人挤进操场和一个人去操场一样。那我直接连接多次mongoDB,看看会发生什么吧,程序代码如下:
const dbUserName = "用户名";
const dbPassWord = "用户密码";
const targetDataBase = "连接的数据库";
const url = `mongodb://${dbUserName}:${dbPassWord}@远程ipAddress/${targetDataBase}`;
const { MongoClient } = require("mongodb");
module.exports = async (ctx) => {
let isSuccess = true;
let success = 0;
let fail = 0;
let timer = setInterval(() => {
const client = new MongoClient(url);
client
.connect()
.then((res) => {
console.log("连接成功:", res);
success++;
})
.catch((err) => {
console.log("连接失败:", err);
isSuccess = false;
fail++;
clearInterval(timer);
})
.finally(() => {
console.log("完成" + success + "次测试", "失败" + fail + "次测试");
});
}, 100);
};
当然运行的时候由于连接失败程序直接崩了,promise里面的数据没有打印,也就是具体能连多少还是看不出来:
第一次测试是在重启了mongoDB的情况下进行的,然后我测一下接口,发现还是能连接,然后没有重启又测了一次:
可以明显看出timeout
,也就是真的“挤”不进去了。
为了确认我又去看了下服务器的日志:
好家伙,服务器把锅给了客户端,说这是客户端主动断开连接
。那现在连接池很卡了,我接着连会不会直接报错呢?看来这个连接池是相对卡顿的。补充这里的setInterval
,这个停下来会比预想的慢,因为发出去的请求是否成功,setInterval
管不了,只是在失败的那一次停止,之前已经发出去的的可能也还有失败的)。
好接下来反向论证一下,将finally里面的关闭连接(client.close()
),得到如下结果:
这个是我主动关闭连接,因为是函数里面调用,也不存在内存不够的情况,理论上无穷次连接。
6.得出结论
使用mongoDB数据库的时候,如果使用mongoose依赖,内部具有默认连接池,不需要关闭连接,如果使用mongoDB依赖,需要主动关闭连接,不关闭连接,最大连接大概在700左右,在连接峰期结束之后还能恢复正常。如果主动关闭连接,那么连接次数就是无穷次。