一線網際網路架構師帶你領略滬江訂單系統分表項目實踐!

背景

隨著滬江產品線的不斷豐富,背後由交易產生的數據也已每年數倍的速度在增長。當前整個交易系統已經完成領域拆分,包括訂單域,商品域,營銷域,清結算域等,其中訂單域的數據增長量最為突出,它提供的服務有創建訂單,改單,查單,配送,售後等。根據當前增長率及對未來預估,數據庫單表存儲容量將會在半年內超過合理閥值。單表容量過大對於插入和查詢操作都會消耗大量數據庫資源(CPU,IO等),進而對訂單域各種服務產生影響。為了避免因單表容量過大帶來的整個交易服務的系統性風險,我們提出訂單分表項目。本文就是介紹訂單系統分表項目的實踐過程。

現狀分析

主要從以下幾個維度描述訂單系統現狀:

系統分類

  • 訂單內部系統:下單系統,改單系統,配送系統,前臺查詢系統,運營查詢系統,售後系統共6個子系統。這些系統主要通過訪問數據庫操作訂單數據。
  • 外圍系統:前臺結算頁,清結算系統,BI 分析系統,CRM 系統,業務運營系統。除了分析系統是通過定時導出訂單數據到數據中心,其它系統是通過訂單服務操作訂單數據。

數據分類

根據訂單的生成和修改頻次,我們把訂單數據分為兩類:

  • 熱數據,下單成功後在2個月內修改的頻次較高,例如:支付狀態,配送狀態,配送地址等。
  • 冷數據,交易完成後的訂單,主要在售後系統,查詢系統中使用。

系統與數據關係

外圍系統主要通過訂單服務訪問訂單數據,根據訪問的數據類型對訂單子系統進行分類:

  • 熱數據訪問,包含下單系統,改單系統,配送系統訪問。
  • 冷數據訪問,包含查詢系統,售後系統。

併發量

這裡重點分析訪問熱數據的訂單子系統,根據歷史訪問量及對未來3年的預估(每年3倍),當前系統可承受的併發量在單表合理閥值內完全能夠滿足業務的高速發展。

方案選型

解決單表容量過大問題,有非常多的成熟方案。我們比較了以下幾種方案:

MySQL表分區技術

普通表是一個邏輯表的所有數據存在相同的文件。分區表同樣是一個獨立的邏輯表,但是底層由多個物理子表組成。分區類似粗粒度的索引,減少訪問的數據集。使用分區表要從以下幾個方面考慮:

  • 分區規則的選擇,MySQL 提供範圍,列表,HASH 等方式。不同的規則會影響數據的查詢效率。
  • 分區的維護,對於增加和刪除分區比較容易,但是對於重組分區或 ALTER 語句複雜一些:需要先創建臨時分區,然後複製數據,最後刪除分區。這期間需要停止應用服務。
  • 可優化性弱,所有的優化都只能在數據庫層面進行,可控性不高。

訂單系統存在多維度的查詢需求,例如用戶,訂單號,商品,商品類型,機構,來源,平臺,時間,狀態,金額等,因此分區表對訂單查詢服務不會帶來明顯的提升。

水平分表

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

數據的寫入和查詢分散到多個表,好處非常明顯:

  • 高併發性能強,無集中寫入瓶頸。
  • 可控性強。

同時對現有系統影響範圍大:

  • 訂單號需要全局分發,當前訂單號的生成規則已不滿足分佈式需求。
  • 訂單服務所有子系統都要改造。
  • 需要停機發布。

冷熱數據分離

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

根據訂單冷熱數據特點以及與相關的訂單系統分組情況,可以把冷數據和熱數據單獨存儲。這種方案有以下優勢:

  • 影響範圍縮小,工作量減少,僅影響訂單查詢系統。
  • 冷數據庫數量可控。
  • 無停機要求。

同時有存在一些缺點:

  • 歷史庫單表容量過大。
  • 高併發情況下,存在單點瓶頸。
  • 活動庫數據不可控。

冷熱數據分離+冷數據水平分表

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

通過方案2+方案3,它既能解決單表容量過大問題又能滿足當前業務的發展。首先數據分離降低活動庫的單表數據容量,依據當前的系統併發量活動庫單表容量能夠保持在合理的範圍內。同時冷數據所在庫進行水平分表操作,能夠保證單表容量在可控範圍。

查詢

