express-15 与生产相关的问题

执行环境

  • Express支持执行环境的概念,它是一种在生产、开发或测试模式中运行应用程序的方法。实际上你可以按自己的想法创建很多种不同的环境。

    • 要记住,开发、生产和测试是“标准”环境,Express、Connect以及第三方中间件可能会基于这些环境做出决定。
    • 换句话说,如果你有一个“临时”环境,则无法让它自动集成生产环境的属性。
  • 尽管可以调用app.set('env', 'production')指定执行环境,但不建议这样做;

    • 因为那意味着不管什么情况,你的应用程序都会一直运行在那个环境中。
    • 更糟的是,它可能在一个环境中开始运行,然后切换到另一个环境。
    • 用环境变量NODE_ENV指定执行环境更好
//通过调用`app.get('env')`让它报告一下它运行在哪种模式下:

http.createServer(app).listen(app.get('port'), function(){ 
  console.log( 'Express started in ' + app.get('env') +
                ' mode on http://localhost:' + app.get('port') +
                '; press Ctrl-C to terminate.' );
});

  • 如果现在启动服务器,将会看到它运行在开发模式下,因为如果你没有指定,开发模式就是默认模式。
//试着把它放在生产模式下:

$ export NODE_ENV=production
$ node meadowlark.js
  • 如果用的是Unix/BSD系统或Cygwin,这里有个方便的语法,仅为一次命令执行期间设定环境:
$ NODE_ENV=production node meadowlark.js
  • 如果在生产模式下启动Express,你可能会注意到有些组件不适合在生产模式下使用的警告信息。

环境特定配置

  • 只是改变执行环境起不到太大的作用,尽管Express在生产模式下会输出更多警告到控制台中(比如告诉你被废弃的模块将来会被移除)。
  • 在生产模式下,视图缓存会默认启用;
  • 执行环境大体是一个可以利用的工具,可以轻松地决定应用程序在不同的环境下应该做何表现。
  • 尽量缩小开发、测试和生产环境之间的差异, 也就是说应该保守地使用这个功能。
  • 有些差异是不可避免的,比如,如果你的程序是高度数据库驱动的,你可能不想在开发期间干扰生产数据库,并且这是环境特定配置的良好候选用途。
  • 另外一个影响不大的领域是更加详细的日志。你想在开发时记录的很多东西都没必要在生产环境中记录。

日志

  • 给程序添加一些日志。在开发环境中,会用Morgan npm install --save morgan ,它的输出是便于查看的彩色文本。
  • 在生产环境中,我们用express-logger npm install --save express-logger,它支持日志循环(每24小时复制一次,然后开始新的日志,防止日志文件无限制地增长)。
//给程序文件添加日志支持:

switch(app.get('env')){ 
  case 'development':
    // 紧凑的、彩色的开发日志
    app.use(require('morgan')('dev'));
    break;
  case 'production':
    // 模块'express-logger'支持按日志循环
    app.use(require('express-logger')({
        path: __dirname + '/log/requests.log'
    }));
    break;
}

如果想实际看看日志的循环功能,可以编辑node_modules/express-logger/logger.js,修改变量defaultInterval,比如从24小时改成10秒(记住,修改node_modules中的包只能是出于实验或学习目的)。

扩展网站

  • 扩展通常意味着向上扩展或向外扩展。
    • 向上扩展是指让服务器变得更强:更快的CPU,更好的架构,更多内核,更多内存,等等。
    • 向外扩展只是意味着更多的服务器。
  • 随着云计算的流行和虚拟化的普及,服务器和计算能力的相关性变得越来越小,并且对于网站的扩展需求而言,向外扩展是成本收益率更高的办法。
  • 在用Node开发网站时,应该总是考虑向外扩展的可能性。

