天天看點

一次job的耗時優化經曆

一、先聊聊需求

說起這次優化,有點奇葩,從耗時12小時到1分鐘,優化經曆了三次,和自己糾結了N次,看看結果還算安慰。

1.故事背景

恰逢大促東風,不如順勢來個商品破盤,營運、技術、産品聯手一搏提升商品的豐富度。那這次的問題就從這個需求開始了。。。

2.需求描述:快速提升商和品的數量,從現有的商品池中撈出符合規則的資料。

3.功能實作:功能很簡單,就是背景通過定時JOB的方式将疑似商品表的資料進行狀态更新。over~

二、再聊聊方案

1. 第一種方案(标簽:單線程執行、無緩存、有三方依賴)

(1)方案圖

  • 疑似商品總數:180w+
  • Page數(50條上限,後面會解釋原因):3w+
  • Thread池數:1
  • 是否有緩存:無
一次job的耗時優化經曆

(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小時的緩存
  • 并發政策:根據線程池數量動态配置設定數資料的起止頁,并發執行
一次job的耗時優化經曆

按照方案一的暴漏問題,逐一優化:

  • step1:增加線程和資料頁數的動态配置設定政策
    一次job的耗時優化經曆
  • step2:多個線程并發執行,并增加sleep降低通路依賴頻率
    一次job的耗時優化經曆
  • step3:增減讀取offerQueryService的tair存儲。

本次執行task處理offer數量180w+條,總耗時127分鐘,時間提升82%,期間無任何異常抛出,終于可以靜靜的吃瓜了。但又想了想,是不是還有更好的思路可以解決這個問題呢:

  • 能不能将時間控制在分鐘級别?
  • 能不能不依賴第三方接口?
  • 能不能不用緩存降低資料丢失或未被命中的機率?

本方案也暴露一些問題:

  • 始終在圍繞解決方案一暴漏問題在優化,思路沒有打開
  • 最大的瓶頸還是依賴第三方接口,必須降級去掉
  • tair已經做到常态化演練,申請空間又是MDB模式,資料丢失成為一種風險。

3.第三種方案(标簽:嵌套SQL、無三方依賴、批量優化)

  • Page分頁:不需要
  • Thread池數:不要要
  • 是否有緩存:不需要
一次job的耗時優化經曆

從頭開始了解需求,無非就是想把疑似商品找出來,然後回寫狀态。能不能找到替代調用三方接口的方案來驗證結果。腦暴一番,果然有。。。

  • step1:替換掉接口依賴,使用odps中的離線xxx表中的資料,然後同步到DB中。這不看起來比較麻煩,但一勞永逸,為後續的性能優化起到關鍵行作用,直接将時間降級至分鐘級。
  • step2:求交集,将DB表1和DB表2聯合查詢,結果即為已經完成更新的offer清單
  • step3:優化update方法為批量更新,至此over

本次執行task處理offer數量180w+條,總耗時<<1分鐘,時間提升100%,期間無任何異常抛出。

三、小結

回頭想想這次優化的經曆,總結有三點:

  • 來一個需求先不要着急碼代碼,分析好場景和資料基礎,然後選擇最優的技術方案。避免後續的返工
  • 思路方向很重要,往往很複雜的方案背後,換種思路會更爽
  • 事情搞完後和自己糾結下,往往會有新的發現