问题出现是这样的,用node写爬虫, 之前每条数据都是await插入,并且是阻塞的,后来改成了非阻塞,可以并行插入操作,结果一直找不到原因。
后来在日志中找到了 too many connections,分析如下:
用nodejs写爬虫的时候,使用了类似这样的函数
let conn = null;
try{
conn = await pool.getConnection();
await conn.begin()
let rst = await .conn.query('xxxx',params);
// 处理rst
...
await conn.commit()
}catch(e){
if(conn) await conn.rollback();
}finally{
if(conn) await conn.release();
}
乍一看没有问题,执行爬虫之后,我会调用这段代码把分析过的数据存在数据库里。
但是由于我是使用非阻塞的形式进行抓取数据的,如下
emitter.on('url_found', async (url)=>{
// 请求url地址,获取返回的response body
let res = await request(url);
// 处理res
...
// 后面调用上面的第一段代码
})
这里会发生一件事,就是可能同时触发了1000个这样的事件,然后一起获取链接,但是还没有释放,然后报错: too many connections
============================ 解决方案 ===============================
改造获取sql连接的函数
1. 判断当前连接数是否达到最大,如果否,则直接返回连接池内连接,连接数++
2. 如果上述判断为true,则等待一个promise,将该promise的resolve函数推入等待队列
3. 当某一个连接release的时候,连接数--
4. release中调用pool的notifyFirstWaiting方法,每次取出队列第一个resolve并执行,然后该resolve出列
5. 第二步中的promise的resolve被执行后,则会执行后续代码,此时等待的promise被唤醒,尝试重新获取连接返回