日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

糟糕!HttpClient 连接池设置引发的一次雪崩!

發布時間:2025/3/21 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 糟糕!HttpClient 连接池设置引发的一次雪崩! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:zxcodestudy

來源:blog.csdn.net/qq_16681169/article/details/94592472

鳳巢團隊獨立搭建和運維的一個高流量的推廣實況系統,是通過HttpClient 調用大搜的實況服務。最近經常出現Address already in use (Bind failed)的問題。

很明顯是一個端口綁定沖突的問題,于是大概排查了一下當前系統的網絡連接情況和端口使用情況,發現是有大量time_wait的連接一直占用著端口沒釋放,導致端口被占滿(最高的時候6w+個),因此HttpClient建立連接的時候會出現申請端口沖突的情況。

具體情況如下:

于是為了解決time_wait的問題,網上搜索了些許資料加上自己的思考,于是認為可以通過連接池來保存tcp連接,減少HttpClient在并發情況下隨機打開的端口數量,復用原來有效的連接。但是新的問題也由連接池的設置引入了。

問題過程

在估算連接池最大連接數的時候,參考了業務高峰期時的請求量為1分鐘1.2w pv,接口平響為1.3s(復雜的廣告推廣效果模擬系統,在這種場景平響高是業務所需的原因),因此qps為12000*1.3\60=260

然后通過觀察了業務日志,每次連接建立耗時1.1s左右, 再留70%+的上浮空間(怕連接數設置小出系統故障),最大連接數估計為260*1.1*1.7約等于500

為了減少對之前業務代碼最小的改動,保證優化的快速上線驗證,仍然使用的是HttpClient3.1 的MultiThreadedHttpConnectionManager,設置核心代碼如下:

