分區取模分庫分表策略:多表事務分庫內閉環解決方案

簡介: 當表數據超過必定量級,就須要經過分表來解決單表的性能瓶頸問題;當數據庫負載超過必定水平線,就須要經過分庫來解決單庫的鏈接數、性能負載的瓶頸問題。本文將闡述在不一樣狀況下,讓不一樣數量級表,在同一個業務ID的事務操做路由到同一分庫中的方案,省去解決垮庫事務的煩惱。
image.png數據庫

做者 | 雨莊
來源 | 阿里技術公衆號性能

一 前言

技術同窗都知道,當表數據超過必定量級,咱們就須要經過分表來解決單表的性能瓶頸問題;當數據庫負載超過必定水平線,咱們就須要經過分庫來解決單庫的鏈接數、性能負載的瓶頸問題。阿里雲

本文主要闡述在同時知足如下業務場景:spa

分表分庫存儲
須要對分表數量不一樣的表進行同事務操做
這些表的分庫分表策略依賴的Sharding業務ID一致
等狀況下,讓這些不一樣數量級表,在同一個業務ID的事務操做路由到同一分庫中的方案,省去解決垮庫事務的煩惱。設計

二 案例

1 背景

假設有2個數據庫實例,須要保存商家訂單明細和彙總2張表的數據,這2張表的 分庫分表策略都用shop_id取模策略,按單表數據500w的原則進行分表分庫:code

(1)shop_order_detail 商家訂單明細表,日均數據6000w事務

image.png

(2)shop_order_stat 商家訂單統計表,日均數據2000w路由

image.png

配置完成後生成的庫表:get

image.png

而後咱們要作這麼一件事情:在同一個事務中,新增用戶訂單明細成功後,更新用戶訂單統計數據:it

image.png

2 問題

此時,我要處理一筆 user_id = 3 的訂單數據:

image.png

如圖,執行新增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分佈圖:

image.png

用shop_id % 12分庫分表策略shop_order_detail的sharding分佈圖:

image.png

圖中看出,兩張表都是根據shop_id作sharding,但現有同一個shop_id有可能會被路由到不一樣的庫中,致使跨庫操做。

此時,我只須要把shop_order_detail的分庫策略調整爲跟shop_order_stat一致,保證同一個shop_id能路由到同一個DB分片中就能解決這個問題。調整後的sharding分佈圖:

image.png

但調整完分庫策略後,本來的表映射策略就失效了:

image.png

本來的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根據分塊大小取模:

image.png

當前分庫數量爲2,shop_order_stat的單庫表數量爲6,計算出跨庫步長=分庫下標*單庫表數量:

image.png

根據分區下標和分塊大小,計算出分區步長=分區下標*分塊大小,最後根據分塊取模數+跨庫步長+分區步長就能定位到最終的分表下標了:

image.png

這樣就完成了把shop_id = 9的數據既映射到DB0中的shop_order_detail_05表中的工做。

四 計算公式

分表下標路由策略計算公式:

分表下標 = 業務ID取模 % 分塊大小 + 業務ID取模 / 分塊大小 單庫表數量 + 業務ID取模 / 分區大小 分塊大小
業務ID取模 = 業務ID % 總表數量
分區大小 = 目標映射表的總表數量
分塊大小 = 目標映射表的單庫表數量
以上面的案例爲例,調整shop_order_detail的分庫分表路由策略:

(1)shop_order_stat 商家訂單統計表

image.png

(2)shop_order_detail 商家訂單明細表

image.png

TDDL sharding-rule配置代碼示例:

image.png

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;

五 結尾

我是本地生活外賣商家運營研發團隊中的一員,在實際業務場景的設計中遇到了多表事務分庫內閉環的問題,沒有找到適合的案例參考,才孵化出這個解決方案。

目前該方案已經在落地上線,有相同業務場景需求的同窗可直接套用計算公式既可,歡迎你們交流溝通。
原文連接本文爲阿里雲原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索