水平分表後,非分片規則的查詢變的複雜。避免遍歷所有子表的方式就是存儲全局的分片鍵與查詢條件的關係。全局的映射關係可以通過以下方式實現:

  • 增加全局表,但是又引入單表過大問題。
  • 搜索引擎,查詢效率高,水平可擴展。 公司基礎架構組已提供穩定高效的搜索服務(Elasticsearch),可直接對接解決查詢問題。

數據存儲架構

確定使用方案4後再次覆盤所有業務需求,對於少數直接依賴訂單庫的系統,決定暫時提供一個全量的數據倉庫供業務方使用,訂單內部服務均不使用此數據倉庫。最終訂單數據存儲分為以下4個部分:

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

  • 活動庫存儲實時產生的數據。
  • 歷史庫存儲2個月前的數據。
  • 全量倉庫存儲所有數據。
  • ES存儲歷史庫中訂單索引數據。

當前應用服務與數據存儲的架構如下圖所示:

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

經過這次改造後變為下圖所示結構:

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

方案執行

執行過程中,主要精力放在下面幾個方面:

冷數據遷移及水平切分

數據遷移主要通過定時任務把冷數據搬到歷史庫,主要遵循以下規則:

  • 根據冷數據的定義按順序遷移。例如2個月前的訂單屬於冷數據,則根據創建訂單時間排序,創建訂單時間小的先遷移。
  • 遷移過程中出現異常則終止遷移併發出異常通知。
  • 遷移過程不負責創建冷數據的索引數據。
  • 遷移過程不負責刪除已遷移的訂單。 表水平切分常見方式有時間範圍,ID 範圍,HASH等方式,我們採用ID 範圍作為切分規則,基於以下幾點考慮:
  • 單表數據可控。
  • 冷數據沒有併發寫入壓力。
  • 易維護,新增子表時已切分數據無改動。

具體規則如下:

  • 訂單號範圍切分,例如1~10000在tb_order_0001表,10001~20000在tb_order_0002表。
  • 所有訂單子表必須與主表是同一個切分邏輯。例如訂單號123主表數據存儲在 tb_order_0001表,那麼訂單商品詳情數據必須在tb_order_detail_0001表。

創建冷數據索引

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

歷史庫的索引創建通過以下2種方式創建:

  • 搜索引擎全量拉取,在初始化階段和重建索引時使用。
  • 增量發送,通過定時創建索引任務拉取最新遷移的冷數據發送到搜索引擎指定的消息隊列。

發送消息成功但是訂單系統無法得知搜索引擎創建結果,因此部署定時巡檢任務檢查歷史庫訂單是否已成功創建索引。

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

由於在第1步冷數據遷移過程中規定必須按順序遷移訂單,因此成功創建索引的訂單號可以作為訂單遷移的分界點,具體業務邏輯如下:

  • 小於此訂單號的訂單已成功遷移並創建了索引。
  • 大於此訂單號的訂單未遷移或者未創建索引。

因此在定時巡檢任務檢查過程中,把已成功創建索引的最大訂單號存儲到訂單分界表和緩存中,便於其它訂單業務邏輯使用(例如查詢服務,定時刪除任務等)。

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

訂單全量庫同步

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

引用阿里開源項目 Otter 作為準實時同步工具,它基於 MySql binlog 實現,穩定性高,同時支持高可用部署。為了避免 DELETE 語句同步到目標庫,修改Otter 中部分源碼實現 DELETE 語句過濾。具體原理參考 Otter 官網介紹,我們採用的是單機房部署模式。同時部署定時巡檢任務,核查實時同步結果。

多數據源一致性

針對冷數據遷移過程中可能出現的丟訂單或者數據不一致問題,通過以下措施解決:

  • 遷移數據過程中出現異常時暫停遷移任務併發送報警消息。
  • 修改數據失敗發送報警消息。
  • 在活動庫中刪除已成功遷移的數據前與歷史庫中的數據比較是否一致。

針對全量倉庫的一致性保證,除了 Otter 本身基於 binlog 的一套保障機制外,我們增加定時巡檢任務檢查1個小時內全量倉庫與活動庫的數據是否一致。

訂單查詢

訂單查詢使用2個庫:活動庫和歷史庫。具體執行過程如下:

  1. 根據分片規則查詢即訂單號
一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!


  1. 根據非分片規則查詢 在上面的兩個流程中主要通過分界點訂單號保證查詢不會出現重複數據,具體規則如下:
一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!


  • 活動庫只查找:x>n 的訂單。
  • 歷史庫只查詢:x<=n 的訂單。

