3 步排查,3 步優化,探針效能損耗直降 44%
應用接探針除了安全問題,最擔心的就是佔用系統性能影響業務正常運轉,今天分享一個實際案例告訴大家如何來降低探針的效能損耗。
下表為某使用者的2條核心鏈路在200併發壓測下的效能資料對比,可以看見在接入探針後效能損耗居高不下。
3步快速排查
1.對比鏈路差異
首先想到的排查方案是通過skywalking監控進行排查,對比應用在接入探針和未接入探針的情況下,效能表現的差異在哪,具體的的效能消耗在哪個中介軟體。
在對比skywalking監控的鏈路耗時,確實可以觀察到未接入探針比接入探針和鏈路的RT高,但是不清楚是否存在客戶環境問題或者skywallking上的鏈路有斷裂的問題,資訊並不全面無法準確定位。
2.外掛排除法
在無其它有效資訊時,嘗試通過排除法定位具體影響效能的外掛。具體做法是先整理鏈路用到的中介軟體,先移除所有中介軟體外掛,再逐一增加單箇中間件外掛,不斷的進行壓測,觀察哪個外掛對效能的影響比較大。依靠這個方法定位成功到dubbo與logback兩個外掛,它們對效能影響比較大。
3.效能資料收集
在壓測測試的同時,我們在agent框架內增加了對中介軟體外掛interceptor方法執行的耗時統計程式碼,這部分資料會統一輸出到固定的日誌檔案中。此外我們開發了與之配套的效能日誌分析程式,配合日誌收集指令碼,可以對整個鏈路的所有應用列印的效能資料進行分析,輸出彙總出一份中介軟體interceptor的統計結果,這份結果可以直觀的看到每個中介軟體的效能耗時佔比。
統計結果樣例:
效能收集程式碼展示:
3步具體優化
1.減少切點
agent產生效能損耗的終歸原因是因為agent增強中介軟體程式碼後,會修改目標類的位元組碼,植入一些額外的邏輯,正是這些額外的邏輯帶來了額外的耗時。切點越多植入的邏輯越多,整個鏈路的損耗就可能越高,所以儘可能的減少切點的數量一定會減少效能損耗。
按照這個思路,我們將前面排查出來耗時佔比較高的logback中介軟體進行了重新設計。原先logback的實現有三個切點,分別負責:影子appender的註冊、流量標識、日誌隔離,經過重新設計後,優化為一個切點實現所有功能。
2.靜默&業務流量過濾
儘管中介軟體外掛的增強邏輯不盡相同,但agent在植入到目標類的位元組碼都是統一的。他們都有統一入口,前置的執行邏輯都是同一套框架,實際執行時序圖如下:
實際上有很多Interceptor的增強邏輯只有壓測流量時才會執行,可這部分interceptor的執行全部需要經過前面從Messager到AdviceListener的一系列呼叫,這是完全沒有必要並且會帶來一定的效能損耗。這種無用呼叫可以在最前端做個判斷,從開始就過濾掉,在達到效果的同時降低效能損耗。
為此我們對框架進行了改造,讓類似這種interceptor能在最前端就把流量過濾掉,避免執行無意義的邏輯。同時在最前端增加了靜默開關,靜默開關可以一鍵禁用掉所有中介軟體增強邏輯的執行,一定程度上可以代替解除安裝操作。相比解除安裝來說它不會還原實際的位元組碼,也不會回收記憶體佔用,但是會更加輕量級,響應更快,影響更小。
改造後的執行時序圖:
3.中斷邏輯優化
對logback外掛進行重新設計後產生了一定效果,但是從效能採集的資料來看,效能損耗佔比最高的還是logback外掛。經過反覆斟酌發現logback本身已經沒有在進一步優化的空間了,於是將目光轉向了框架層面,最後將重點放在了優化CutoffInterceptor型別中斷機制。
CutoffInterceptor是一個類似擋板的Interceptor,它可以中斷原始碼本身的執行,並且支援對返回值替換。比如資料庫隔離的實現,我們一般會實現一個CutoffInterceptor,在壓測流量經過時返回影子資料庫的connection代替業務connection,以實現資料的隔離。logback同樣也是實現了一個CutoffInterceptor,在壓測流量經過時返回影子的appender替換業務的appender實現日誌隔離。
CutoffInterceptor內部的實現原理是通過異常機制實現的,在替換返回值時,實際上是丟擲了一個異常由上層捕獲,實現對原始碼的中斷。
眾所周知,在java中通過丟擲實現流程控制的效率其實是比較低的,我們內部測試驗證也證實了這點,一個空邏輯的CutoffInterceptor和同樣的一個空邏輯Interceptor的效能差距相差幾十近百倍。恰好logback這種日誌型別的中介軟體執行頻率是非常高的,所以導致這塊的效能損耗一直下不去。於是我們把CutoffInterceptor的中斷機制進行了優化,丟擲異常改為了先advice設定中斷標記,再由上層判斷去控制中斷。
最終結果
經過一系列的優化動作之後,兩條核心鏈路的效能損耗都有了大幅度的提升,鏈路A效能損耗由48%下降至4%,鏈路B的效能損耗由35%下降至3.4%。