Nodejs -如何防止节点崩溃时的损失



我有一个快速的应用程序,用户可以动态地创建代理站点的子域。

用户可以创建数千个唯一的代理,但如果应用程序出错&如果系统崩溃或重新启动,则此数据将丢失。

var app = require('express')();
var proxy = require('express-http-proxy');
var vhost = require('vhost');
app.get('/create', function(req, res){
    app.use(vhost('subdomain.mysite.com', proxy('http://example.com')));
    res.send('Created');
});
app.listen(8080);

我知道我可以将它们存储在数据库中,然后循环并重新创建每个代理,但这似乎不是一个可靠的解决方案,可能有数千个唯一创建的代理。

我知道这些新创建的路由存储在app变量(app._router)中。是否有办法从另一个来源获得路由?蒙戈?)

或者是否有一种方法来持久化这个路由信息?

或者任何节点管理工具(PM2, forever, supervisor等)是否可以防止或从这种类型的事情中恢复?

还是有更好的解决方案?任何建议都很感激。

显然,您需要以一种能够在服务器进程崩溃(您似乎已经知道了)时幸存的方式保存此信息。像这样持久化信息的通常方法是将其保存到一个持久化存储(通常是磁盘)。

从架构上讲,有两种方法可以做到:

  1. 保持当前的体系结构,但是在代理的状态发生变化时(添加、删除或修改一个)添加"保存到磁盘"步骤。因此,每当它发生变化时,您就会将路由的整个当前状态写入磁盘。要做到这一点,你需要添加一个新的基于ram的数据结构来保存你所创建的所有路由的当前状态。您可以尝试从Express中读取这些内容,但坦率地说,我宁愿为此维护自己的数据结构,因为它允许我保留我想要的属性。这将允许您在服务器启动时读取保存的配置/状态文件,并遍历保存的状态以重新创建上次的状态。如果每次进行更改时都保存此状态,那么丢失的最坏情况就是即将保存的操作。您必须确保在保存操作中有适当的并发保护,这样两个保存就不会相互冲突。这并不难。

  2. 切换到数据库体系结构,因此每次进行更改时,都将该更改写入数据库(使用持久存储的数据库)。然后,在服务器重启的任何时候,您都可以从数据库中读取状态,并重新创建服务器重启前的状态。

数据库可能更具可伸缩性,但每次更改时将整个状态写入磁盘可能更简单(不需要数据库,只需将状态写入磁盘(可能JSON将是最简单的读写)。在一定规模之后,数据库解决方案就更有意义了(根据每秒的更改或要跟踪的代理总数进行扩展)。

我知道我可以将这些存储在数据库中,然后循环和重新创建每一个,但这似乎不是一个可靠的解决方案可能有数千个唯一创建的代理。

我觉得你搞反了。对于大量代理来说,数据库可能更具可伸缩性,尽管数千不是一个特别大的数字。您可能可以使用上述任何一种技术来处理这个大小。

我知道这些新创建的路由存储在app变量中(app._router)。有办法从另一个地方得到路线吗源?(复述,?蒙戈?)

如果这是我的应用程序,我会在每次添加,删除或修改新代理时将数据持久化到一个永久存储中,而不使用Express来跟踪任何内容。

或者是否有一种方法来持久化这个路由信息?

据我所知,

Express没有任何自动持久化路由的功能。在express架构中,假设您的启动代码或后续代码将创建所需的路由处理程序。您可以在创建这些路由时自己持久化这些信息。

或者使用任何节点管理工具(PM2、forever、supervisor等)防止或从这类事情中恢复?

据我所知没有。这些工具帮助管理过程本身,而不是它的内部状态。

还是有更好的解决方案?如有任何建议,不胜感激。

自己持久化数据,然后在服务器启动时从持久化存储重新创建状态,如上述两个选项所述。


下面是上面第一个选项的示例,它只在每次进行更改时保存数据,然后在服务器启动时读取保存的状态:

const app = require('express')();
const proxy = require('express-http-proxy');
const vhost = require('vhost');
const Promise = require('bluebird');
const fs = Promise.promisify(require('fs'));
let proxyData = [];
readProxyData();
app.get('/create', function(req, res){
    app.use(vhost('subdomain.mysite.com', proxy('http://example.com')));
    // save proxy data
    proxyData.push({subDomain: 'subdomain.mysite.com', userDomain: 'http://example.com'})
    saveProxyData();
    res.send('Created');
});
app.listen(8080);
// call this anytime a new proxy has been added 
// (after the proxy info is added to the proxyData data structure)
function saveProxyData() {
     // use a promise to automatically sequence successive saves
     // makes a pending save wait for the current one to finish
     proxyData.promise = proxyData.promise.then(function() {
         return fs.writeFileAsync("proxyState.json", JSON.stringify(proxyData));
     }).catch(function(err) {
         // log save state error, but allow promise to continue so
         // subsequent saves will continue uninterrupted
         console.err(err);
         return;
     });
}
// only to be called upon server startup
function readProxyData() {
    try {
        proxyData = require("proxyState.json");
    } catch(err) {
        console.err("Error reading proxyState.json - continuing with no saved state: ", err);
    }
    // set initial promise state (used for chaining consecutive writes)
    proxyData.promise = Promise.resolve();
    // establish any previously existing proxies saved in the proxyData
    proxyData.forEach(function(item) {
        app.use(vhost(item.subDomain, proxy(item.userDomain)));
    });
}

我认为你只需要捕获未处理的错误/异常。你可以process uncaughtException这是你的应用程序不会退出,如果任何错误发生

process.on('uncaughtException', function (err) {
  console.log('Caught exception: ' + err);
});

一旦进程结束,其工作内存中的所有数据都将丢失。一种常见的解决方案是,一旦数据被服务器接收,就将其写入更持久的系统(数据库、文件系统等)。

我最近写了一个npm包cashola,试图使这个过程尽可能简单。

这是使用cashola的示例。

var cashola = require('cashola');
var app = require('express')();
var proxy = require('express-http-proxy');
var vhost = require('vhost');
var state = cashola.rememberArraySync('state');
for (const item of state) {
    app.use(vhost(item.domain, proxy(item.proxy)));
}
app.get('/create', function(req, res){
    const vhostDomain = 'subdomain.mysite.com';
    const proxyDomain = 'http://example.com';
    state.push({ domain: vhostDomain, proxy: proxyDomain });
    app.use(vhost(vhostDomain, proxy(proxyDomain)));
    res.send('Created');
});
app.listen(8080);

相关内容

  • 没有找到相关文章

最新更新