訂單查詢服務包含兩種分頁查詢方式:

  • 上一頁,下一頁查詢。
  • 頁碼分頁查詢。

多數據源分頁問題本質是多個有序集合的分頁問題。對於第1種查詢方式,每次查詢都會知道上一次的起始或者結束位置,因此只需在查詢條件中添加起始或者結束位置可以定位到哪幾個數據源。對於第2種查詢方式,需要通過遍歷數據源獲取數據總量,計算總頁碼數,並且記錄每個數據源滿足條件的數據總量,然後根據當前請求頁碼和每頁個數判斷數據落在哪幾個數據源。

實現過程中,我們遇到的問題是搜索服務存在深度分頁限制(最多返回1000條記錄),例如:每頁20條記錄,則只能翻到第50頁。而實際情況下後臺某些運營查詢業務超過這種限制。因此我們採取修改查詢條件的策略實現深度分頁,下面簡化描述深度分頁實現:假設搜索服務中有10條記錄,查詢接口通過offset 和 limit 實現分頁,具體如下圖

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

如果分頁沒有限制的情況下,每頁2條數據,則查詢第1,2,3頁數據語法如下: 第1頁,offset=0,limit=2,返回100,102 第2頁,offset=2,limit=2,返回110,200 第3頁,offset=4,limit=2,返回201,300 現在offset和limit添加如下限制:offset<=1,limit<=2,則實際分頁中這兩個變量都有可能超過限制,解決思路如下:

  • 先解決offset問題,如果offset>maxOffset,則通過修改查詢條件使offset=0,例如查詢第2頁數據(offset=2,limit=2),查詢條件中添加orderId>102,就可以把offset修改為0。
  • Offset滿足條件後,再處理limit問題。如果limit>maxLimit,則通過修改查詢條件循環查詢使每次查詢的limit<=maxLimit。 示例代碼如下:

如果 offset 大於限制數(offset>MAX_OFFSET),則需要找到前一個滿足條件的訂單號,從而修改查詢條件使 offset=0。代碼如下:

查找前一個訂單號的主要方法是 skip,找到訂單號後就可以修改 offset=0 解決offset 限制。下面列出 skip 方法部分代碼,如下所示。

主要利用搜索服務最大查詢個數跳躍查詢,減少查找次數。 解決 offset 的限制後,開始著手處理 limit 的限制。同樣通過修改前一個訂單號多次查詢獲取當前頁的所有數據。

上線發佈

為了保證平穩上線,整個項目分6個步驟,4次發佈,具體執行計劃如下:

第1批發布:

  • 冷熱數據分離訂單遷移任務。
  • Otter部署,全量庫同步。

第2批發布:

  • 增量冷數據遷移定時任務。
  • 接入搜索服務,創建訂單索引數據。

第3批發布:

  • 改造訂單後臺運營查詢服務。

第4批發布:

  • 改造訂單前臺查詢服務。
  • 啟動定時任務刪除熱庫的冷數據。

原文出處:https://mp.weixin.qq.com/s/TGJiwqd4wcQ4KWsbJLLvfA?utm_source=tuicool&utm_medium=referral

總結

通過這次項目,訂單單表容量得到有效控制,用戶端訂單查詢 QPS 提升2倍,運營端歷史訂單查詢提升4倍。當前方案也存在一些問題:全量倉庫容量問題,此全量倉庫主要目的是減少直接依賴交易庫的外圍系統的改動。接下來需要與外圍系統制定更合理的獲取訂單全量數據的方式,去除全量倉庫的依賴。

那如何學習才能快速入門並精通呢?

當真正開始學習的時候難免不知道從哪入手,導致效率低下影響繼續學習的信心。

但最重要的是不知道哪些技術需要重點掌握,學習時頻繁踩坑,最終浪費大量時間,所以有一套實用的視頻課程用來跟著學習是非常有必要的。

為了讓學習變得輕鬆、高效,今天給大家免費分享一套阿里架構師傳授的一套教學資源。幫助大家在成為架構師的道路上披荊斬棘。

這套視頻課程詳細講解了(Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構)等這些成為架構師必備的內容!

而且還把框架需要用到的各種程序進行了打包,根據基礎視頻可以讓你輕鬆搭建分佈式框架環境,像在企業生產環境一樣進行學習和實踐。

一線互聯網架構師帶你領略滬江訂單系統分表項目實踐!

後臺私信回覆 “ 架構 ” 就可以馬上免費獲得這套價值一萬八的內部教材!


分享到:


相關文章: