在阿里云上使用Node搭建“图书转码“服务遇到了天坑,实在搞不定了,跪求帮助(如果有高人愿意出手帮忙,我们可以掏钱咨询)
发布于 7 年前 作者 hz0324 5907 次浏览 来自 问答

我们是一个小团队,全栈JS,后端用的Nodejs,做的是在线epub电子书阅读器,网址:www.neat-reader.cn 因为我们有很多用户想打开 mobi 格式的电子书,或是希望提供一个 mobi 转码成 epub 的功能。所以我们想要搭建一个专门的转码服务器。

至于转码的方式,我们是用一个叫 Calibre 的开源项目提供的 CMD 命令行。 目前我们在阿里云上有一个实验服务器(1核2G内存,Windows Server),用于测试转码服务器的效果。 现在遇到了很奇怪的问题:在本地跑的好好的,但是一旦上到服务器,就会出错,导致服务器崩溃。实在找不到原因,只能求助于大家了。

用户使用我们的服务,以及我们的程序运行的流程如下: 1.用户打开转码页面,选择一个文件,以及目标转码格式,然后点提交。 2.此时前端会向服务器发送一个任务提交请求,后端会在文本数据库中(用的nedb)创建一个task,有id信息,还有新上传的文件要存在哪里之类的信息,最重要的是一个工作状态值:uploading。然后把这些数据返回给前端 3.前端收到task创建成功的返回后,开始上传文件到指定地点(上传使用的是一个叫formidable的包),上传成功后,这个task的状态值会改为waiting。同时告诉前端,文件传完了,然后前端会每一秒使用task id询问服务器:我的这个task现在怎么样了 4.后端每次收到前端的询问请求,都会做一次判断,看看这个task是不是整个task表中,第一个状态为waiting的,如果是,则调用CMD对文件进行转码(CMD使用的是node-cmd包,这个包运行完成后会输出两种状态,要么成功,要么失败,其他我们一概不知),同时把这个task的状态改为processing,期间前端询问时,我们就告诉它正在processing,过1秒你再来问!等CMD成功或是失败后,task的状态就会修改成success或是fail。此时当前端询问时,就告诉它,如果成功,告知下载地址,如果失败,告知失败原因。到此为止,一个转码请求就算结束了。 我们认为按照这样的设计,可以保证很多用户同时提交任务也不会导致崩溃。

类似的流程可以看这个网站:http://www.epubconverter.com/epub-to-mobi-converter/

我们现在遇到的问题是:本地运行好好的,同时打开3个浏览器提交转码任务都没问题。但是一旦上到服务器,随便传两下就崩溃了。 我们猜测原因可能是下列,但是又不知道怎么确定: 1.因为服务器是1核的,本地机器是多核的,所以出问题 2.因为本地的IO操作速度非常快,但是在服务器上,因为有了上传和下载流程,导致程序出问题 3.node-cmd出问题,可能每次启动cmd命令都会影响程序

希望各位大神帮帮忙,看看我们的设计有什么问题,可能的原因是什么,怎么解决。 不胜感激啊!

PS:补充一下在线上的错误信息。每次运行时,第一次转码都能成功,第二次再转,就会出现如下的报错 TIM截图20170422141341.png

26 回复

这个我朋友也遇到过, 第一种情况:阿里自带的硬盘读写很差,而且不是一般的差,你要不买个高速云盘或者一个SSD,可能问题就解决了 第二种:CPU暴涨到100%,内存吃满,很多情况下node意外多开。(我觉得你可能是这里的问题,因为你本地请求量不是很大) (就是有东西一直保持你的node运行)比如: mysql使用了连接池(而这个连接池是不会断开的,一直保持连接), 而你请求过来,又运行了一个node,而这个node有开了连接池,所以这个node执行到底不会关闭,所以node的进程越来越多 会一直执行它的事件循环,慢慢的node就无限多了,而没有释放。你可以尝试一下process.exit()在程序执行完成的时候,如果问题解决了,你就看一下是不是有什么东西让他不断运行

前提是你这个必须是类似crontab的脚本,而不是网站服务,如果是网站服务,你这样用,页面就直接跪了

@zy445566 多谢,我下午试试你说的。不过我们这个服务器没有跑其他东西,就只有这一个程序,process.exit()确实值得一试,多谢啦

看报错貌似是 输出日志 时 发生写入错误

@mabu233 是吗?我发现js输出的错误经常标错地方,所以对debug意义不大。我试试去掉log输出试试

问题解决了吗?建议还是不要用阿里云,磁盘速度巨慢无比,如果喜欢用BAT的话百度云IO要好的多,另外可以试试换Linux吧,我刚才试了下不装图形界面,在linux下面可以直接装calibre,ebook-convert这个命令可用。用windows做服务器还要跑这种命令行应用,总觉得有点不靠谱

突然发现你们这个阅读器我好像以前用过,呵呵 还有个可能性就是找找有没有fs.open(‘xxx.xx’, ‘w’)这类的语句,以独占方式打开了文件以后没用fs.close关闭。这种问题有可能导致重复写入文件时的错误

