10億訂單如何分庫(kù)分表?
前言
場(chǎng)景痛點(diǎn):某電商平臺(tái)的MySQL訂單表達(dá)到7億行時(shí),出現(xiàn)致命問(wèn)題:
-- 簡(jiǎn)單查詢(xún)竟需12秒!
SELECT * FROM orders WHERE user_id=10086 LIMIT 10;
-- 統(tǒng)計(jì)全表耗時(shí)278秒
SELECT COUNT(*) FROM orders;
核心矛盾:
- B+樹(shù)索引深度達(dá)到5層,磁盤(pán)IO暴增。
- 單表超200GB導(dǎo)致備份時(shí)間窗突破6小時(shí)。
- 寫(xiě)并發(fā)量達(dá)8000QPS,主從延遲高達(dá)15分鐘。
關(guān)鍵認(rèn)知:當(dāng)單表數(shù)據(jù)量突破5000萬(wàn)行時(shí),就該啟動(dòng)分庫(kù)分表設(shè)計(jì)預(yù)案。
那么問(wèn)題來(lái)了,假如現(xiàn)在有10億的訂單數(shù)據(jù),我們?cè)撊绾巫龇謳?kù)分表呢?
今天這篇文章就跟大家一起聊聊這個(gè)問(wèn)題,希望對(duì)你會(huì)有所幫助。
1 分庫(kù)分表核心策略
1.1 垂直拆分:先給數(shù)據(jù)做減法

優(yōu)化效果:
- 核心表體積減少60%
- 高頻查詢(xún)字段集中提升緩存命中率
1.2 水平拆分:終極解決方案
分片鍵選擇三原則:
- 離散性:避免數(shù)據(jù)熱點(diǎn)(如user_id優(yōu)于status)
- 業(yè)務(wù)相關(guān)性:80%查詢(xún)需攜帶該字段
- 穩(wěn)定性:值不隨業(yè)務(wù)變更(避免使用手機(jī)號(hào))
分片策略對(duì)比:
| 策略類(lèi)型 | 適用場(chǎng)景 | 擴(kuò)容復(fù)雜度 | 示例 |
|---|---|---|---|
| 范圍分片 | 帶時(shí)間范圍的查詢(xún) | 簡(jiǎn)單 | create_time按月分表 |
| 哈希取模 | 均勻分布 | 困難 | user_id % 128 |
| 一致性哈希 | 動(dòng)態(tài)擴(kuò)容 | 中等 | 使用Ketama算法 |
| 基因分片 | 避免跨分片查詢(xún) | 復(fù)雜 | 從user_id提取分庫(kù)基因 |
2 基因分片
針對(duì)訂單系統(tǒng)的三大高頻查詢(xún):
- 用戶(hù)查歷史訂單(user_id)
- 商家查訂單(merchant_id)
- 客服按訂單號(hào)查詢(xún)(order_no)
解決方案:

Snowflake訂單ID改造:
// 基因分片ID生成器
public class OrderIdGenerator {
// 64位ID結(jié)構(gòu):符號(hào)位(1)+時(shí)間戳(41)+分片基因(12)+序列號(hào)(10)
private static final int GENE_BITS = 12;
public static long generateId(long userId) {
long timestamp = System.currentTimeMillis() - 1288834974657L;
// 提取用戶(hù)ID后12位作為基因
long gene = userId & ((1 << GENE_BITS) - 1);
long sequence = ... // 獲取序列號(hào)
return (timestamp << 22)
| (gene << 10)
| sequence;
}
// 從訂單ID反推分片位置
public static int getShardKey(long orderId) {
return (int) ((orderId >> 10) & 0xFFF); // 提取中間12位
}
}
路由邏輯:
// 分庫(kù)分表路由引擎
public class OrderShardingRouter {
// 分8個(gè)庫(kù) 每個(gè)庫(kù)16張表
private static final int DB_COUNT = 8;
private static final int TABLE_COUNT_PER_DB = 16;
public static String route(long orderId) {
int gene = OrderIdGenerator.getShardKey(orderId);
int dbIndex = gene % DB_COUNT;
int tableIndex = gene % TABLE_COUNT_PER_DB;
return "order_db_" + dbIndex + ".orders_" + tableIndex;
}
}
關(guān)鍵突破:通過(guò)基因嵌入,使相同用戶(hù)的訂單始終落在同一分片,同時(shí)支持通過(guò)訂單ID直接定位分片
3 跨分片查詢(xún)
3.1 異構(gòu)索引表方案

