从头说起,最近服务器硬盘空间开始紧张,主要是用户上传文件不断增加导致的,于是前天着手解决
我们用的青云,很简单,新建块硬盘挂上,把上传目录迁移过去,然后ln
一下,搞定
然后就悲剧了
昨天晚上无意间发现大量文件404了,赶紧查
第一反应是挂载有问题,排除,权限问题,排除,log也没发现对应错误(其实基本没什么log…)
没辙了只能反复试错,然后确定问题肯定在ln
上,进而确定是跨盘ln
造成的,甚至开始怀疑是CentOS的bug…
搞了几个小时没找到解决方案,决定放弃,准备调整系统改为把上传目录指定到新磁盘上(幸亏没做做了也没用)
然后冷静了一会,决定去翻上传代码,上传用的是 flow.js,服务端就直接用了它的示例代码,由于比较复杂一直不想碰,翻了一会看到了这行: https://github.com/flowjs/flow.js/blob/master/samples/Node.js/flow-node.js#L112
fs.rename(files[$.fileParameterName].path, chunkFilename, function() {
//...
});
直觉告诉我就是它了,一查果然:https://github.com/joyent/node/issues/2703(看下底下那一堆ref都是栽在这的) 擦,fs模块竟然用rename来处理move,而且还不符合move的语义,然后示例代码压根就没考虑处理rename错误,然后万年callback坑又把异常给吃掉了… 找到问题就等于解决了,后面就不说了
教训:
- Callback的的确确是Hell
- 错误处理不当坑死人,做大项目堪忧
- log多多益善
- 拿来主义害死人,在Node里用第三方代码一定慎之又慎
@tulayang “rename在*nix设计出来时,就是移动文件的功能” 是不是说反了?
楼主 @ravenwang man 2 rename
就知道了。这个其实也要怪 Node.js,它没具体说会遇到什么类型的错误,鬼知道还要去看*nix文档,而且flow的samples竟然误导人不handle错误。
EXDEV oldpath and newpath are not on the same mounted file system. (Linux permits a file system to be mounted at multiple points, but rename() does not work across different mount points, even if the same file system is mounted on both.)
另外楼主不是一开始就应该将上传文件临时文件夹和目标文件夹设置成同一分区么?每次copy多费力啊