您可以看看MongoDB的兩階段提交方法,或者您可以完全忘記事務並通過服務總線方法分離您的進程。以亞馬遜爲例 - 他們將允許您提交您的訂單,但他們不會確認,直到他們能夠確保您的庫存物品,爲您的卡收取費用等等。這些都不會發生在單筆交易中 - 這是一個一系列可以單獨出現的步驟,並且可以在必要時應用補償步驟。
一個天真的總線實施將執行以下操作(請記住,這只是一個普通的建議供您工作,確切的實施將取決於您的併發的特殊需求等):
- 將訂單放置在隊列中。此時,您可以繼續讓您的客戶等待,或者您可以感謝他們的 訂單,並讓他們知道在處理完 之後他們將收到一封電子郵件。
- 「庫存員工」將獲取訂單並鎖定其需要預留的庫存項目 。這可以通過許多不同的方式完成。使用Mongo,您可以創建一個每個orderid具有一個文檔的集合。這個文件的ID應該是庫存項目ID和一個合理的TTL(例如30秒)。只要工作人員擁有鎖定,它就可以管理其鎖定項目的庫存水平。一旦其 進行了更改,它可以刪除「鎖定」文檔。
- 如果另一名工人走來想要同時其鎖定到管理同一項目 ,你可以把阻塞的工作進入休眠模式 X秒,然後重試,或者更好的,你可以把 要求放回消息總線稍後將被另一個 工作人員拾起。
- 一旦工作人員解決了所有的庫存物品,它便可以在服務總線上放置另一條消息,表明應該收取一張卡 或者處理應該收到通知到 拉出庫存,或者一封電子郵件可以是發送給誰做 順序,
聽起來很複雜的人等等等等,但一旦你有一個消息總線設置,其實際上比較簡單。 A list of Node Message Bus Implementations can be found here.
一些開發人員甚至會完全跳過正式的消息總線,並使用數據庫作爲消息傳遞引擎,它可以在簡單的實現中工作。 Google Mongo和Queues。
如果您不希望超過1個服務器,並且消息總線實現過於龐大,那麼節點可以爲您處理鎖定和消息傳遞。例如,如果您確實想要鎖定節點,則可以創建一個存儲庫存項目ID的數組。儘管坦率地說,我認爲消息總線是最好的選擇。無論如何,這裏有一些我過去用來處理Node簡單外部資源鎖定的代碼。
// attempt to take out a lock, if the lock exists, then place the callback into the array.
this.getLock = function(id, cb) {
if(locks[id]) {
locks[id].push(cb);
return false;
}
else {
locks[id] = [];
return true;
}
};
// call freelock when done
this.freeLock = function(that, id) {
async.forEach(locks[id], function(item, callback) {
item.apply(that,[id]);
callback();
}, function(err){
if(err) {
// do something on error
}
locks[id] = null;
});
};
你有看了看MongoDB中,提出了兩個階段提交的方式描述這裏(http://cookbook.mongodb.org/patterns/perform-two-phase-commits/)? – JohnnyHK