Elasticsearch索引表結(jié)構(gòu):
{
"order_index": {
"mappings": {
"properties": {
"order_no": { "type": "keyword" },
"shard_key": { "type": "integer" },
"create_time": { "type": "date" }
}
}
}
}
4.2 全局二級(jí)索引(GSI)
-- 在ShardingSphere中創(chuàng)建全局索引
CREATE SHARDING GLOBAL INDEX idx_merchant ON orders(merchant_id)
BY SHARDING_ALGORITHM(merchant_hash)
WITH STORAGE_UNIT(ds_0,ds_1);
4、數(shù)據(jù)遷移
雙寫(xiě)遷移方案:

灰度切換步驟:
- 開(kāi)啟雙寫(xiě)(新庫(kù)寫(xiě)失敗需回滾舊庫(kù))
- 全量遷移歷史數(shù)據(jù)(采用分頁(yè)批處理)
- 增量數(shù)據(jù)實(shí)時(shí)校驗(yàn)(校驗(yàn)不一致自動(dòng)修復(fù))
- 按用戶(hù)ID灰度流量切換(從1%到100%)
5、避坑指南
5.1 熱點(diǎn)問(wèn)題
雙十一期間發(fā)現(xiàn)某網(wǎng)紅店鋪訂單全部分到同一分片。
解決方案:引入復(fù)合分片鍵 (merchant_id + user_id) % 1024
5.2 分布式事務(wù)
這里的分布式事務(wù)使用的RocketMQ的數(shù)據(jù)最終一致性方案:
// 最終一致性方案
@Transactional
public void createOrder(Order order) {
orderDao.insert(order); // 寫(xiě)主庫(kù)
rocketMQTemplate.sendAsync("order_create_event", order); // 發(fā)消息
}
// 消費(fèi)者處理
@RocketMQMessageListener(topic = "order_create_event")
public void handleEvent(OrderEvent event) {
bonusService.addPoints(event.getUserId()); // 異步加積分
inventoryService.deduct(event.getSkuId()); // 異步扣庫(kù)存
}
5.3 分頁(yè)陷阱
跨分片查詢(xún)頁(yè)碼錯(cuò)亂。
解決方案:改用ES聚合查詢(xún)或業(yè)務(wù)折衷方案(只查最近3個(gè)月訂單)。
6 終極架構(gòu)方案

性能指標(biāo):
| 場(chǎng)景 | 拆分前 | 拆分后 |
|---|---|---|
| 用戶(hù)訂單查詢(xún) | 3200ms | 68ms |
| 商家訂單導(dǎo)出 | 超時(shí)失敗 | 8s完成 |
| 全表統(tǒng)計(jì) | 不可用 | 1.2s(近似) |
總結(jié)
- 分片鍵選擇大于努力:基因分片是訂單系統(tǒng)的最佳拍檔。
- 擴(kuò)容預(yù)留空間:建議初始設(shè)計(jì)支持2年數(shù)據(jù)增長(zhǎng)。
- 避免過(guò)度設(shè)計(jì):小表關(guān)聯(lián)查詢(xún)遠(yuǎn)比分布式Join高。效
- 監(jiān)控驅(qū)動(dòng)優(yōu)化:重點(diǎn)關(guān)注分片傾斜率>15%的庫(kù)。
真正的架構(gòu)藝術(shù),是在分與合之間找到平衡點(diǎn)。
最后說(shuō)一句(求關(guān)注,別白嫖我)
如果這篇文章對(duì)您有所幫助,或者有所啟發(fā)的話(huà),幫忙關(guān)注一下我的同名公眾號(hào):蘇三說(shuō)技術(shù),您的支持是我堅(jiān)持寫(xiě)作最大的動(dòng)力。
求一鍵三連:點(diǎn)贊、轉(zhuǎn)發(fā)、在看。
關(guān)注公眾號(hào):【蘇三說(shuō)技術(shù)】,在公眾號(hào)中回復(fù):進(jìn)大廠,可以免費(fèi)獲取我最近整理的10萬(wàn)字的面試寶典,好多小伙伴靠這個(gè)寶典拿到了多家大廠的offer。
本文收錄于我的技術(shù)網(wǎng)站:http://www.susan.net.cn

浙公網(wǎng)安備 33010602011771號(hào)