部署
我选择使用 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]
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 将它封装起来,使用得十分频繁。