訂單導出應對大流量訂單導出時的設計問題

背景

2018年4月16日,訂單導出跪了。幾乎接近於崩潰,導出接口響應很是慢,以致於前端直接報錯。最後只能經過重啓服務器解決。html

過後排查發現: 當時有多個VIP商家在線上導出,有 X 個大流量導出,都在幾十萬的訂單量導出之間,導出只有m臺機器,當時訪問Hbase集羣大量超時,線程被hang住,最終無力支撐。雖然在預發驗證過 100w+ 萬訂單的導出,但是沒預料到多個稍小但也很大的導出同時「侵襲」導出服務器。 自此,開始了「應對VIP大流量導出」的設計優化旅程。

前端

總體設計

這裏須要說明下大流量訂單導出的總體設計,採用了「批量併發」的處理策略。服務器

  • 因爲導出訂單量可能很是大,「所有加載到內存,計算報表字段邏輯,再寫入文件」的方式很容易把內存撐爆,所以,採用了批次的概念。將所有要導出的訂單量,切分紅多個批次,每批次處理 Batch 條訂單,批量寫入指定文件; 批次之間是串行的;架構

  • 爲了保證總體性能,當發現要導出訂單數大於 Threshold 時,就會經過併發策略來導出。上面的每批次 Batch 條訂單,會被切分紅 num 個訂單,多個線程併發去獲取訂單詳情數據,而後聚合起來進行格式化計算,寫入文件。併發

  • 訂單導出拉取訂單詳情先經過訂單詳情批量API接口,而後要訪問多個Hbase表,其中有一個大量級表的一次scanByPrefix和一個稍小量級表的2次scanByPrefix,四個大量級表的屢次batchGet,以及一些稍小量級的batchGet。大量級表和小量級表的差異也就至多一個數量級的差異。性能

  • 合法者不拒。 只要是合法的導出請求,都會開啓線程去處理,沒有限制。

    大數據

求解之旅

限制與隔離

顯然,若是多個大流量訂單導出同時來到,假設一個 X 訂單的導出。那麼就須要 X/num 次詳情接口的併發調用, 4X/num 次大量級表的屢次batchGet,X/num次大量級表的 scanByPrefix 和 2X/num 次小量級表的 scanByPrefix, N*X/num次小量級表的batchGet。 假設有 10X 訂單量的同時導出,上述每一個數字乘以 10, 而後還要在比較短的時間內完成,可見,1000個線程也不夠用啊!優化

所以,大流量訂單的合法導出即便不拒絕,也不能當即響應。 這裏須要做出一些限制。 好比每次同時只能導出 Y 個VIP大流量導出。但這個策略也是很粗略的。 更優化的策略能夠是: 專門設置一個大流量訂單導出隊列, 檢測到大流量導出後先放到該隊列,在機器相對空閒的時候再進行處理。線程

最完全的方案是隔離大流量導出。系統穩定性,實質上是資源分配和使用的問題。保證系統穩定性,能夠從兩個方面來保證: 1. 保證合理的資源分配和利用;2. 隔離不穩定性源,保證總體不受影響。合理的資源利用,包括資源的限速、限流、線程池和鏈接池的優化; 隔離不穩定性源,便是將可能致使不穩定性的因素隔離在正常服務以外,即便部分出現不穩定,總體也不受影響。架構設計

之因此大流量導出會影響總體導出服務穩定性,正是由於不穩定性源混雜在正常服務中,未作有效隔離。 大流量導出與正常流量導出混雜在一塊兒,大流量導出會佔用大量線程,致使正常流量導出資源分配不夠,從而影響總體服務。 所以,有必要將大流量導出抽離出來,用專門的服務器來完成。這樣,正常流量導出始終是穩定的,而大流量導出即便有問題,也只會影響極少數導出,不會影響總體導出服務的穩定性。且能夠重試。

識別關鍵威脅

要真正提高系統穩定性,就要識別出關鍵威脅並解決它。對於訂單導出來講,有個大量級表的 scanByPrefix 容易超時,消耗大量服務器資源並帶來很大壓力。之因此用 scan, 這個是歷史設計問題。 當時導出總體架構設計從DB遷移到大數據中心來獲取數據,總體方案是可行的,但沒有意識到這個設計會給大流量導出以及多個大流量導出下的導出系統穩定性埋下隱患。如今看來,幹掉 scan ,儘量採用 batchGet 來獲取數據,而後在客戶端來聚合數據,是一個更好的策略。 遺憾的是,當時沒有作太多思考,等意識到這個設計問題時,有點爲時過晚。 參閱: 兩個設計教訓:前瞻性思考與根本性解決方案


Hbase表的訪問優化

當時故障的直接緣由是,scanByPrefix 大量超時,致使線程被hang住。跟數據組同窗討論後,認爲這個操做太耗Hbase集羣服務器資源。所以,作了三個優化:

  • Hbase超時設定。 Hbase默認的超時設定值比較大,致使線程長久被hang住沒法被釋放。 合理的超時設置,不必定能避免應用崩潰,但不仔細的超時設置,在應用出現問題徵兆時會放大問題;觸類旁通,對於應用中所用到的默認設置,都應該仔細斟酌下,量身定製。

  • 加 Hbase 主備切換, 若是主集羣訪問超時,自動切換到備集羣訪問,減小主集羣壓力。

  • scan 在服務端, filter by prefix 移到客戶端去過濾。 能夠很大程度上減小Hbase集羣的壓力。作過這個優化後,超時基本沒有了。不過也帶來了新的問題:導出客戶端壓力過大。這種作法致使導出應用在scan和filter大流量訂單時,CPU和內存都大幅攀升。由於導出須要獲取(可能遠)超出所需的數據,而後過濾出指定的訂單號列表的數據。這說明,有些優化會解決面臨的問題,可是會引入新的問題。儘管如此,解決超時仍然是向正確方向邁進了一步,保證Hbase集羣的總體穩定性高於單個導出服務器的穩定性。

  • 同一個表的屢次訪問進行合併。

減小沒必要要的訪問

另外一個方法是梳理和優化詳情流程,減小沒必要要的訪問。 新報表或老報表的導出不須要某些字段,就能夠不用訪問某些Hbase表,減小訪問Hbase表的IO流量;此外,只獲取須要的字段,也能夠減小服務間的傳輸消耗。若有可能,都應該指定要獲取的列集合,避免暴力性獲取全部字段的數據。

線程池獨立和監控

在故障發生後,發現導出任務提交和訂單詳情數據拉取共用一個導出任務提交線程池,這樣也是有隱患的。所以增長了兩個線程池: 批量調用詳情接口的線程池和併發獲取Hbase數據的線程池,並進行線程池的監控。

小結

一些初始設計在常見場景下並不存在問題,可是在大壓力場景下會給系統穩定性帶來隱患,這一點往後切要注意。 另外,作系統局部優化時,也要全局考慮,避免由於優化某個局部又引入了新的甚至威脅更大的問題。

相關文章
相關標籤/搜索