分区取模分库分表策略:多表事务分库内闭环解决方案
簡介:?當表數據超過一定量級,就需要通過分表來解決單表的性能瓶頸問題;當數據庫負載超過一定水平線,就需要通過分庫來解決單庫的連接數、性能負載的瓶頸問題。本文將闡述在不同情況下,讓不同數量級表,在同一個業務ID的事務操作路由到同一分庫中的方案,省去解決垮庫事務的煩惱。
作者 | 雨莊
來源 | 阿里技術公眾號
一 前言
技術同學都知道,當表數據超過一定量級,我們就需要通過分表來解決單表的性能瓶頸問題;當數據庫負載超過一定水平線,我們就需要通過分庫來解決單庫的連接數、性能負載的瓶頸問題。
本文主要闡述在同時滿足以下業務場景:
- 分表分庫存儲
- 需要對分表數量不同的表進行同事務操作
- 這些表的分庫分表策略依賴的Sharding業務ID一致
等情況下,讓這些不同數量級表,在同一個業務ID的事務操作路由到同一分庫中的方案,省去解決垮庫事務的煩惱。
二 案例
1 背景
假設有2個數據庫實例,需要保存商家訂單明細和匯總2張表的數據,這2張表的 分庫分表策略都用shop_id取模策略,按單表數據500w的原則進行分表分庫:
(1)shop_order_detail 商家訂單明細表,日均數據6000w
(2)shop_order_stat 商家訂單統計表,日均數據2000w
配置完成后生成的庫表:
然后我們要做這么一件事情:在同一個事務中,新增用戶訂單明細成功后,更新用戶訂單統計數據:
2 問題
此時,我要處理一筆 user_id = 3 的訂單數據:
如圖,執行新增shop_order_detail表操作的時候,操作被路由到了DB0中;執行更新shop_order_stat表操作的時候,操作被路由到了DB1。這時候 這兩個操作跨庫了,無法在同一個事務中執行, 流程異常中斷。
如果用TDDL組件的話就會報這樣的錯:
### Cause: ERR-CODE: [TDDL-4603][ERR_ACCROSS_DB_TRANSACTION] Transaction accross db is not supported in current transaction policy三 解決方案
解決多表跨庫事務的方案有很多,本文闡述的是如下解決方案:
將shop_order_stat作為shop_order_detail的映射基礎表,調整shop_order_detail的分表策略,讓shop_order_detail和shop_order_stat的數據都路由到同一個庫中。但該方案的前提是目標表的表數量是映射基礎表表數量的N倍數。比如shop_order_stat的總表數量是4,shop_order_detail的總表數量是12,故shop_order_detail的總表數是shop_order_stat總表數的3倍。
shop_order_detail新分表分庫策略的推導思路如下:
1 調整分庫策略
首先,我們看shop_id在0~11范圍內,用shop_id % 4分庫分表策略shop_order_stat的sharding分布圖:
用shop_id % 12分庫分表策略shop_order_detail的sharding分布圖:
圖中看出,兩張表都是根據shop_id做sharding,但現有同一個shop_id有可能會被路由到不同的庫中,導致跨庫操作。
此時,我只需要把shop_order_detail的分庫策略調整為跟shop_order_stat一致,保證同一個shop_id能路由到同一個DB分片中就能解決這個問題。調整后的sharding分布圖:
但調整完分庫策略后,原本的表映射策略就失效了:
原本的shop_id = 5數據可以通過shop % 12 = 5的取模策略映射到DB0的shop_order_detail_05表上。調整完分庫策略后,shop_id = 9被路由到了DB0中,通過shop % 12 = 9的取模策略會映射到shop_order_detail_09這張表上,但shop_order_detail_09這張表不在DB0中,所以操作失敗了。
這時候,我們需要調整分表策略,把shop_id = 9的數據既映射到DB0中的shop_order_detail_05表中。
2 分區取模策略
首先,以shop_order_stat的單庫表數量2作為分塊大小,總表數量4作為分區大小,對shop_id=[0~11]進行分區操作,并且將shop_id根據分塊大小取模:
當前分庫數量為2,shop_order_stat的單庫表數量為6,計算出跨庫步長=分庫下標*單庫表數量:
根據分區下標和分塊大小,計算出分區步長=分區下標*分塊大小,最后根據分塊取模數+跨庫步長+分區步長就能定位到最終的分表下標了:
這樣就完成了把shop_id = 9的數據既映射到DB0中的shop_order_detail_05表中的工作。
四 計算公式
分表下標路由策略計算公式:
分表下標 = 業務ID取模 % 分塊大小 + 業務ID取模 / 分塊大小?單庫表數量 + 業務ID取模 / 分區大小?分塊大小- 業務ID取模 = 業務ID % 總表數量
- 分區大小 = 目標映射表的總表數量
- 分塊大小 = 目標映射表的單庫表數量
以上面的案例為例,調整shop_order_detail的分庫分表路由策略:
(1)shop_order_stat 商家訂單統計表
(2)shop_order_detail 商家訂單明細表
TDDL sharding-rule配置代碼示例:
Java代碼示例:
long shopId = 9; int dbs = 2; int tables = 12; int oneDbTables = 6; int partitionSize = 4; int blockSize = 2; int sharding = (int) (shopId % tables); // 目標分庫 int dbIndex = (int) (shopId % partitionSize / dbs); // 目標分表 int tableIndex = sharding % blockSize + sharding % partitionSize / blockSize * oneDbTables + sharding / partitionSize * blockSize;五 結尾
我是本地生活外賣商家運營研發團隊中的一員,在實際業務場景的設計中遇到了多表事務分庫內閉環的問題,沒有找到適合的案例參考,才孵化出這個解決方案。
目前該方案已經在落地上線,有相同業務場景需求的同學可直接套用計算公式既可,歡迎大家交流溝通。
原文鏈接
本文為阿里云原創內容,未經允許不得轉載。
總結
以上是生活随笔為你收集整理的分区取模分库分表策略:多表事务分库内闭环解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 快速上手,使用 Kotlin 把支付宝小
- 下一篇: 后疫情时代企业将加速向云服务迁移