原因併發
新系統重構中,收穫了一個重要的設計教訓。
性能
事情是這樣滴,以下圖所示:
大數據
有一個 Hbase 表 oe_item 存放訂單商品相關的交易信息,rowkey 設計爲 「訂單號_oldItemID」 ,是經過 storm 同步任務處理 old_item 表的binlog訂閱寫入該表的。oe_item 的量級很大。優化
在老的實現方式中,因爲應用在訪問這個表以前沒法取到訂單的oldItemID, 所以,須要拿到訂單號去 scan 這個表。顯然這個開銷是很大的。當須要訪問大量訂單的 oe_item 數據時,併發訪問這個表會致使超時,線程被hang住,進而影響系統總體穩定性。如有可能,應該幹掉 scan oe_item 這個威脅系統穩定性的耗時操做。
線程
系統重構後,經過詳情API接口,可以獲取到新訂單及newItemID, 可以獲取到老訂單及oldItemId。顯然,對於老訂單來講,能夠用{order_no}_{oldItemID}拼成 rowkey 來 batchGet oe_item 表; 然而,對於新訂單,因爲沒法獲取到oldItemID, 這使得要獲取新訂單 oe_item 表的信息,依然要 scan 這個表,而不能替換爲 batchGet, —— 衆所周知, batchGet 操做一般比 scan 操做的性能要更好,獲取大數據量時穩定性更優 , —— 所以,錯過了優化系統穩定性的一個關鍵環節。是否是很蛋疼 ?
設計
教訓orm
在沒有對總體設計足夠清晰以前,不要急於着手去解決一個問題。 倉促地解決一個問題,會致使解決不足,繼續受到該問題的困擾,以前的方案甚至會形成束縛。blog
敏捷設計並非不作充分的思考和設計,而是強調不要「過猶不及」; 完成當前須要的,併爲擴展預留空間。 這實際上須要更充分的設計考量。接口
好比作訂單導出配置化時,我是採用小步優化逼近的方式來實現配置能力的。這當然也能解決問題,可是當面對新問題時,時而有某個地方考慮不周到,須要再修改代碼和發佈。 這便是由於在總體設計上沒有思考的足夠清晰,沒有足夠的融會貫通, 以至於老是紕漏百出。同步
所以,解決問題,要從總體設計上儘可能考量得足夠清晰,而後再下手去作。
這裏說的是,當創建新模型時,不要去兼容老方案,不然永遠都無法擺脫歷史包袱。
好比作新退款信息獲取的時候,當時貪急求快(也考慮到退款金額不對致使訂單狀態不對,會誘導商家誤發貨), 就沿用老方案的存儲,將新退款的數據也存儲在老的退款 HBase 表裏, 結果新老退款都須要去 scan 這個表,性能開銷甚大,並且對穩定性有影響。
正確的作法應該是, 針對新模型,創建新方案的存儲,而後在應用中聚合兩種方案,分流,冷卻老方案的存儲和獲取,一段時間後,就會自動切換到新方案上,擺脫老方案的歷史包袱。
約定勝於配置。 良好的約定,可使得系統的交互和整合更加簡潔清晰, 而不須要考慮過多的狀況,致使複雜度上升。
好比導出擴展字段時,約定擴展字段在下單表裏的存儲形式,而後導出按照這種約定去獲取相應數據。 除非下單存儲有誤,不然導出是不會有問題的,省了不少事。
在設計存儲的時候,就要想到如何去使用。
Think Deeper, Design Better.