public?void?init()?{??connectionManager?=?new?MultiThreadedHttpConnectionManager();??HttpConnectionManagerParams?managerParams?=?new?HttpConnectionManagerParams();??managerParams.setMaxTotalConnections(500);?//?最大連接數??connectionManager.setParams(managerParams);??client?=?new?HttpClient(connectionManager);??}??

然后在線下手寫了多線程的測試用例,測試了下并發度確實能比沒用線程池的時候更高,然后先在我們的南京機房小流量上線驗證效果,效果也符合預期之后,就開始整個北京機房的轉全。結果轉全之后就出現了意料之外的系統異常。。。

案情回顧

在當天晚上流量轉全之后,一起情況符合預期,但是到了第二天早上就看到用戶群和相關的運維群里有一些人在反饋實況頁面打不開了。

這個時候我在路上,讓值班人幫忙先看了下大概的情況,定位到了耗時最高的部分正是通過連接池調用后端服務的部分,于是可以把這個突發問題的排查思路大致定在圍繞線程池的故障來考慮了。

于是等我到了公司,首先觀察了一下應用整體的情況:

  • 監控平臺的業務流量表現正常,但是部分機器的網卡流量略有突增

  • 接口的平響出現了明顯的上升

  • 業務日志無明顯的異常,不是底層服務超時的原因,因此平響的原因肯定不是業務本身

  • 發現30個機器實例竟然有9個出現了掛死的現象,其中6個北京實例,3個南京實例

  • 深入排查

    由于發現了有近 1/3的實例進程崩潰,而業務流量沒變,由于RPC服務對provider的流量進行負載均衡,所以引發單臺機器的流量升高,這樣會導致后面的存活實例更容易出現崩潰問題,于是高優看了進程掛死的原因。

    由于很可能是修改了HttpClient連接方式為連接池引發的問題,最容易引起變化的肯定是線程和CPU狀態,于是立即排查了線程數和CPU的狀態是否正常。

    CPU狀態

    如圖可見Java進程占用cpu非常高,是平時的近10倍。

    線程數監控狀態

    圖中可以看到多個機器大概在10點初時,出現了線程數大量飆升,甚至超出了虛擬化平臺對容器的2000線程數限制(平臺為了避免機器上的部分容器線程數過高,導致機器整體夯死而設置的熔斷保護),因此實例是被虛擬化平臺kill了。之前為什么之前在南京機房小流量上線的時候沒出現線程數超限的問題,應該和南京機房流量較少,只有北京機房流量的1/3有關。

    接下來就是分析線程數為啥會快速積累直至超限了。這個時候我就在考慮是否是連接池設置的最大連接數有問題,限制了系統連接線程的并發度。為了更好的排查問題,我回滾了線上一部分的實例,于是觀察了下線上實例的 tcp連接情況和回滾之后的連接情況。

    回滾之前tcp連接情況

    回滾之后tcp連接情況

    發現連接線程的并發度果然小很多了,這個時候要再確認一下是否是連接池設置導致的原因,于是將沒回滾的機器進行jstack了,對Java進程中分配的子線程進行了分析,總于可以確認問題。

    jstack狀態

    從jstack的日志中可以很容易分析出來,有大量的線程在等待獲取連接池里的連接而進行排隊,因此導致了線程堆積,因此平響上升。由于線程堆積越多,系統資源占用越厲害,接口平響也會因此升高,更加劇了線程的堆積,因此很容易出現惡性循環而導致線程數超限。

    那么為什么會出現并發度設置過小呢?之前已經留了70%的上浮空間來估算并發度,這里面必定有蹊蹺!

    于是我對源碼進行了解讀分析,發現了端倪:

    如MultiThreadedHttpConnectionManager源碼可見,連接池在分配連接時調用的doGetConnection方法時,對能否獲得連接,不僅會對我設置的參數maxTotalConnections進行是否超限校驗,還會對maxHostConnections進行是否超限的校驗。

    于是我立刻網上搜索了下maxHostConnections的含義:每個host路由的默認最大連接,需要通過setDefaultMaxConnectionsPerHost來設置,否則默認值是2。

    所以并不是我對業務的最大連接數計算失誤,而是因為不知道要設置DefaultMaxConnectionsPerHost而導致每個請求的Host并發連接數只有2,限制了線程獲取連接的并發度(所以難怪剛才觀察tcp并發度的時候發現只有2個連接建立 😃 )

    案情總結

    到此這次雪崩事件的根本問題已徹底定位,讓我們再次精煉的總結一下這個案件的全過程:

    • 連接池設置錯參數,導致最大連接數為2

    • 大量請求線程需要等待連接池釋放連接,出現排隊堆積

    • 夯住的線程變多,接口平響升高,占用了更多的系統資源,會加劇接口的耗時增加和線程堆積

    • 最后直至線程超限,實例被虛擬化平臺kill

    • 部分實例掛死,導致流量轉移到其他存活實例。其他實例流量壓力變大,容易引發雪崩。

    關于優化方案與如何避免此類問題再次發生,我想到的方案有3個:

    • 在做技術升級前,要仔細熟讀相關的官方技術文檔,最好不要遺漏任何細節

    • 可以在網上找其他可靠的開源項目,看看別人的優秀的項目是怎么使用的。比如github上就可以搜索技術關鍵字,找到同樣使用了這個技術的開源項目。要注意挑選質量高的項目進行參考

    • 先在線下壓測,用控制變量法對比各類設置的不同情況,這樣把所有問題在線下提前暴露了,再上線心里就有底了

    以下是我設計的一個壓測方案:

    • 測試不用連接池和使用連接池時,分析整體能承受的qps峰值和線程數變化

    • 對比setDefaultMaxConnectionsPerHost設置和不設置時,分析整體能承受的qps峰值和線程數變化

    • 對比調整setMaxTotalConnections,setDefaultMaxConnectionsPerHost 的閾值,分析整體能承受的qps峰值和線程數變化

    • 重點關注壓測時實例的線程數,cpu利用率,tcp連接數,端口使用情況,內存使用率

    綜上所述,一次連接池參數導致的雪崩問題已經從分析到定位已全部解決。在技術改造時我們應該要謹慎對待升級的技術點。在出現問題后,要重點分析問題的特征和規律,找到共性去揪出根本原因。

    總結

    以上是生活随笔為你收集整理的糟糕!HttpClient 连接池设置引发的一次雪崩!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。