一、先聊聊需求
說起這次優化,有點奇葩,從耗時12小時到1分鐘,優化經曆了三次,和自己糾結了N次,看看結果還算安慰。
1.故事背景
恰逢大促東風,不如順勢來個商品破盤,營運、技術、産品聯手一搏提升商品的豐富度。那這次的問題就從這個需求開始了。。。
2.需求描述:快速提升商和品的數量,從現有的商品池中撈出符合規則的資料。
3.功能實作:功能很簡單,就是背景通過定時JOB的方式将疑似商品表的資料進行狀态更新。over~
二、再聊聊方案
1. 第一種方案(标簽:單線程執行、無緩存、有三方依賴)
(1)方案圖
- 疑似商品總數:180w+
- Page數(50條上限,後面會解釋原因):3w+
- Thread池數:1
- 是否有緩存:無
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL2YzMhdTN0EGZ4IzYjRjNwUWMjZjMwMWZjZWZ0kjYiZGOhNjNllTOi9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
(2)執行邏輯
類似的小任務也寫過不少,自以為輕車熟路,方案也很順手,順手就是一坨代碼:
step1:從ODPS表中将疑似商品資料同步到應用的DB表中,做好資料準備
step2:分頁擷取offer資料,每頁必須按照50條資料來執行邏輯。之是以定死這個頁數上線,是由于标第三方HSF的接口的限制,用過的童鞋都知道,性能上限每次最多傳入50條Id。先忍一忍,繼續實作功能。
step3:循環周遊每頁,通過第三方接口check是否打上标。然後把已打上标的商品放到一個list集合中。
step4:将list裡offer依次循環回寫狀态
至此coding結束,迫不及待的将任務Run起來。又看看表已淩晨1點多,算了,睡上一覺明天收割資料。早上醒來,蛋疼是事情發生了,才跑了100w的資料,并且一直在報逾時。異常顯示“HSF TimeOut:OfferQueryServiceException:xxxx”,很顯然批量接口不行了,必須優化。
(3)執行結果
本次執行task處理offer數量180w+條,總耗時739分鐘,雖然能順利跑完,但已吐血。簡單總結下~
本方案滿足了三無條件:
- 無緩存
- 無多線程
- 無延時政策。
本方案暴露的問題:
- 第三方的接口依賴成為性能瓶頸,多頻次的循環調用會造成應用的強依賴和性能瓶頸
- 本次處理的資料量還是比較大,單Thread方案肯定不合适,
- ODPS表同步DB每周才執行一次,資料的實時性比較弱,完全可以緩存調用offerQueryService的接口,提升性能
- hsf逾時嚴重,需要增加sleep降低調用頻次的時間間隔
2.第二種方案(标簽:多線程執行、有緩存、有三方依賴)
- 疑似offer總數:180w+
- Thread池數:6
- 是否有緩存:增加offer接口調用1小時的緩存
- 并發政策:根據線程池數量動态配置設定數資料的起止頁,并發執行
按照方案一的暴漏問題,逐一優化:
- step1:增加線程和資料頁數的動态配置設定政策
一次job的耗時優化經曆 - step2:多個線程并發執行,并增加sleep降低通路依賴頻率
一次job的耗時優化經曆 - step3:增減讀取offerQueryService的tair存儲。
本次執行task處理offer數量180w+條,總耗時127分鐘,時間提升82%,期間無任何異常抛出,終于可以靜靜的吃瓜了。但又想了想,是不是還有更好的思路可以解決這個問題呢:
- 能不能将時間控制在分鐘級别?
- 能不能不依賴第三方接口?
- 能不能不用緩存降低資料丢失或未被命中的機率?
本方案也暴露一些問題:
- 始終在圍繞解決方案一暴漏問題在優化,思路沒有打開
- 最大的瓶頸還是依賴第三方接口,必須降級去掉
- tair已經做到常态化演練,申請空間又是MDB模式,資料丢失成為一種風險。
3.第三種方案(标簽:嵌套SQL、無三方依賴、批量優化)
- Page分頁:不需要
- Thread池數:不要要
- 是否有緩存:不需要
從頭開始了解需求,無非就是想把疑似商品找出來,然後回寫狀态。能不能找到替代調用三方接口的方案來驗證結果。腦暴一番,果然有。。。
- step1:替換掉接口依賴,使用odps中的離線xxx表中的資料,然後同步到DB中。這不看起來比較麻煩,但一勞永逸,為後續的性能優化起到關鍵行作用,直接将時間降級至分鐘級。
- step2:求交集,将DB表1和DB表2聯合查詢,結果即為已經完成更新的offer清單
- step3:優化update方法為批量更新,至此over
本次執行task處理offer數量180w+條,總耗時<<1分鐘,時間提升100%,期間無任何異常抛出。
三、小結
回頭想想這次優化的經曆,總結有三點:
- 來一個需求先不要着急碼代碼,分析好場景和資料基礎,然後選擇最優的技術方案。避免後續的返工
- 思路方向很重要,往往很複雜的方案背後,換種思路會更爽
- 事情搞完後和自己糾結下,往往會有新的發現