mongoose/mongodb DoS-ing 一個 nodeJS 實例
我們在 AWS VPC 中有一個 nodeJS 實例,它向另一個可用區中執行的 mongodb 實例發出請求。
節點實例經常受到特定請求的影響。該請求用於從 mongodb 實例中提取大量資訊。在第一次查詢之後,該條目被記憶體了一段時間。
昨天,它返回的數據量發生了一些事情。使用如下程式碼:
console.log('before retrieve'); Model.find({}).exec(function() { console.log('after retrieve'); });
如果會在“檢索之前”點擊 10 次,然後就停止,DoS-ing 本身。我刪除了一些它作為臨時修復提取的數據。
在 mongoDB 方面,我有時會看到:
SocketException handling request, closing client connection: 9001 socket exception [SEND_ERROR]
我怎樣才能避免這種情況發生?
您所描述的問題與 mongoose、mongodb 和 node 的關係要少得多,而更多地是通常被稱為“記憶體踩踏”或“狗堆”的問題的表現。
顧名思義,當一大堆東西試圖一次刷新記憶體時,就會發生記憶體踩踏事件。在您的情況下,這發生在記憶體過期或數據初始載入到記憶體中時。突然,大量請求進入並在您的數據庫上應用大量讀取負載,這 1) 導致記憶體刷新速度緩慢,以及 2) 導致更多請求堆積起來等待記憶體。這基本上會導致您看到的行為,事情只是崩潰
這個維基百科頁面相當清楚地描述了這個問題,以及如何使用單獨的程序或鎖來解決它。由於節點沒有鎖或執行緒,這可能不是解決方案。此外,雖然單獨的過程可以工作,但它要復雜得多。
我過去使用的一種技術是使用兩個過期記憶體鍵,一個鍵僅用於指示何時刷新記憶體,而另一個保存實際數據。
為了說明,假設我有一個對像
foo
要記憶體並且每小時過期。我可以創建另一個在密鑰foo_refresh
前 1 分鐘過期的foo
密鑰。當
foo_refresh
密鑰過期時,一個工作人員/請求會立即替換foo_refresh
密鑰並忽略記憶體,而是從數據庫中提取數據,完成後刷新foo
密鑰(同時重置過期時間)。使用這樣的機制,我們在刷新記憶體時獲得了一種“鎖定”,這意味著不會有超過一個工作人員進行昂貴的讀取。假設記憶體刷新時間少於 1 分鐘,則
foo
對象永不過期,相反,它通過鍵的過期來刷新foo_refresh
。希望這會有所幫助!