没错,她就是一段代码: 一个简单的资源服务器。
// 伪代码
// ...
http.createServer(function (request, response) {
let pathname = url.parse(request.url)['pathname'];
let requestUrl = path.join(fileDir, pathname);
fs.readFile(requestUrl, (err, data) => {
if (err) {
response.writeHead(404);
response.end(err.message);
} else {
response.writeHead(200, {
'Content-Type': 'text/html'
});
response.end(data);
}
});
}).listen(port);
大家也看到了,确实很简单的实现,但显然可以更好,下面就以这个思路开始吧!🤭
我想让她更快,性 能更好
像上面这样实现,典型的io操作,会先把文件的内容读取存于内存,等全部内容都存于内存时,才会响应输出。可以想象,当大量请求并发时,对于小文件还好,但文件较大时,内存开销就会很紧张。于是,这里改用stream - 流的形式来实现,这样的好处是可以做到读取文件的时候,就开始响应输出,也就能解决刚才的问题。响应的更快,内存的压力也下来了。伪代码如下:
// 伪代码
// ...
http.createServer(function (request, response) {
let pathname = url.parse(request.url)['pathname'];
let requestUrl = path.join(fileDir, pathname);
let reader = fs.createReadStream(requestUrl);
response.writeHead(200, {
'Content-Type': 'text/html'
});
reader.pipe(response, { end: false });
reader.on('end', function() {
response.end();
});
}).listen(port);
ab压测效果:ab -n 100 -c 50,请求文件40+M
前者 后者 可以看到效果还是很明显的,尽管并发才50,但后者性能也已经是前者的两倍多了。
我想让她情绪更稳定
前面性能已经得到了优化,看似可以了。但我们知道,bug总是改不完的😄,就像她每次来的时候突然发脾气,程序也会在不经意间挂掉。我们要做的就是让她更稳定。这里用到nodejs的进程管理(ps:强烈推荐大家看朴灵老师的《深入浅出Node.js》里玩转进程章节,写的很清晰,受益匪浅),简单说明下机制:主进程通过进程间通信来实现监控工作进程,监听端口,把请求句柄发送给工作进程,从而达到多个进程监听同个端口的效果。当发现工作进程异常时,也可选择kill该进程,并重新生成新的进程。下面具体是用cluster-集群来实现,能达到两个目的,一来可以更高效的利用cpu,而来当某个工作进程挂掉时,也能自动生成新的进程,这样就靠谱多了。伪代码如下:
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
cluster.fork();
});
} else {
http.createServer(function (request, response) {
let pathname = url.parse(request.url)['pathname'];
pathname = pathname === '/' ? 'small.txt' : pathname;
let requestUrl = path.join(fileDir, pathname);
let reader = fs.createReadStream(requestUrl);
response.writeHead(200, {
'Content-Type': 'text/html'
});
reader.pipe(response, { end: false });
reader.on('end', function() {
response.end();
});
}).listen(port);
console.log(`工作进程 ${process.pid} 已启动`);
}
可以看到,每次进程退出,都能重新启动新进程。这里有个细节就是要考虑平滑的启动新进程,不细讲。还有就是如果主进程挂了,工作进程也会失去管理,这里可以通过监听工作进程数量,日志等方式来保证其稳定性。
我想让她更好部署,要做就做全套
我们程序最后是要部署到服务器上的,就要有基本start,stop,restart功能,这里就直接用现在热门的pm2来处理了,当然也可以用shell通过监听工作进程的方式来实现。
本文到此已结束了,相信她应该比之前更好了。 希望大家有更多能让她更xxx的想法提出来,欢迎pr,欢迎纠错,共同进步。