2016-09-19 53 views
1

我有一個快速應用程序,用戶可以在其中動態創建代理網站的子域。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._router)。有沒有辦法從其他來源獲得路線?(Redis的?蒙戈?)

還是有辦法保持此路由信息?

或者做任何的節點管理工具(PM2,永遠,監事等),防止針對或這種類型的東西恢復?

還是有更好的解決方案嗎?任何意見表示讚賞。

回答

0

顯然,你需要堅持其生存的服務器進程崩潰(這你似乎已經知道)的方式這些信息。像這樣保存信息的通常方式是將其保存到持久存儲區(通常是磁盤)。

建築上,你有這樣做的幾種方法:

  1. 保留目前的架構,但增加了「保存到磁盤」的步驟隨時代理的狀態改變(一個添加或刪除或改性)。因此,無論何時進行更改,您都可以將當前的所有路由狀態寫入磁盤。爲此,您需要添加一個新的基於RAM的數據結構,以保存您創建的所有路線的當前狀態。你可以嘗試從Express閱讀它,但坦率地說,我寧願維護我自己的數據結構,因爲它允許我確切地保留我想要的屬性。這將允許您在服務器啓動時讀取您保存的配置/狀態文件,並通過保存的狀態循環來重新創建您最後一次使用的狀態。如果每次進行更改時都保存此狀態,則最可能丟失的是即將被保存的操作。您必須確保在保存操作中具有適當的併發保護功能,因此兩次保存不會相互影響。這並不難。

  2. 切換到一個數據庫架構,因此每次做出改變的時候,你寫的一個變化到數據庫(使用持久存儲數據庫)。然後,在您的服務器重新啓動的任何時候,您都可以從數據庫中讀取狀態並重新創建服務器重新啓動之前的狀態。

數據庫可能更具可擴展性,但寫全州至在每次變盤可能更簡單(不需要數據庫,只寫你的狀態到硬盤上(很可能是JSON是最簡單的讀取和寫入)。這兩者都可以工作得很好,達到了一定的規模之後,數據庫解決方案,使得(在每代理的第二或總數有任何變化方面的規模來跟蹤)更有意義。

我知道我可以存儲這些在數據庫中,然後循環並且 重新創建每一個,但這似乎不是一個可靠的 固體解決方案usands獨特創建的代理。

我想你有這個倒退。數據庫對於大量的代理可能更具可擴展性,儘管數千個並不是特別多的代理。你可以用上述任何一種技術來處理這個尺寸。

我知道這些新創建的路線存儲在應用變量 (app._router)中。有沒有辦法從另一個 源獲取途徑?(Redis的?蒙戈?)

如果這是我的應用程序,我將自己每加入一個新的代理,除去還存留的數據永久存儲或修改並不使用Express來跟蹤任何事物。

還是有辦法堅持這個路由信息?

表達式沒有任何功能我知道自動持續路由。在快速架構中假定您的啓動代碼或後續代碼將創建它所需的路由處理程序。您可以在創建這些路線時自行保存這些信息。

或者做任何節點管理工具(PM2,永遠,監督等) 防止或恢復這種類型的東西?

不是我所知道的。這些工具有助於管理流程本身,但不管它的內部狀態。

或者還有更好的解決方案嗎?任何意見表示讚賞。

自己堅持數據,然後在服務器啓動時從持久存儲中重新創建狀態,如上述兩個選項中所述。


這裏是上面做出改變,然後在服務器啓動時,每次只是保存數據的第一個選項的一個例子,讀取保存的狀態:

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))); 
    }); 
} 
0

我想你只需要抓到未處理的錯誤/異常。你可能processuncaughtException這是你的應用程序不會退出,如果有任何錯誤發生

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