另外还有个想法是觉得node-cmd这种封装了的东西不知道怎么写的不一定靠谱,不如自己用childprocess.spawn来写,可以得到stdout和stderr 两个流、这样的话可以用一个on(‘end’)一类的事件直接判断cli是否执行完了,比那种非常hacky的去一秒查一下进程靠谱的多。还有推荐一个模块,why-is-node-runing,可查看为什么有些时候代码应该结束的时候还没结束。当然前提是最好还是要用linux,稳定性肯定要比windows好

实在不行就用vscode的debug去跑下这个服务器,在出错的时候从调用栈里逐一往上排查看哪里出错了。这个方法是我解决各种坑的最终手段,一步一步断点一步一步排查,找到问题点只是时间问题,如果实在搞不定可以帮忙解决,专业趟坑很多年,也可以接开发项目

@andyhu 多谢你的回答啊,信息量很大,很有帮助。我下周好好研究研究。我们确实也准备换Linux主机了。我先研究研究,还搞不定就找你帮忙哈,多谢多谢^_^~

@andyhu 关于使用Linux这个问题,我还想多问两句。我们平时开发都是在Windows下完成,现在主要用的是LeanCloud的云引擎(底层是Linux),我们其实是没有办法进入云引擎更底层进行操作的,只能提交代码,然后部署。在Windows上我发现只要找到那个ebook-convert.exe文件,复制到项目里就可以用了。不知道Linux有没有这种用法?就是说,不装Calibre,只是拿到某一个文件,然后用命令行调用那个文件。

@hz0324 Linux下一般不能直接拷贝的,有一些其他动态链接库,软件本身的插件一类的。您可能需要的是 docker,用 docker 来部署,就不用考虑安装问题了,各个平台也能统一。不过windows下要用虚拟机,mac和linux都可以直接在系统下跑。不过我后来仔细看了下,您这次发的这个错误,的确好像是输出log的时候发生的错误。log找不到stdio了,换掉那个node-cmd直接用childprocess应该可以搞定

@andyhu 非常感谢啊。我们确实有用docker的计划,部署和扩容也都比较容易。就是卡在开发机是windows这个事儿上了,看来只能安装个Linux来搞了。现在团队没钱,没法配Mac,悲催啊。

@hz0324 哈,可以配个黑苹果啊,一样用,用来开发性价比高很多 windows下的docker自动调用虚拟机,其实也一样用

@andyhu 我想问一下,如果使用docker的话,具体该怎么部署呢?目前配置了一个黑苹果,docker环境也都按照网上的教程安装好了,但是下一步却不知道该怎么做了,毕竟需要跟我们自己的服务配合起来。 按照网上的教程也只是搭建了一个nginx服务器,毕竟不是专业弄这个的,弄起来确实无从下手

@myadmin 苹果跑docker不太好用吧,我比较喜欢arch linux这种滚动更新的系统。不过最近我看到消息,windows server 2016版本已经支持不用虚拟机跑原生的docker了。还没具体测试过,不过应该没什么难的。先找篇文章学下基础,自己建立一个dockerfile,然后docker build下既可以了

@hz0324 现在windows 2016可以支持原生docker了。我也用windows开发,最近新买了6个KVM的VPS,自己折腾了一星期给搞了个Windows Server 2012 R2 和 基于 Arch linux 的 Antergos 双启动,性价比很高,4M多线带宽100g硬盘2核CPU,600多一年,还可以启动的时候远程选操作系统双启动或者多启动,磁盘IO读写能到600-700MB/s

我觉得有几个问题, 一、先说基础,楼主好像对linux不是很了解,做后端需要稍微熟悉下 二是直接用nodejs的child_process库即可,挺简单,不需要使用nodecmd,因为那个nodecmd你不知道底层, 三是可以用node的cluster模块管理多个node进程,可以实现并行转码 四是装个虚拟机本地在linux上试一下,或者docker

以上总结也是我也写过类似的任务调度转码项目总结出来的,也遇到过类似的坑,但那是两年前了。希望对楼主有帮助。

来自酷炫的 CNodeMD

服务器用windows都是天坑~

8成是内存泄露了。

或者简单用pm2管起来

@ringtail 如果是内存泄露,一般CPU不会出现持续暴涨,只有在争抢资源的时候才会出现这种情况 如果楼主真想解决,就必须把这段时间,机器的状况贴出来,包括CPU使用率,内存增长和占用情况

如果是CPU使用率高,就很有可能发生争抢资源时引起的死循环或者就是死循环导致 如果是使用内存不断增加而且,一直都没有减少则有可能是内存泄露 如果是并发症,则可以确定死循环,而且由于死循环导致无法CG

内存泄露可能导致OOM,然后系统IO会飙高,然后CPU飙高。

可以重点关注下内存和swap的部分。

多谢各位,我们现在决定找朋友用PHP写一套来解决了,毕竟主攻前端的现在写Node,遇到这种问题比较蒙逼啊

回到顶部