Dubbo超时机制导致的雪崩连接
?
Bug影響:Dubbo服務提供者出現無法獲取Dubbo服務處理線程異常,后端DB爆出拿不到數據庫連接池,導致前端響應時間異常飆高,系統處理能力下降,核心基礎服務無法提供正常服務。
?Bug發現過程:
?線 上,對于高并發的服務化接口應用,時常會出現Dubbo連接池爆滿情況,通常,我們理所應當的認為,這是客戶端并發連接過高所致,一方面調整連接池大小, 一方面考慮去增加服務接口的機器,當然也會考慮去優化服務接口的應用。很自然的,當我們在線上壓測一個營銷頁面(為大促服務,具備高并發)時,我們遇到了 這種情況。而通過不斷的深入研究,我發現了一個特別的情況。
場景描述:
?
壓力從Jmeter壓至前端web應用marketingfront,場景是批量獲取30個產品的信息。wsproductreadserver有一個批量接口,會循環從tair中獲取產品信息,若緩存不存在,則命中db。
壓測后有兩個現象:
1)Dubbo的服務端爆出大量連接拿不到的異常,還伴隨著無法獲取數據庫連接池的情況
2)Dubbo Consumer端有大量的Dubbo超時和重試的異常,且重試3次后,均失敗。
3)Dubbo Consumer端的最大并發時91個
Dubbo Provider端的最大并發卻是600個,而服務端配置的dubbo最大線程數即為600
這個時候,出于性能測試的警覺性,發現這兩個并發數極為不妥。
按照正常的請求模式,DubboConsumer和DubboProvider展示出來的并發應該是一致的。此處為何會出現服務端的并發數被放大6倍,甚至有可能不止6倍,因為服務端的dubbo連接數限制就是600。
此處開始發揮性能測試各種大膽猜想:
1)是否是因為服務端再dubboServerHandle處理請求時,開啟了多線程,而這塊兒的多線程會累計到Dubbo的連接上,dragoon采集的這個數據可以真實的反應目前應用活動的線程對系統的壓力情況;
2)壓測環境不純潔?我的小伙伴們在偷偷和我一起壓測?(這個被我生生排除了,性能測試基本環境還是要保持獨立性)
3)是否是因為超時所致?這里超時會重試3次,那么順其自然的想,并發有可能最多會被放大到3倍,3*91=273<<600….還是不止3倍?
有了猜想,就得小心求證!
首先通過和dubbo開發人員 【草谷】分析,Dubbo連接數爆滿的原因,猜想1被否決,Dubbo服務端連接池是計數DubboServerHandle個數的業務是否采用多線程無關。 通過在壓測時,Dump provider端的線程數,也證明了這個。?
那么,可能還是和超時有很大關系。 再觀察wsproductreadserver接口的處理時間分布情況:?
?從RT的分布來看。基本上78.5%的響應時間是超過1s的。那么這個接口方法的dubbo超時時間是500ms,此時dubbo的重試機制會帶來怎樣的雪崩效應呢?
如果按照上圖,雖然客戶端只有1個并發在做操作,但是由于服務端執行十分耗時,每個請求的執行RT遠遠超過了超時時間500ms,此時服務端的最大并發會有多少呢? 和服務端處理的響應時間有特比特別大的關系。服務端處理時間變長,但是如果超時,客戶端的阻塞時間卻只有可憐的500ms,超過500ms,新一輪壓力又將發起。 上圖可直接看到的并發是8個,如果服務端RT再長些,那么并發可能還會再大些! 這也是為什么從marketingfront consumer的dragoon監控來看,只有90個并發。但是到服務端,卻導致dubbo連接池爆掉的直接原因。 查看了wsproductreadserver的堆棧,600個dubboServerHandle大部分都在做數據庫的讀取和數據庫連接獲取以及tair的操作。 所以,為什么Dubbo服務端的連接池會爆掉?很有可能就是因為你的服務接口,在高并發下的大部分RT分布已經超過了你的Dubbo設置的超時時間!這將直接導致Dubbo的重試機制會不斷放大你的服務端請求并發。 所 以如果,你在線上曾經遇到過類似場景,您可以采取去除Dubbo的重試機器,并且合理的設置Dubbo的超時時間。目前國際站的服務中心,已經開始去除 Dubbo的重試機制。當然Dubbo的重試機制其實是非常好的QOS保證,它的路由機制,是會幫你把超時的請求路由到其他機器上,而不是本機嘗試,所以 dubbo的重試機器也能一定程度的保證服務的質量。但是請一定要綜合線上的訪問情況,給出綜合的評估。 ————等等等,別著急,我們似乎又忽略了一些細節,元芳,你怎么看?———————— 我們重新回顧剛才的業務流程架構,wsproductReadserver層有DB和tair兩級存儲。那么對于同樣接口為什么服務化的接口RT如此之差,按照前面提到的架構,包含tair緩存,怎么還會有數據庫連接獲取不到的情況? ?接續深入追蹤,將問題暴露和開發討論,他們拿出tair ?可以看到,客戶端提交批量查詢30個產品的產品信息。在服務端,有一個緩存模塊,緩存的key是產品的ID。當產品命中tair時,則直接返回,若不命中,那么回去db中取數,再放入緩存中。這里可以發現一個潛在的性能問題:
客 戶端提交30個產品的查詢請求,而服務端,則通過for循環和tair交互,所以這個接口在通常情況下的性能估計也得超過60-100ms。如果不是30 個產品,而是50或者100,那么這個接口的性能將會衰減的非常厲害!(這純屬性能測試的yy,當然這個暫時還不是我們本次關注的主要原因)
那么如此的架構,請求打在db上的可能性是比較小的, 由緩存命中率來保證。從線上真實的監控數據來看,tair的命中率在70%,應該說還不錯,為什么在我們的壓測場景,DB的壓力確是如此兇殘,甚至導致db的連接池無法獲取呢?
所以性能驗證場景就呼之欲出了:
場景:準備30個產品ID,保持不變,這樣最多只會第一次會去訪問DB,并將數據存入緩存,后面將會直接命中緩存,db就在后面喝喝茶好了!
但是從測試結果來看,有兩點可以觀察到: 1) tair是存在命中的,否則查詢db的總次數應該是30*66812 2) 查詢db的次數大概是調用次數的2倍。從數據比例可以明顯的看出,可能有2個產品一直沒命中緩存。 3) 但是這個數據也讓我們奇怪,如果緩存開始工作,為什么總是有一些產品未進入緩存? 于是開始檢查這30個產品到底有哪幾個沒有存入緩存。 通 過開發Debug預發布環境代碼,最終發現,這兩個產品竟然已經被用戶移到垃圾箱了。而通過和李浩和躍波溝通SellerCoponList的業務來 看,DA推送過來的產品是存在被用戶移除的可能性。因而,每次這兩個數據的查詢,由于數據庫查詢不到記錄,tair也沒有存儲相關記錄,導致這些查詢都將 經過數據庫。數據庫壓力原因也找到了。 ? ?但是問題還沒有結束,這似乎只像是冰山表面,我們希望能夠鳥瞰整個冰山! ?細細品味這個問題的最終性能表象,這是一種變向擊穿緩存的做法啊!也就是具備一定的通用性。如果接口始終傳入數據庫和緩存都不可能存在的數據,那么每次的訪問都就落到db上,導致緩存變相擊穿,這個現象很有意思! ? ?目前有一種解決方案,就是Null Object Pattern,將數據庫不存在的記錄也記錄到緩存中,但是value為NULL,使得緩存可以有效的攔截。由于數據的超時時間是10min,所以如果數據有所改動,也可以接受。 ? ? 我相信這只是一種方案,可能還會有其他方案,但是這種變向的緩存擊穿卻讓我很興奮。回過頭來,如果讓我自己去實現這樣的緩存機制,數據庫和緩存都不存在的 數據場景很容易被忽略,并且這個對于業務確實也不會有影響。在線上存在大量熱點數據情況下,這樣的機制,往往并不會暴露性能問題。巧合的是,特定的場景, 性能卻會出現很大的偏差,這考驗的既是性能測試工程師的功力,也考驗的是架構的功力!?Bug解決辦法:
其實這過程中不僅僅有一些方法論,也有一些是性能測試經驗的功底,更重要的是產出了一些通用性的性能問題解決方案,以及部分參數和技術方案的設計對系統架構的影響。?
1)對于核心的服務中心,去除dubbo超時重試機制,并重新評估設置超時時間。
?2)對于存在tair或者其他中間件緩存產品,對NULL數據進行緩存,防止出現緩存的變相擊穿問題
?
?GBA傳承:
?
?個人感受:
?1)性能調優和診斷是一個不斷挖掘的過程,不放過一個細節點,大膽猜想,小心求證
?2)敢于質疑開發的建議和解決方案,提出自己的思路,并求證
?3)勇于專研。性能調優就像追求自己心儀的女孩,有時努力了很久卻沒有任何結果,但是心動的感覺卻是一生僅有的。
轉載于:https://www.cnblogs.com/austinspark-jessylu/p/7793403.html
總結
以上是生活随笔為你收集整理的Dubbo超时机制导致的雪崩连接的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql myisampack_每天进
- 下一篇: 单片机矩阵键盘扫描程序c语言,51单片机