加载中...

第三次迭代


第二次迭代之后,服务器本身的功能和性能已经得到了初步满足。接下来我们需要从稳定性的角度重新审视一下代码,看看还需要做些什么。

设计

从工程角度上讲,没有绝对可靠的系统。即使第二次迭代的代码经过反复检查后能确保没有bug,也很难说是否会因为NodeJS本身,或者是操作系统本身,甚至是硬件本身导致我们的服务器程序在某一天挂掉。因此一般生产环境下的服务器程序都配有一个守护进程,在服务挂掉的时候立即重启服务。一般守护进程的代码会远比服务进程的代码简单,从概率上可以保证守护进程更难挂掉。如果再做得严谨一些,甚至守护进程自身可以在自己挂掉时重启自己,从而实现双保险。

因此在本次迭代时,我们先利用NodeJS的进程管理机制,将守护进程作为父进程,将服务器程序作为子进程,并让父进程监控子进程的运行状态,在其异常退出时重启子进程。

实现

根据以上设计,我们编写了守护进程需要的代码。

  1. var cp = require('child_process');
  2. var worker;
  3. function spawn(server, config) {
  4. worker = cp.spawn('node', [ server, config ]);
  5. worker.on('exit', function (code) {
  6. if (code !== 0) {
  7. spawn(server, config);
  8. }
  9. });
  10. }
  11. function main(argv) {
  12. spawn('server.js', argv[0]);
  13. process.on('SIGTERM', function () {
  14. worker.kill();
  15. process.exit(0);
  16. });
  17. }
  18. main(process.argv.slice(2));

此外,服务器代码本身的入口函数也要做以下调整。

  1. function main(argv) {
  2. var config = JSON.parse(fs.readFileSync(argv[0], 'utf-8')),
  3. root = config.root || '.',
  4. port = config.port || 80,
  5. server;
  6. server = http.createServer(function (request, response) {
  7. ...
  8. }).listen(port);
  9. process.on('SIGTERM', function () {
  10. server.close(function () {
  11. process.exit(0);
  12. });
  13. });
  14. }

我们可以把守护进程的代码保存为daemon.js,之后我们可以通过node daemon.js config.json启动服务,而守护进程会进一步启动和监控服务器进程。此外,为了能够正常终止服务,我们让守护进程在接收到SIGTERM信号时终止服务器进程。而在服务器进程这一端,同样在收到SIGTERM信号时先停掉HTTP服务再正常退出。至此,我们的服务器程序就靠谱很多了。


还没有评论.