天天看點

關于RPC事務過載保護

最近系統出現一個問題,少量Proxy出現故障,群組消息應用伺服器會出現記憶體資源不夠導緻的崩潰的情況。我們對每個worker做了過載的保護,并且對每個worker的記憶體使用做了限制。從抓下來的dump來看,記憶體中的sipc對象占用了過多記憶體導緻的崩潰。sipc請求對象在記憶體中的數量遠遠超過設定的數量,說明過載沒有起到作用。

現場描述:

群消息伺服器會通路多台Proxy給同的使用者下行消息。

壞了兩台proxy。

群組消息應用worker與zookeeper斷掉連接配接,沒有任何請求過來從proxy過來。記憶體占用設定的2.4G,每顆cpu在20%左右,正常地對程序抓dump抓不下來,得加-F參數。kill程序的操作,需要一段時間後,程序才會消失。

事故原因分析:

SipcHost在做過載保護的機制是這樣的:

Sipc請求進來的時候,計數器加1,Sipc應答的時候,計數器減1;

計數器如果到達門檻值,對于新請求,直接傳回server busy;

但是目前上線的很多應答無内容的應用為了快速響應用戶端的請求,都是直接發送應答之後再開始做業務邏輯,群消息就是個典型的例子,先給用戶端reponse,再做群消息的分發。

SipcHost的線程池使用的是 java.util.concurrent.Executors.newFixedThreadPool(int nThreads),而這個線程池使用的是無容量限制的LinkedBlockingQueue。

基于以上三點,群消息在做消息分發的時候由于proxy的問題RPC消息發不下去,進入RPC重試機制;由于群消息快速reponse了,是以群消息的Sipc計數器一直為一個比較小的值,群消息的請求一直會進入到SipcHost的Queue中,最終導緻記憶體被使用完畢,所有的線程被hang死。

經驗總結:

盡量不要使用計數器做過載保護,因為計數器由于應用多使用異步的原因,不能準确判斷事務是否完成,隻能根據應用的response來計數,不是很準确。建議使用有一定容量的queue的線程池,queue滿了直接報busy來做過載保護。

繼續閱讀