【问题标题】:Nodejs - How to prevent loss when node crashes?Nodejs - 节点崩溃时如何防止丢失?
【发布时间】:2017-01-26 14:29:36
【问题描述】:

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

用户可能会创建数以千计的唯一代理,但如果应用出错、崩溃或重新启动,这些数据就会丢失。

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) 中。有没有办法从其他来源获取路线?(redis?mongo?)

或者有没有办法持久化这个路由信息?

或者是否有任何节点管理工具(PM2、forever、supervisor 等)防止此类事情发生或从中恢复?

或者有更好的解决方案吗?任何建议表示赞赏。

【问题讨论】:

    标签: node.js express proxy express-vhost


    【解决方案1】:

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

    在架构上,您有几种方法可以做到这一点:

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

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

    数据库可能更具可扩展性,但每次更改时将整个状态写入磁盘可能更简单(不需要数据库,只需将您的状态写入磁盘(可能 JSON 最容易读写)。两者都可以工作精细到一定规模,之后数据库解决方案更有意义(根据每秒更改或要跟踪的代理总数进行扩展)。

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

    我认为你有这个倒退。对于大量代理来说,数据库可能更具可扩展性,尽管数千并不是一个特别大的数字。您可能可以使用上述任何一种技术来处理该大小。

    我知道这些新创建的路由存储在 app 变量中 (app._router)。有没有办法从另一个获取路线 来源?(redis?mongo?)

    如果这是我的应用程序,我会在每次添加、删除或修改新代理时自己将数据保存到永久存储中,并且不使用 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)));
        });
    }
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-05
        • 2013-03-20
        • 1970-01-01
        • 1970-01-01
        • 2016-06-29
        • 2014-05-31
        • 2021-04-19
        • 2011-11-25
        相关资源
        最近更新 更多