V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dreamer2020
V2EX  ›  Node.js

nodejs 爬虫长时间运行后卡住

  •  
  •   dreamer2020 · 2018-05-22 21:07:34 +08:00 · 7031 次点击
    这是一个创建于 2375 天前的主题,其中的信息可能已经有所发展或是发生改变。
    各位大佬,
    有一个困惑许久的问题:

    用 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 ”

    各位大佬,有没有遇到过类似问题的?能否给出一些提示思路?非常感谢!
    17 条回复    2018-05-23 11:48:39 +08:00
    jiangzhuo
        1
    jiangzhuo  
       2018-05-22 21:25:18 +08:00 via iPhone
    能上生产服务器的话,看看当前堆栈不就好了
    LevineChen
        2
    LevineChen  
       2018-05-22 21:26:01 +08:00 via iPhone
    同遇到
    airyland
        3
    airyland  
       2018-05-22 21:43:24 +08:00
    如果暂时不能确定到具体问题,可以在一个或者多个抓取任务结束后,直接 process.exit(1),pm2 会自动重启,还也可以定义 restart delay。
    dreamer2020
        4
    dreamer2020  
    OP
       2018-05-22 21:44:16 +08:00
    @jiangzhuo 弱问一下,怎么样查看当前状况下的堆栈啊?
    jiangzhuo
        5
    jiangzhuo  
       2018-05-22 21:45:14 +08:00 via iPhone
    @dreamer2020 就是平时调试用的那些工具的 pstack 啊 strace 啊找到问题再 gdb 啊
    dreamer2020
        6
    dreamer2020  
    OP
       2018-05-22 21:47:51 +08:00
    @jiangzhuo 哦,明白了。感谢!
    dreamer2020
        7
    dreamer2020  
    OP
       2018-05-22 21:48:40 +08:00
    @airyland 这确实是一个当前的解决办法!
    gabon
        8
    gabon  
       2018-05-22 22:00:47 +08:00 via Android
    死锁?
    whypool
        9
    whypool  
       2018-05-22 22:06:31 +08:00   ❤️ 2
    遇到过,解决如下:
    1,主动释放内存,虽然会自动 gc,但是爬取很快的时候,内存直接飙到 2G+,然后直接卡死
    2,爬取频率,不要用阻塞的迭代,比如 for map each 什么的,如果有迭代最好用递归,放 settimeout 延迟执行

    目前爬取了某云歌曲 80w+,内存占用稳定 90M,运行一个多月了
    ETiV
        10
    ETiV  
       2018-05-22 23:22:05 +08:00
    pm2 start 命令前加「 DEBUG=*」,看有没有输出
    aisin
        11
    aisin  
       2018-05-22 23:25:56 +08:00
    @whypool 兄弟说的很靠谱,我现在也都是这么干的
    shiny
        12
    shiny  
       2018-05-22 23:28:24 +08:00
    分享下我的经验: 使用 eggjs 的 schedule 设置定时任务,使用 Kue 或者 async.js 创建队列,设置好并发数,控制进队列的数量(比如用数据库储存任务,分批读取送进队列抓取),内存和 CPU 使用非常稳定。有问题建议使用 alinode 跟踪诊断。
    LeungJZ
        13
    LeungJZ  
       2018-05-22 23:35:38 +08:00
    我也遇到了。
    我的问题:抓取数据后,更新数据库( mongodb,bulkWrite 更新),更新时长 12000 个文档需要 60000ms。
    最后解决办法:使用 egg.js 的定时任务和 mongodb 的插件,更新方式是先查询是否存在,存在的一个个更新,save,不存在的批量插入,insertAll。12000 个文档耗时 1s 不到。

    服务器:2C4G。
    qfdk
        14
    qfdk  
       2018-05-23 00:19:03 +08:00 via iPhone
    你 mongo 插了多少数据?
    dreamer2020
        15
    dreamer2020  
    OP
       2018-05-23 11:40:36 +08:00
    @whypool 内存这个问题之前我也注意到了,确实需要释放,我现在最多是 300M 左右。

    迭代用得比较多,主要是 for,用了 async/await 控制异步,用 Promise.map 做了多并发。大佬说的递归,应该是在函数里面使用 setTimeout 延迟调用自己吧?

    另外,关于 Promise.map 有什么改进建议么?
    dreamer2020
        16
    dreamer2020  
    OP
       2018-05-23 11:47:19 +08:00
    @gabon node 不是单线程的么?没有考虑过锁的问题
    dreamer2020
        17
    dreamer2020  
    OP
       2018-05-23 11:48:39 +08:00
    @qfdk 一次最多会塞 4 万条数据
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5255 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 59ms · UTC 09:10 · PVG 17:10 · LAX 01:10 · JFK 04:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.