zuul禁用FormBodyWrapperFilter

工作原理

先介紹下zuul的工作原理,看圖zuul中定義了四種filter分別是

1.pre 在請求到達origin之前執行,在這一步可以做認證,選擇轉發地址,記錄日誌

2.Routing 建立http請求,可以使用httpClient或者netflix的ribbon

3.Post 返回請求,可以在這一步做統計收集,設置response的http heder,把請求返回個客戶端

4.Error當在以上三個步驟執行出錯時執行

 

 

問題

 

性能壓測時,tps只有400多,開啓併發10個線程和100線程結果一致

分析

watchman中無任何業務邏輯,沒有數據庫連接操作,沒有頻繁io操作 只有安全驗校驗類和限流類,直覺上感覺肯定有問題,代碼結構如下

使用jprofiler分析,首先查看CPU views下的call Tree,方法調用鏈路棧,

按調用時間算的百分比,最高的是WrappingRunable下面有10個百分比較高的http,這10個http就是本次壓測的接口。每個接口的佔用比都差不多,展開第一個9%的

同樣是route爲啥preroute耗時這麼久,肯定有問題

一個請求進入會依次被三種filter處理,第一種prefilter,第二種route,第三組postroute,初步定爲preroute有問題,結合代碼看,本次開發pre包中只有兩個prefilter一個是AppUrsTokenPreFilter,對app請求解籤驗籤,另一個prefilter做流量控制,仔細檢查了代碼發現沒有問題,spring源碼包中有5個prefilter類,查看代碼沒有問題,沒有找到問題換個方向

cpuload猜想

從cpu load看,一直很高,聯想到cpu與計算有關,然後AppUrsTokenPreFilter filter中有動態md5的計算,可能與這個類有關係,驗證把該類從容器中排除,繼續壓測,最終結果和之前一致,cpu並沒有降下去,猜想錯誤

堆GC分析

一切正常,繼續換方向

線程dump分析

通過觀察thread監控,發現50個線程併發時只有5個線程處於runnable狀態,其餘BLOCKED和waiting,加到線程數到200, runnable還是隻有個位數運行,194個BLOCKED,如圖。到這可以猜測代碼有大量鎖競爭

使用jstack dump線程日誌,全局搜索blocked 第12行 BLOCKED

其他先不管看到loadclass查看源碼,同步鎖。。。,問題已找到

接下來查看在哪裏調用的,FormBodyWrapperFilter 137行,看代碼,spring內置的一個prefilter 作用是針對form表單請求把參數進行轉換,使用的是MappingJackson2HttpMessageConverter,其中在構造函數中是這樣的

又調用了Jackson2ObjectMapperBuilder,繼續看代碼

繼續看代碼Jackson2ObjectMapperBuilder這個類

繼續看代碼,還是Jackson2ObjectMapperBuilder這個類裏的

快到源頭了,繼續 ,這次到classutils類了

forname方法太長 我只截了關鍵部分

這個就是源頭,loadclass使用的是同步鎖

解決問題方法禁用spring自帶的prefilter類zuulzuul.FormBodyWrapperFilter.pre.disable=true,改完之後重新部署壓測,瞬間上去了

 

還沒有結束

之前把自己寫的兩個prefilter代碼註釋,加上去之後重新壓測,tps瞬間只有一半(紅線是kill)

繼續線程dump查看。是的你沒看錯 log4j已經成爲了瓶頸 

看log4j源碼

從這邊可以看到在轉發loggingEvent到各個appender的時候,是同步的,即使你用asycAppender也沒有效果,解決方法使用logback,再壓測一把,平均4k+,可以接受

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章