隨着惟品會業務的快速發展,訂單量的不斷增加,原有的訂單存儲架構已經不能知足公司的發展了,特別是在大促高峯期,原訂單庫已經成爲搶購瓶頸,已經嚴重製約公司的發展。數據庫
惟品會舊訂單庫包含幾十張訂單相關表,舊訂單庫是典型的一主多從架構;主庫容量已接近服務器物理空間上限,同時也已經達到MySQL的處理上限,很快將沒法再處理新增訂單。緩存
舊訂單庫面臨的問題有:服務器
一、超大容量問題架構
訂單相關表都已是超大表,最大表的數據量已是幾十億,數據庫處理能力已經到了極限;分佈式
單庫包含多個超大表,佔用的硬盤空間已經接近了服務器的硬盤極限,很快將無空間可用;性能
二、性能問題優化
單一服務器處理能力是有限的,單一訂單庫的TPS也有上限,無論如何優化,總會有達到上限,這限制了單位時間的訂單處理能力,這個問題在大促時更加明顯,若是不重構,訂單達到必定量之後,就沒法再繼續增加,嚴重影響到用戶體驗。設計
三、升級擴展問題中間件
單一主庫沒法靈活的進行升級和擴展,沒法知足公司快速發展要求;索引
全部的訂單數據都放在同一庫裏面,存在單點故障的風險;
綜上所述,容量、性能問題是急需解決的問題,擴展是爲了未來3~5年內可以很好的知足惟品會快速發展的須要,而不須要每隔幾個月花費人力物力去考慮擴容等問題。
解決方法思考
一、解決容量問題
咱們能夠考慮到最直接的方式是增長大容量硬盤,或者對IO有更高要求,還能夠考慮增長SSD硬盤來解決容量的問題。此方法沒法解決單表數據量問題。
能夠對數據表歷史數據進行歸檔,但也須要頻繁進行歸檔操做,並且不能解決性能問題。
二、解決性能問題
提升數據庫服務器的配置,這個能夠提高必定數量的QPS和TPS,但仍然不能解決單服務器鏈接數、IO讀寫存在上限的問題,此方法仍然存在單點故障的問題。
拆分方法探討
常見的數據庫拆分方式有三種:垂直拆分、水平拆分、垂直水平拆分。
一、垂直拆分
垂直拆庫是根據數據庫裏面的數據表的相關性進行拆分,好比:一個數據庫裏面既存在用戶數據,又存在訂單數據,那麼垂直拆分能夠把用戶數據放到用戶庫、把訂單數據放到訂單庫。以下圖:
垂直拆表是對數據表進行垂直拆分的一種方式,常見的是把一個多字段的大表按經常使用字段和很是用字段進行拆分,每一個表裏面的數據記錄數通常狀況下是相同的,只是字段不同,使用主鍵關聯,以下圖:
二、水平拆分
水平拆分是把單表按某個規則把數據分散到多個表的拆分方式,好比:把單表1億數據按某個規則拆分,分別存儲到10個相同結果的表,每一個表的數據是1千萬,拆分出來的表,能夠分別放至到不一樣數據庫中,即同時進行水平拆庫操做,以下圖:
水平拆分能夠下降單表數據量,讓每一個單表的數據量保持在必定範圍內,從而提高單表讀寫性能。但水平拆分後,同一業務數據分佈在不一樣的表或庫中,可能須要把單表事務改爲跨表事務,須要轉變數據統計方式等。
三、垂直水平拆分
垂直水平拆分,是綜合了垂直和水平拆分方式的一種混合方式,垂直拆分把不一樣類型的數據存儲到不一樣庫中,再結合水平拆分,使單表數據量保持在合理範圍內,提高總TPS,提高性能,以下圖:
垂直拆分策略
原訂單庫把全部訂單相關的數據(訂單銷售、訂單售後、訂單任務處理等數據)都放在同一數據庫中,不符合電商系統分層設計,對於訂單銷售數據,性能第一,須要可以在大促高峯承受每分鐘幾萬到幾十萬訂單的壓力;而售後數據,是在訂單生成之後,用於訂單物流、訂單客服等,性能壓力不明顯,只要保證數據的及時性便可;因此根據這種狀況,把原訂單庫進行垂直拆分,拆分紅訂單售後數據、訂單銷售數據、其餘數據等,以下圖:
水平拆分策略
垂直拆分從業務上把訂單下單數據與下單後處理數據分開,但對於訂單銷售數據,因爲數據量仍然巨大,最大的訂單銷售相關表達到幾十億的數據量,若是遇到大型促銷(如:店慶12八、41九、61八、雙十一等等),數據庫TPS達到上限,單銷售庫單訂單表仍然沒法知足需求,還須要進一步進行拆分,在這裏使用水平拆分策略。
訂單分表是首先考慮的,分表的目標是保證每一個數據表的數量保持在1000~5000萬左右,在這個量級下,數據表的大小與性能是最理想的。
若是幾十個分表都放到一個訂單庫裏面,運行於單組服務器上,則受限於單組服務器的處理能力,數據庫的TPS有限,因此須要考慮分庫,把分表放到分庫裏面,減輕單庫的壓力,增長總的訂單TPS。
一、用戶編號HASH切分
使用用戶編號哈希取模,根據數據量評估,把單庫拆分紅n個庫,n個庫分別存放到m組服務器中,以下圖:
每組服務器容納4個庫,若是未來單服務器達到性能、容量等瓶頸,能夠直接把數據庫水平擴展爲2倍服務器集羣,還能夠繼續擴展爲4倍服務器集羣。水平擴展能夠支撐公司在將來3~5年的快速訂單增加。
使用用戶編號進行 sharding,可使得建立訂單的處理更簡單,不須要進行跨庫的事務處理,提升下單的性能與成功率。
二、訂單號索引表
根據用戶編號進行哈希分庫分表,能夠知足建立訂單和經過用戶編號維度進行查詢操做的需求,可是根據統計,按訂單號進行查詢的佔比達到80%以上,因此須要解決經過訂單號進行訂單的CURD等操做,因此須要創建訂單號索引表。
訂單號索引表是用於用戶編號與訂單號的對應關係表,根據訂單號進行哈希取模,放到分庫裏面。根據訂單號進行查詢時,先查出訂單號對應的用戶編號,再根據用戶編號取模查詢去對應的庫查詢訂單數據。
訂單號與用戶編號的關係在建立訂單後是不會更改的,爲了進一步提升性能,引入緩存,把訂單號與用戶編號的關係存放到緩存裏面,減小查表操做,提高性能,索引不命中時再去查表,並把查詢結果更新到緩存中。
三、分佈式數據庫集羣
訂單水平分庫分表之後,經過用戶編號,訂單號的查詢能夠經過上面的方法快速定位到訂單數據,但對於其餘條件的查詢、統計操做,沒法簡單作到,因此引入分佈式數據庫中間件。
下圖是基本構架:
總結與思考
技術架構與業務場景息息相關,不能脫離實際的業務場景、歷史架構、團隊能力、數據體量等等去作架構重構,對於一家快速發展的電子商務公司,訂單系統是核心,訂單庫是核心的核心,訂單庫的重構就像汽車在高速公路上跑着的過程當中更換輪胎。
本文是對惟品會訂單庫重構——採用分庫分表策略對原訂單庫表進行拆分的粗略總結,在訂單庫重構過程當中遇到的問題遠遠超過這些,好比:歷史數據的遷移、各外圍系統的對接等,但這些在公司強大的技術團隊面前,最終都順利的解決,新舊訂單庫順利的切換,給公司快速的業務發展提供堅實的保障。