`npm uninstall` 挂起(或非常慢)没有明显 activity

`npm uninstall` hangs (or very slow) without apparent activity

我总是发现 npm uninstall 花费的时间出奇地长,我正在尝试进行故障排除。我在大约 25 分钟前开始卸载四个软件包,它似乎停滞不前,没有任何进展,没有明显的 CPU activity,也没有明显的磁盘 activity(使用 iotop) .我不知道问题是什么。

这是日志级别为 'silly' 的当前输出(匿名):

$ npm uninstall --save-dev -ddd gulp-autoprefixer gulp-sass gulp-sequence gulp-sourcemaps
npm info it worked if it ends with ok
npm verb cli [ '/path/to/home/bin/node-v0.12.2-linux-x64/bin/node',
npm verb cli   '/path/to/home/bin/node-v0.12.2-linux-x64/bin/npm',
npm verb cli   'uninstall',
npm verb cli   '--save-dev',
npm verb cli   '-ddd',
npm verb cli   'gulp-autoprefixer',
npm verb cli   'gulp-sass',
npm verb cli   'gulp-sequence',
npm verb cli   'gulp-sourcemaps' ]
npm info using npm@2.7.4
npm info using node@v0.12.2
npm verb unbuild node_modules/gulp-autoprefixer
npm verb unbuild node_modules/gulp-sass
npm verb unbuild node_modules/gulp-sequence
npm verb unbuild node_modules/gulp-sourcemaps
npm sill gentlyRm /path/to/home/myproject/node_modules/gulp-autoprefixer is being purged from base /path/to/home/myproject
npm verb gentlyRm don't care about contents; nuking /path/to/home/myproject/node_modules/gulp-autoprefixer
npm sill gentlyRm /path/to/home/myproject/node_modules/gulp-sass is being purged from base /path/to/home/myproject
npm verb gentlyRm don't care about contents; nuking /path/to/home/myproject/node_modules/gulp-sass
npm sill gentlyRm /path/to/home/myproject/node_modules/gulp-sequence is being purged from base /path/to/home/myproject
npm verb gentlyRm don't care about contents; nuking /path/to/home/myproject/node_modules/gulp-sequence
npm sill gentlyRm /path/to/home/myproject/node_modules/gulp-sourcemaps is being purged from base /path/to/home/myproject
npm verb gentlyRm don't care about contents; nuking /path/to/home/myproject/node_modules/gulp-sourcemaps
npm sill vacuum-fs purging /path/to/home/myproject/node_modules/gulp-autoprefixer
npm sill vacuum-fs purging /path/to/home/myproject/node_modules/gulp-sass
npm sill vacuum-fs purging /path/to/home/myproject/node_modules/gulp-sequence
npm sill vacuum-fs purging /path/to/home/myproject/node_modules/gulp-sourcemaps

...我启动后不久就停在那里了。早期一次删除一个包的尝试奏效了,但仍然在 vacuum-fs 步骤停滞了一段时间(大约 30 秒)。我是 运行 Ubuntu 14.04 LTS,配备 8 GB 内存的四核 Intel i5、Node v0.12.2 和 npm 2.7.4。

有谁知道可能是什么问题或如何进一步解决问题?

(顺便说一句,我不确定这是否是解决工具问题的合适 StackExchange 站点,所以如果不是,请推荐其他站点!)


编辑: 我根据下面@dekkard 的回答使用 strace 进行了一些调查;这是发生减速的区域的摘录(以 strace -f -t -o out.log npm uninstall -D gobble 为例):

...
18327 17:00:52 rmdir("/path/to/home/myproject/node_modules/gobble/node_modules/minimatch" <unfinished ...>
18318 17:00:52 read(8, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=]", 1024) = 8
18318 17:00:52 epoll_wait(5,  <unfinished ...>
18325 17:00:55 <... rmdir resumed> )    = -1 ENOTEMPTY (Directory not empty)
18325 17:00:55 write(8, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=]", 8) = 8
18325 17:00:55 rmdir("/path/to/home/myproject/node_modules/gobble/node_modules/mkdirp" <unfinished ...>
18318 17:00:55 <... epoll_wait resumed> {{EPOLLIN, {u32=8, u64=8}}}, 1024, -1) = 1
18318 17:00:55 read(8, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=]", 1024) = 8
18318 17:00:55 epoll_wait(5,  <unfinished ...>
18328 17:00:58 <... rmdir resumed> )    = -1 ENOTEMPTY (Directory not empty)
18328 17:00:58 write(8, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=]", 8) = 8
18318 17:00:58 <... epoll_wait resumed> {{EPOLLIN, {u32=8, u64=8}}}, 1024, -1) = 1
18328 17:00:58 rmdir("/path/to/home/myproject/node_modules/gobble/node_modules/promise-map-series" <unfinished ...>
18318 17:00:58 read(8, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=]", 1024) = 8
18318 17:00:58 epoll_wait(5,  <unfinished ...>
18326 17:01:01 <... rmdir resumed> )    = -1 ENOTEMPTY (Directory not empty)
18326 17:01:01 write(8, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=]", 8) = 8
18318 17:01:01 <... epoll_wait resumed> {{EPOLLIN, {u32=8, u64=8}}}, 1024, -1) = 1
...

在控制台中实时查看时,每个 epoll_wait(5, 和任何后续输出之间有约 3 秒的停顿。想法?

我建议找到您的 npm uninstall 的 PID 并使用 straceltrace:

附加到它
strace -c -p <PID>

http://linux.die.net/man/1/strace

-c
Count time, calls, and errors for each system call and report a summary on program exit

此外,您还可以过滤要跟踪的内容(即文件、网络、信号等)

更新:

18318 17:00:52 epoll_wait(5, <unfinished ...>

您可以尝试向后滚动并找到返回 epollfd == 5 的对 epoll_create() 的调用,后者随后传递给 epoll_wait().检查其周围的呼叫可能会提供一些线索。

为了将来参考,根本问题是以下两件事的结合:

  1. 节点 rimraf 模块(被 npm 和许多其他包使用)通过首先尝试删除目录来运行,并且只有在 rmdir 错误 ENOTEMPTY(参见 this line in the rimraf source)。

  2. 我的项目文件夹在一个 AFS 卷上,默认情况下,AFS 文件服务器似乎会限制连续发出太多失败 RPC 的客户端(向 MIT's Student Information Processing Board 的人们提示通过电子邮件指出这一点)。具体来说,默认设置会为连续超过 10 个失败的 RPC 设置 3 秒延迟。

最终结果是 rimraf 和依赖它的包在 AFS 卷上的爬行速度很慢,至少在我的机器上是这样……虽然看起来有 OS 优化要做至少 一些 命令在到达文件服务器之前就出现错误(例如 http://milek.blogspot.com/2014/01/mkdir-performance.html),根据上面的日志,我的系统上 rmdir 似乎没有发生这种情况.

我在这里开了一个 rimraf 问题:https://github.com/isaacs/rimraf/issues/73