大數據處理系列之(二)系統過載保護

前言:前段時間在網上看到騰訊後臺開發總監bison分享的一篇文章《淺談過載保護》,讀來受益不淺。html

恰好本身也在處理系統請求過載的問題,把本身的一些心得體會總結出來拿來與你們一塊兒探討。前端

      在bison的文章中談到:對於延時敏感的服務,當外部請求超過系統處理能力,若是系統沒有作相後端

應保護,可能致使歷史累計的超時請求達到必定的規模,像雪球同樣造成惡性循環,因爲系統處理的每一個多線程

請求都由於超時而無效,系統對外呈現的服務能力爲0,且這種狀況不能自動恢復。咱們的系統就是要盡分佈式

量避免這種狀況的出現,下面將詳細來分析一個現實中的案例。線程

一  有過載問題的系統htm

 

數據處理流程:blog

       1) 前端將請求發送給數據解析及轉發系統,隊列

       2)數據解析及轉發系統將封裝好的數據發送後臺數據請求,設置超時時間(假設300ms),線程同步等待處進程

理結果從後臺返回。

      3)在300ms內正確返回結果後,則將處理的結果返回給前端,若是在300ms內超時,則將數據發送到一次超

時處理系統(假設設置超時時間500ms),線程同步等待結果返回。

      4)在500ms內正確返回結果後,則將處理的結果返回給前端,若是再一次超時,返回一個默認的處理結果給前

端,後端對數據進行本地化,而後能夠將數據發送到離線處理系統進行二次處理。

       數據解析的機器爲多核,數據解析及轉發系統採用的是單進程多線程模型,在前一篇文章《海量數據處理系列

之Java線程池使用》詳細描述了多線程處理的實現,採起的是無界隊列線程池的實現,這樣從客戶端來的請求,會被

這樣處理:

      1)  若是線程池中有空閒線程,會將請求直接交給線程處理。

      2)  若是沒有空閒線程,就將請求保存到任務隊列。

假設開50個線程,每一個線程秒平均處理一個請求,那麼系統每秒能夠處理的最大請求數是50個。一旦前端數據請求超

過50個每秒,在任務隊列中將會堆積大量的請求,前臺不斷髮送過來,後來處理不過來,前端又設置了套接字超時,導

致隊列中的大量請求超時,直接使得後端線程從隊列中取出套接字解析的時候,套接字已經被前臺關閉了,引起I/O異常。

堆積的量一旦雪崩,將使前臺發送過來的請求所有I/O異常,後臺處理系統跟掛掉無異了。

二  相對完善的系統

 

在上面的系統中,對請求是來者不拒的狀態,具體來說就是將全部的請求都保存到任務隊列。請求堆積到必定程度,

隊列中的不少請求都超時,這是能夠採起清空請求隊列的方式,這個能夠經過採起必定的監控方式來實現。例如上圖

中的心跳監控模塊,它能夠經過這樣的方式來實現,就是模擬客戶端的請求,每隔必定時間發送一些請求過去,若是

有大部分都正常返回,說明後端處理系統正常;當出現大部分超時的時候,說明後臺系統已經掛掉了,這時候重啓數

據解析及轉發系統,清空系統中的任務請求隊列,這樣能夠暫時處理請求高峯期的狀況。

      可是這個方式也是治標不治本的,後臺最多隻能處理這麼多請求,重啓後照樣會致使大量堵塞致使系統又掛掉,

而後監控系統又重啓,這樣會使得不少的請求沒有獲得有效的處理,大大下降系統的處理能力。爲了保證後臺系統每

時每刻都最大限度的發揮本身的處理能力,當負載超過系統自身的處理能力時,拒絕該請求。拒絕後能夠將該請求本

地系列化,保存相關的數據發送到離線數據處理系統進行處理。

   在前一篇文章《海量數據處理系列之Java線程池使用》第四節中有界隊列線程池使用中有提到這種方式的具體實現。

以上面的系統爲例,有界線程池能夠這樣配置,corePoolSize爲30,maximumPoolSize爲50,有界隊列爲

ArrayBlockingQueue<Runnable>(100)。

這樣系統在處理請求的時候採用以下策略:

1) 當一個請求過來,線程池開啓一個線程來處理,直到30個線程都在處理請求。

2) 當線程池中沒有空閒線程了,就將請求添加到有界隊列當中,直到隊列滿爲止。

3) 當隊列滿之後,在開啓線程來處理新的請求,直到開啓的線程數達到maximumPoolSize。

4) 當開啓的線程數達到maximumPoolSize後,任務隊列又已經滿了後,此時再過來的請求將被拒絕,被拒絕的請求

在本地系列化,將保存的數據同步到離線數據系統進行處理。

        海量數據處理都是採用分佈式的,每臺機器的處理能力有限,能夠將請求分佈到不一樣的機器上去。若是每臺機器被

拒絕的請求數過多的時候,就要考慮添加處理的機器了。

相關文章
相關標籤/搜索