官术网_书友最值得收藏!

3.3 分表分庫實現思路

技術選型這一難題解決后,具體如何落實分表分庫方案呢?需要考慮5個要點。

1)使用什么字段作為分片主鍵?

2)分片的策略是什么?

3)業務代碼如何修改?

4)歷史數據如何遷移?

5)未來的擴容方案是什么?

具體如下。

3.3.1 使用什么字段作為分片主鍵

先來回顧一下業務場景中的數據庫示例,見表3-4。

表3-4 用戶和訂單數據量

把表3-4中的數據拆分成一個訂單表,表中主要數據結構見表3-5。

表3-5 訂單主要數據結構

表t_order使用user_ID作為分片主鍵,為什么呢?當時的思路如下。

在選擇分片主鍵之前,首先要了解系統中的一些常見業務需求。

1)用戶需要查詢所有訂單,訂單數據中肯定包含不同的user_ID、order_time。

2)后臺需要根據城市查詢當地的訂單。

3)后臺需要統計每個時間段的訂單趨勢。

根據這些常見業務需求,判斷一下優先級,用戶操作(也就是第一個需求)必須優先滿足。

此時如果使用user_ID作為訂單的分片主鍵,就能保證每次用戶查詢數據(第一個需求)時,在一個分庫的一個分表里即可獲取數據。

因此,在方案里,最終還是使用user_ID作為分片主鍵,這樣在分表分庫查詢時,首先會把user_ID作為參數傳過來。

Tips

選擇字段作為分片主鍵時,一般需要考慮3個要求:數據盡量均勻分布在不同的表或庫、跨庫查詢操作盡可能少、所選字段的值不會變(這點尤為重要)。

3.3.2 分片的策略是什么

決定使用user_ID作為訂單分片主鍵后,就要開始考慮使用何種分片策略了。

目前通用的分片策略分為根據范圍分片、根據Hash值分片、根據Hash值及范圍混合分片這3種。

1)根據范圍分片:比如user_ID是自增型數字,把user_ID按照每100萬份分為一個庫,每10萬份分為一個表的形式進行分片,見表3-6。

表3-6 范圍分片表結構

說明:這里只講分表,分庫就是把分表分組存放在一個庫即可。

2)根據Hash值分片:指的是根據user_ID的Hash值mod(取模)一個特定的數進行分片(為了方便后續擴展,一般是2n)。

3)根據Hash值及范圍混合分片:先按照范圍分片,再根據Hash值取模分片。比如,表名=order_#user_ID% 10#_#hash(user_ID)%8,即分成了10×8=80個表,如圖3-4所示。

以上3種分片策略到底應該選擇哪個?只需要考慮一點:假設之后數據量變大了,需要把表分得更細,此時保證遷移的數據盡量少即可。

因此,根據Hash值分片時,一般建議拆分成2n個表。比如分成8張表,數據遷移時把原來的每張表拆一半出來組成新表,這樣數據遷移量就小了。

當初的方案中,就是根據user_ID的Hash值按32取模,把數據分到32個數據庫中,每個數據庫再分成16張表。

簡單計算一下,假設每天訂單量為1000萬,則每個庫日增1000萬/16=31.25萬,每個表日增1000萬/32/16=1.95萬,3年后每個表的數據量就是2000萬左右,仍在可控范圍內。

? 圖3-4 Hash值和范圍混合分片結構

如果業務增長特別快,且運維還能承受,為避免以后出現擴容問題,建議庫分得越多越好。

3.3.3 業務代碼如何修改

分片策略確定后,就要考慮業務代碼如何修改了。因業務代碼修改與業務強關聯,所以該項目采用的方案不具備通用性,這里就沒有列出來。

但是,筆者在這里分享一些經驗。近年來,分表分庫操作更加容易,不過需要注意幾個要點。

1)如果使用微服務,對于特定表的分表分庫,其影響面只為該表所在的服務,而如果是一個單體架構的應用做分表分庫,那會很麻煩。因為單體架構里面會有很多的跨表關聯查詢,也就是說,很多地方會直接與訂單表一起進行Join查詢,這種情況下,要想將訂單數據拆分到多個庫、多個表中,修改的代碼就會非常多。

2)在互聯網架構中,基本不使用外鍵約束。

3)分庫分表以后,與訂單有關的一些讀操作都要考慮對應的數據是在哪個庫哪個表??梢缘脑挘M量避免跨庫或跨表查詢。

一般來說,除了業務代碼需要修改以外,歷史數據的遷移也是一個難點。

3.3.4 歷史數據如何遷移

歷史數據的遷移非常耗時,遷移幾天幾夜都很正常。而在互聯網行業中,別說幾天幾夜,就算停機幾分鐘,業務都可能無法接受,這就要求給出一個無縫遷移的解決方案。

講解查詢分離時提過一個方案,就是監控數據庫變更日志,將數據庫變更的事件變成消息,存到消息系統,然后有個消費者訂閱消息,再將變動的數據同步到查詢數據庫,如圖3-5所示。

? 圖3-5 監控數據庫日志更新查詢數據示意圖

歷史數據遷移就可以采用類似的方案,如圖3-6所示。

? 圖3-6 分表分庫數據遷移方案示意圖

此數據遷移方案的基本思路為:舊架構繼續運行,存量數據直接遷移,增量數據監聽binlog,然后通過canal通知遷移程序遷移數據,等到新的數據庫擁有全量數據且校驗通過后再逐步切換流量到新架構。

數據遷移解決方案的詳細步驟如下。

1)上線canal,通過canal觸發增量數據的遷移。

2)遷移數據腳本測試通過后,將老數據遷移到新的分表分庫中。

3)注意遷移增量數據與遷移老數據的時間差,確保全部數據都被遷移過去,無任何遺漏。

4)此時新的分表分庫中已經擁有全量數據了,可以運行數據驗證程序,確保所有數據都存放在新數據庫中。

到這里數據遷移就算完成了,之后就是新版本代碼上線,至于是灰度上線還是直接上線,需要根據實際情況決定,回滾方案也是一樣。

3.3.5 未來的擴容方案是什么

隨著業務的發展,如果原來的分片設計已經無法滿足日益增長的數據量的需求,就需要考慮擴容了。擴容方案主要依賴以下兩點。

1)分片策略是否可以讓新表數據的遷移源只有一個舊表,而不是多個舊表?這就是前面建議使用2n分表的原因——以后每次擴容都能擴為2倍,都是把原來一張表的數據拆分到兩張表中。

2)數據遷移。需要把舊分片的數據遷移到新的分片上,這個方案與上面提及的歷史數據遷移一樣,此處不再贅述。

主站蜘蛛池模板: 兰溪市| 红原县| 孙吴县| 松阳县| 桂阳县| 乌拉特中旗| 岑巩县| 玉门市| 曲水县| 关岭| 井陉县| 佛教| 山丹县| 张掖市| 门源| 曲松县| 韩城市| 汤原县| 宿松县| 高淳县| 汝阳县| 陇南市| 东海县| 兴宁市| 岳普湖县| 渑池县| 蒙山县| 北票市| 晋中市| 文成县| 彭山县| 通江县| 宁陕县| 花莲县| 高邑县| 南投市| 东乌珠穆沁旗| 阆中市| 南靖县| 澄城县| 无极县|