性能調優也是有跡可尋的,本文梳理了在實際開發過程中沉澱的通用性能優化策略,並且結合風控系統服務內使用場景,幫助讀者理解性能調優相關可行策略,從而建立性能優化 SOP 概念,以後出現問題即可參照優化流程改造即可。 ...
引言
性能調優也是有跡可尋的,本文梳理了在實際開發過程中沉澱的通用性能優化策略,並且結合風控系統服務內使用場景,幫助讀者理解性能調優相關可行策略,從而建立性能優化 SOP 概念,以後出現問題即可參照優化流程改造即可。
性能優化策略
時空轉換
刷過演算法題目的都知道評分條件有:時間複雜度、空間複雜度,兩樣消耗都很小的話,評分越高,即優秀的演算法。
但在實際開發過程中,一般二者不可兼得。要麼占用空間小運行時間長一點,要麼追求效率則占用空間就多一點。我們要做的就是在特定的需求場景中,極力優化其中的一方,此時往往需要犧牲另一方來達到目的。
空間換時間
在當前業務場景下,追求的是極致性能,即響應速度要足夠快,比如開屏頁的打開速度,如果每次打開 H5 都去服務端請求頁面的渲染數據,再加上用戶所在城市不同,從紐約用戶訪問北京,比北京本地用戶訪問肯定慢很多。那此時就有了 **CDN **這種工具。運營商的 CDN 節點遍佈全球,頁面在開發完畢後,直接推送到全球各地的 CDN 中緩存起來,這樣用戶訪問時只需要命中最近的 CDN 節點,速度自然而然就上去了,但是付出了空間的成本。
在風控場景內也有類似場景,決策引擎為了極致性能,也需要空間換取時間:
- 配置數據緩存:決策流數據關聯複雜,如果每次都去和 DB 或者數據中心交互,I/O 耗時大,得不償失。本地緩存一道 + 更新觸發反而是更好的選擇。
- 短期緩存:熱點信息且在一段時間內不會改變的(或者能容忍一段時間不變的),接入緩存會更利於查詢速度。
時間換空間
此策略反其道而行,用時間換取空間。此時,“空間比較寶貴”,比如記憶體相對於磁碟來說就很寶貴,但是存放在磁碟內再調度起來使用時,需要一定的時間來獲取。
在風控場景內,同樣存在很多場景:
- 節省空間成本:“雲上”伺服器相對“雲下”自建 IDC 機房是更貴的空間資源,所以風控將大量非實時的數據放在雲下伺服器計算,雲上服務需要用的時候,需要付出一定的調用時間即可:跨機房調用(專線帶寬爭搶占用)需要額外多消耗 5~10 ms
- 設備指紋採集數據壓縮上傳:風控依賴設備指紋,設備指紋是內嵌在應用 APP 內採集機器本身信息的 SDK,大量的設備信息如果不壓縮上傳會占用很多帶寬,影響占用了正常的用戶請求。壓縮後,節省了空間,但是付出的代價就是,每次都需要額外付出壓縮/解壓的耗時。
預處理/後處理
提前處理
預處理主要是為了提速。比如 CPU 和記憶體的預取操作,將記憶體中的指令和數據,提前存放到緩存中,從而加快執行的速度。
決策引擎為了保證策略的執行 RT 控制到 200ms 內,需要優化壓縮執行策略的時間,假設一個策略再怎麼優化,執行時間也是超過 200ms 的,那此時可以在上一個事件(場景)提前觸發預處理操作。
舉例:用戶發單時需要判定群組風險,但訪問群組是比較耗時,那可以在用戶進入發單前先觸發查詢群組信息並緩住,真正發單時直接讀取上次結果即可。同樣的,我們可以在用戶登錄時觸發一些操作,利於後續風控事件感知。
延後處理
不到必要時刻堅決不執行,節省成本。運用這一策略最有名的例子,就是 COW(Copy On Write,寫時複製)。假設多個線程都想操作一份數據,一般情況下,每個線程可以自己拷貝一份,放到自己的空間裡面。但是拷貝的操作很費時間。系統如果採用惰性處理,就會將拷貝的操作推遲。如果多個線程對這份數據只有讀的請求,那麼同一個數據資源是可以共用的,因為“讀”的操作不會改變這份數據。當某個線程需要修改這一數據時(寫操作),系統就將資源拷貝一份給該線程使用,允許改寫,這樣就不會影響別的線程。
延後操作在風控中主要為了節省成本,決策引擎為了極致的性能,很多變數(或者叫特征/指標)都是一次性並行載入的,但此時有的變數是第三方收費指標,比如 IP、同盾、蟻盾等,預載入的好處顯而易見,但是也極大的增加了成本:用戶有可能還未走到付費變數決策節點時就被拒或者白名單直接通過,此時這部分用戶提前請求三方就是極大的浪費。只有真正走到付費策略時,才會去請求,此時成本最小。
並行/非同步操作
並行
一個人乾不完的活,那就多找幾個人一起乾!並行操作,處理效率高(前提是機器多核心),時間大大縮短,極大縮短了 RT 時間。絕大多數互聯網伺服器,要麼使用多進程,要麼使用多線程來處理用戶的請求,以充分利用多核 CPU。另外一種情況就是在有 IO 阻塞的地方,也是非常適合使用多線程並行操作的,因為這種情況 CPU 基本上是空閑狀態,多線程可以讓 CPU 多乾點活。
決策引擎如果執行策略都是同步執行的話,幾分鐘可能都執行不完,運用並行,充分發揮 CPU 多個核心的性能,那麼此時性能瓶頸就是最長的那塊木板,只要專攻優化它就好了。
非同步
非同步相對同步來說,就是是否等待結果還是立即返回。同步操作在碰到內部有大量 I/O 操作時,性能損耗極大,此時採用非同步操作,系統的吞吐行會有極大的提升。但是有利有弊,非同步操作也增加了程式的複雜度,需要考慮失敗補償等額外的操作。
此類場景在風控系統中也是隨處可見:
- MQ 消息:天然的非同步處理,依托於消息消費機制削峰填谷特性,在大耗時操作動作,且業務不需要同步返回情況下,非常適合用消息來處理,比如離線決策。
- 埋點、監控採樣:不在業務關心的流程內發起的操作,為了不影響 RT,需要將額外的操作非同步處理。
緩存/批量合併
數據緩存
緩存的目的就是為了加速,這個我們從學習程式語言開始就基本達成的共識,基本上各個系統內只要有性能考慮的,多少都會用到緩存。我們常用的一些工具,也穿插了緩存的影子,比如:
- IOC 控制反轉:不僅僅是依賴註入,同時也節省了創建 bean 的時間
- 線程池中活躍線程:池化概念目的是增速,池本身就是一個緩存容器,頻繁的創建池內對象,得不償失,此時固定一批在池內,用完即還,極大的避免了創建新對象的開銷。
批量合併處理
批操作一般是遇到 I/O 操作時才會使用,一次性儘量多的查詢到多的數據,減少網路耗時時間(註意,這不是絕對,思考一下為何需要分頁,在時間和空間找平衡)。
常見批操作如下:
- 資料庫查詢批處理:在處理多條數據時一次性 in 查詢出來,避免頻繁的單條迴圈查詢
- redis 掃描數據:可以使用 scan 類命令,而不是頻繁的 get (註:會造成 redis hold 住,需要平衡 key 的個數)
總結
性能調優可以有多種手段,有時從不同的角度,能發揮奇效,當然前提是得在業務可接受的成本內,不考慮實際是不切實際的。
如上介紹的性能調優策略,這些是在日常開發過程中總結思考沉澱的,希望能夠幫助讀者建立一個性能優化 SOP,能有通用的摸排手段,做到用時心中有數。
往期精彩
歡迎關註公眾號:咕咕雞技術專欄
個人技術博客:https://jifuwei.github.io/
參考: