Node.js 生产环境部署

3

现在是2013年,自2011年以来(有新的和过时的库),最常见的node.js部署问题已得到解答。

我想知道您认为部署node.js的最佳实践是什么。

如何自动重启node.js应用程序

使用Monit?

如何创建一个集群并平衡请求(支持websocket)

使用node-http-proxy,HAProxy?

由于hook.io已被删除,因此我不太喜欢使用node-http-proxy。

Node.js日志记录工具

等等...

现在的Node.js更加成熟了,您学到了什么,您有什么推荐?


为什么要踩?很多东西都改变了,例如 'cluster (https://github.com/learnboost/cluster)' 不再支持新的 node.js,hook.io 已经不存在了... - Ben
踩票是针对问题的,这个问题不适合在Stack Overflow上发布(有关更多信息,请参见FAQ)。我怀疑没有人会因为不同意node.js在过去2年中发生了变化而投反对票。 - Clive
那我应该在哪里问呢? - Ben
在这种特殊情况下,我和Ben一起面对NodeJs的同样问题,没有其他网站如此受欢迎以至于可以提出这个问题。我知道@Clive想要维持网站的水平,但请重新考虑开放这个问题。并非所有问题都是是/否问题。 - McSas
@McSas 不允许发散性问题是这里问答哲学的基础之一,毫无疑问,关于node.js的这个问题非常好、有趣、有潜在用处,但它不适合在这个网站上提出。 - Clive
显示剩余3条评论
1个回答

3

部署

我选择使用 substack 的 fleet 进行部署。

我在 SmartOS 上部署并运行 fleet 中心和无人机作为 服务,这些服务会自动重启。

我正在开发 dispatcher,它是 fleet 的前端。Dispatcher 可以让您将所有存储在中央位置(如 github 或 bitbucket)的存储库保持在一个地方,然后从中央 git 服务器部署最新代码。

负载均衡

有关设置 http 和 https 服务器,请参见此处的我的答案。在我的应用程序中,http 服务器实际上是另一个 node-http-proxy 服务器。在这种设置中,我的应用程序可以由许多小型服务组成,这些服务已在 seaport 中注册。

路由 http 服务器

var http = require('http')
var https = require('https')
var httpProxy = require('http-proxy');
var seaport = require('seaport');
var fs = require('fs')
var inspect = require('eyespect').inspector();
var express = require('express')
function router(data, cb) {
  var app = express()
  var config = data.config
  var logger = data.logger
  var appPort = config.get('application:port');
  var routerConfig = config.get('router')
  var seaHost = config.get('seaport:host')
  var seaPort = config.get('seaport:port')
  var ports = seaport.connect(seaPort, seaHost)
  var proxy = new httpProxy.RoutingProxy();
  app.use(express.methodOverride());
  app.use(app.router)
  var server = http.createServer(app)
  app.all('/api/:service/*', function (req, res) {
    var service = req.params.service
    var ps = ports.query(service);
    if (!ps || ps.length === 0) {
      ps = null
      unavailable(req, res, service, logger);
      service = null
      return
    }
    var item = ps[0]
    // remove /api/service/ from start of the url
    var newURL = req.url.replace(/^\/api\/.*?\//, '/')
    logger.debug('proxying to api service', {
      role: router,
      service: service,
      url: req.url,
      newURL: newURL
    })
    req.url = newURL
    proxy.proxyRequest(req, res, {
      host: item.host,
      port: item.port
    });
    item = null
  })

  var pong = 'PONG'
  app.get('/ping', function (req, res) {
    res.send(pong)
  })
  app.get('/services', function (req, res) {
    return showServices(req, res, ports)
  })
  app.all('/*', function (req, res) {
    var service = 'web'
    var ps = ports.query(service);
    if (!ps || ps.length === 0) {
      unavailable(req, res, service, logger);
      service = null
      ps = null
      return
    }

    proxy.proxyRequest(req, res, {
      host: ps[0].host,
      port: ps[0].port
    });
    ps = null
  })

  var serverPort = routerConfig.port
  server.listen(serverPort, function (err, reply) {
    if (err) { return cb(err); }
    logger.debug('router application online', {
      type: 'router',
      port: serverPort
    });
    var output = {
      port: serverPort,
      server: server
    }
    cb(null, output)
  });
}
function showServices(req, res, ports) {
  var ps = ports.query();
  var data = {
    message: 'Current services registered',
    services: ps
  }
  res.writeHead(200)
  return res.end(JSON.stringify(data))
}

function isServicesURL(url) {
  var pattern = /^\/services/i;
  return pattern.test(url)
}

function unavailable(req, res, service, logger ) {
  var resData = {
    error: 'service unavailable',
    message: 'no servers are available to serve your request',
    url: req.url,
    role: 'router'
    service: service
  };
  logger.debug('router service unavailable', {
    role: 'router',
    responseData: resData
  })
  res.writeHead(500);
  return res.end(JSON.stringify(resData));
}

module.exports = router;

spinUpRouter.js 是由 Fleet 实际生成的节点进程。

var inspect = require('eyespect').inspector()
var assert = require('assert')
var fs = require('fs')
var routerLib = require('./index.js');
var optimist = require('optimist');
var nconf = require('nconf')
var argv = optimist.demand(['config']).argv;
var configFilePath = argv.config
assert.ok(fs.existsSync(configFilePath), 'config file not found at path: ' + configFilePath);
var config = nconf.argv().env().file({file: configFilePath});
var logger = require('loggly-console-logger')
var routerData = {
  config: config,
  logger: logger
}
logger.debug('spinning up router', {
  type: 'router',
  configFilePath: configFilePath
})
routerLib(routerData, function (err, server) {
  inspect('router online')
})

日志记录

我使用 winston 来管理我的日志记录。更具体地说,我使用控制台和Loggly 传输。我用一个模块 loggly-console-logger 将它封装起来,使用得十分频繁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接