Nodejs 爬虫长时间运行后卡住
Nodejs 爬虫长时间运行后卡住
各位大佬,
有一个困惑许久的问题:
用 nodejs 做了一个爬虫,每天定时爬取数据,node 版本 v9.8.0,定时试过系统命令 crontab,现在用 node-schedule,使用 pm2 管理程序。
爬虫在运行一段时间后,有时候是三四天,有时候是一周或者更长后,卡住了。没有错误日志,pm2 也没有任何日志信息,程序也没有退出,似乎是卡死在后台了。
程序使用的依赖如下:
“ axer ”: “ 0.0.5 ”,
“ log4js ”: “^1.1.1 ”,
“ moment ”: “^2.18.1 ”,
“ mongodb ”: “^3.0.5 ”,
“ node-schedule ”: “^1.2.4 ”,
“ bluebird ”: “^3.5.1 ”,
“ util ”: “^0.10.3 ”,
“ xml2js ”: “^0.4.17 ”
各位大佬,有没有遇到过类似问题的?能否给出一些提示思路?非常感谢!
能上生产服务器的话,看看当前堆栈不就好了
如果暂时不能确定到具体问题,可以在一个或者多个抓取任务结束后,直接 process.exit(1),pm2 会自动重启,还也可以定义 restart delay。
弱问一下,怎么样查看当前状况下的堆栈啊?
就是平时调试用的那些工具的 pstack 啊 strace 啊找到问题再 gdb 啊
哦,明白了。感谢!
这确实是一个当前的解决办法!
死锁?
遇到过,解决如下:
1,主动释放内存,虽然会自动 gc,但是爬取很快的时候,内存直接飙到 2G+,然后直接卡死
2,爬取频率,不要用阻塞的迭代,比如 for map each 什么的,如果有迭代最好用递归,放 settimeout 延迟执行
目前爬取了某云歌曲 80w+,内存占用稳定 90M,运行一个多月了
pm2 start 命令前加「 DEBUG=*」,看有没有输出
兄弟说的很靠谱,我现在也都是这么干的
分享下我的经验: 使用 eggjs 的 schedule 设置定时任务,使用 Kue 或者 async.js 创建队列,设置好并发数,控制进队列的数量(比如用数据库储存任务,分批读取送进队列抓取),内存和 CPU 使用非常稳定。有问题建议使用 alinode 跟踪诊断。
我也遇到了。
我的问题:抓取数据后,更新数据库( mongodb,bulkWrite 更新),更新时长 12000 个文档需要 60000ms。
最后解决办法:使用 egg.js 的定时任务和 mongodb 的插件,更新方式是先查询是否存在,存在的一个个更新,save,不存在的批量插入,insertAll。12000 个文档耗时 1s 不到。
服务器:2C4G。
你 mongo 插了多少数据?
内存这个问题之前我也注意到了,确实需要释放,我现在最多是 300M 左右。
迭代用得比较多,主要是 for,用了 async/await 控制异步,用 Promise.map 做了多并发。大佬说的递归,应该是在函数里面使用 setTimeout 延迟调用自己吧?
另外,关于 Promise.map 有什么改进建议么?
node 不是单线程的么?没有考虑过锁的问题
一次最多会塞 4 万条数据
在Node.js中,爬虫程序长时间运行后卡住的问题可能由多种因素引起,包括但不限于内存泄漏、资源未释放、异步回调未处理等。以下是一些常见的调试和优化建议:
- 内存泄漏检查:使用Node.js的内存分析工具,如
heapdump
和Chrome DevTools
,来监控和分析内存使用情况。
const heapdump = require('heapdump');
// 在爬虫运行一段时间后触发堆快照
setTimeout(() => {
heapdump.writeSnapshot((err, filename) => {
console.log('Heap snapshot written to', filename);
});
}, 3600000); // 例如,1小时后
- 资源释放:确保每次请求后都正确关闭连接和释放资源,例如使用
axios
时设置responseType: 'stream'
并监听end
事件来关闭流。
const axios = require('axios');
axios({
url: 'http://example.com',
responseType: 'stream'
}).then(response => {
response.data.on('end', () => {
console.log('Stream ended');
});
}).catch(error => {
console.error('Error:', error);
});
-
异步回调处理:使用
async/await
或Promise
来确保异步操作正确完成,避免“僵尸”回调。 -
超时设置:为HTTP请求设置超时时间,防止请求挂起。
axios.get('http://example.com', { timeout: 5000 }); // 设置5秒超时
- 日志记录:增加详细的日志记录,帮助定位问题发生的位置。
通过上述方法,可以有效减少Node.js爬虫长时间运行后卡住的问题。