在搭建一个设计好要向外扩展的网站时,最重要的是持久化。

  • 除非所有服务器都能访问到那个文件系统,否则不应该用本地文件系统做持久化。
  • 不过只读数据是个例外,比如日志和备份。
  • 比如,可以把表单提交的数据备份到本地普通文件中,以防数据库接连失效。一旦遇到数据库中断的情况,到每个服务器上收集文件虽然麻烦,但最起码不会造成破坏。

用应用集群扩展

  • Node本身支持应用集群,它是一种简单的、单服务器形式的向外扩展。

  • 使用应用集群,可以为系统上的每个内核(CPU)创建一个独立的服务器(有更多的服务器而不是内核数不会提高程序的性能)。

  • 应用集群好在两个地方:

    • 第一,它有助于实现给定服务器性能的最大化(硬件或虚拟机);
    • 第二,它是一种在并行条件下测试程序的低开销方式。
  • 给网站添加集群支持。尽管在主程序文件中做这些工作的做法十分普遍,但我们准备创建第二个程序文件,用之前一直在用的非集群程序文件在集群中运行程序。为此我们必须先对meadowlark.js做些轻微的调整:

function startServer() { 
  app.listen(process.env.PORT || 3000, function(){
    console.log( 'Express started in ' + app.get('env') +
        ' mode on http://localhost:' + app.get('port') +
        '; press Ctrl-C to terminate.' );
  }); 
};

if(require.main === module){
  // 应用程序直接运行;启动应用服务器
  startServer();
} else {
  // 应用程序作为一个模块通过"require"引入: 导出函数 
  // 创建服务器
  module.exports = startServer;
}

//这样修改之后,meadowlark.js既可以直接运行(node meadowlark.js),也可以通过require语句作为一个模块引入。
  • 然后我们会创建一个新脚本,meadowlark_cluster.js:
var cluster = require('cluster');

function startWorker() {
  var worker = cluster.fork();
  console.log('CLUSTER: Worker %d started', worker.id);
} 

if(cluster.isMaster){

  require('os').cpus().forEach(function(){ 
    startWorker();
  });

  // 记录所有断开的工作线程。如果工作线程断开了,它应该退出,
  // 因此我们可以等待exit事件然后繁衍  一个新工作线程来代替它
  cluster.on('disconnect', function(worker){
      console.log('CLUSTER: Worker %d disconnected from the cluster.',
                  worker.id);
  });
  // 当有工作线程死掉(退出)时,创建一个工作线程代替它
  cluster.on('exit', function(worker, code, signal){
    console.log('CLUSTER: Worker %d died with exit code %d (%s)',
          worker.id, code, signal);
    startWorker();
  });

} else {

        // 在这个工作线程上启动我们的应用服务器,参见meadowlark.js
        require('./meadowlark.js')();

}
  • 在这个JavaScript执行时,它或者在主线程的上下文中(当用node meadowlark_cluster.js直接运行它时),或者在工作线程的上下文中(在Node集群系统执行它时)。
  • 属性cluster.isMaster和cluster.isWorker决定了运行在哪个上下文中。
  • 在我们运行这个脚本时,它是在主线程模式下执行的,并且我们用cluster.fork为系统中的每个CPU启动了一个工作线程。
  • 我们还监听了工作线程的exit事件,重新繁衍死掉的工作线程。最后,我们在else从句中处理工作线程的情况。既然我们将meadowlark.js配置为模块使用,只需要引入并立即调用它(记住,我们将它作为一个函数输出并启动服务器)。
  • 如果你用的是虚拟机(比如Oracle的VirtualBox),则必须将VM配置为多个CPU。虚拟机一般默认只有一个CPU。

假定你在多核系统上,应该能看到一些工作线程启动了。如果你想看到不同工作线程处理不同请求的证据,在路由前添加下面这个中间件:

app.use(function(req,res,next){
  var cluster = require('cluster');
  if(cluster.isWorker) console.log('Worker %d received request',
      cluster.worker.id);
});
posted @ 2015-03-19 17:48  JinksPeng  阅读(343)  评论(0编辑  收藏  举报