虚拟分片查询一致性分析
如果小伙伴对于 为什么通过 订单编号(OrderNumber)以及 用户id(userId)在虚拟分片路由表查询后,能够定位到相同的物理库和物理表 还有疑惑的话,可以详细查看此篇章节的讲解
一、观察到的现象
订单编号查询:
shardingKey = 1978005150261182474
→ 虚拟分片266 → 库0.表2
用户ID查询:
shardingKey = 1136344580112367618
→ 虚拟分片258 → 库0.表2
现象:
虚拟分片ID不同(266 vs 258),但最终路由到相同位置(库0.表2)!
二、真实数据计算验证
订单号:1978005150261182474
步骤1:提取基因位(后3位)
1978005150261182474 & 0b111 = 2 (二进制:0b10)
步骤2:解析基因位
- 表索引(后2位):2
- 库索引(第3位):0
步骤3:计算物理分片索引
physicalShardIndex = 0 × 4 + 2 = 2
步骤4:计算虚拟偏移
1978005150261182474 % 128 = 10
步骤5:计算虚拟分片ID
logicalShardId = 2 × 128 + 10 = 266
用户ID:1136344580112367618
步骤1:提取基因位(后3位)
1136344580112367618 & 0b111 = 2 (二进制:0b10)
步骤2:解析基因位
- 表索引(后2位):2
- 库索引(第3位):0
步骤3:计算物理分片索引
physicalShardIndex = 0 × 4 + 2 = 2
步骤4:计算虚拟偏移
1136344580112367618 % 128 = 2
步骤5:计算虚拟分片ID
logicalShardId = 2 × 128 + 2 = 258
关键对比
| 维度 | 订单号 | 用户ID | 是否相同 |
|---|---|---|---|
| 基因位(后3位) | 2 | 2 | ✅ 相同 |
| 物理分片索引 | 2 | 2 | ✅ 相同 |
| 虚拟偏移 | 10 | 2 | ❌ 不同 |
| 虚拟分片ID | 266 | 258 | ❌ 不同 |
| 虚拟分片范围 | 256-383 | 256-383 | ✅ 相同 |
| 最终路由 | 库0.表2 | 库0.表2 | ✅ 相同 |
三、核心机制解析
3.1 为什么 physicalShardIndex 相同?
关键:订单号生成时嵌入了用户ID的基因位!
回顾 SnowflakeIdGenerator.getOrderNumber() 方法:
public synchronized long getOrderNumber(long userId,
long tableCount,
long databaseCount) {
//pro项目中有详细的代码和注释
}
结果:
userId的后3位 = 订单号的后3位
验证:
userId: 1136344580112367618 & 0b111 = 2
orderNumber: 1978005150261182474 & 0b111 = 2
✅ 相同!
3.2 为什么虚拟分片ID不同但路由相同?
物理分片2对应的虚拟分片范围:256 - 383
路由表映射:
┌─────────────────┬──────────────────┬──────────────────┐
│ 虚拟分片ID │ 物理库表 │ 说明 │
├─────────────────┼──────────────────┼──────────────────┤
│ 256 │ db_0.table_2 │ │
│ 257 │ db_0.table_2 │ │
│ 258 │ db_0.table_2 │ ← 用户ID路由到这里│
│ ... │ db_0.table_2 │ │
│ 266 │ db_0.table_2 │ ← 订单号路由到这里│
│ ... │ db_0.table_2 │ │
│ 383 │ db_0.table_2 │ │
└─────────────────┴──────────────────┴──────────────────┘
关键:虚拟分片 256-383 的所有ID都映射到同一个物理表!
三层保障机制
第1层保障:基因法
├─ 订单号生成时嵌入userId的基因位(后3位)
└─ 结果:订单号和userId的基因位相同 ✅
第2层保障:物理分片索引
├─ 基因位相同 → physicalShardIndex相同
└─ 结果:都路由到物理分片2 ✅
第3层保障:虚拟分片范围
├─ physicalShardIndex相同 → 虚拟分片在同一个128范围内
├─ 物理分片2 → 虚拟分片256-383
└─ 结果:266和258都在256-383范围内 ✅
最终保障:路由表映射
├─ 虚拟分片256-383全部映射到同一个物理表
└─ 结果:都路由到 damai_order_0.d_order_2 ✅
3.3 为什么必须整体迁移128个虚拟分片?
❌ 错误示例(只迁移部分虚拟分片)
虚拟分片258 → 迁移到 db_0.table_6
虚拟分片266 → 保留在 db_0.table_2
结果:
用户ID查询 → 路由到 table_6 ✗
订单号查询 → 路由到 table_2 ✗
查询不一致!数据找不到!
✅ 正确示例(整体迁移128个虚拟分片)
虚拟分片256-383 → 全部迁移到 db_0.table_6
结果:
用户ID查询 → 路由到 table_6 ✓
订单号查询 → 路由到 table_6 ✓
查询一致!数据都在table_6!
3.4 🔑 核心问题:为什么 266 和 258 都在 [256, 383] 范围内?
💡 最核心的本质(一句话说清楚)
关键就是这一行代码:
int virtualOffset = (int)(Math.abs(shardingKey) % virtualShardsPerPhysical);
// ↑
// 对128取模
付费内容提示
该文档的全部内容仅对「码力全开」项目实战&技术讲解 知识星球用户开放
加入星球,一次获得完整项目资料、全栈技术知识库和长期答疑服务。
100万+字全栈技术知识库深入讲解技术核心、数据库、中间件和分布式等内容
8套热门的实战项目持续更新的企业级项目覆盖高并发、微服务、数据中台 和 AI Agent 等方向
AI 技术知识大模型面试详解覆盖 AI 模型原理、Agent、RAG、MCP、Skills、Harness 等核心知识点
文档 + 视频两种讲解形式既能系统阅读,也能跟随视频理解核心业务
完整项目实战资料
每套项目均包含从 0 到 1 讲解文档核心业务讲解视频从基础项目到复杂业务场景,项目资料会持续更新。
- 01Nexus Agent AI 智能体
- 02Nexus Agent Pro 完全版
- 03黑马点评Plus
- 04大麦
- 05大麦Pro
- 06大麦AI
- 07流量切换
- 08数据中台
加入后还能获得
进入星球后,即可享受上述所有服务,保证不会再有其他隐藏费用。从学习、面试到项目启动,都可以继续获得支持。
- 1 对 1 解答项目和技术问题都可以提问
- 针对性补充没有讲清楚的内容会继续补充
- 面试与简历指导梳理回答技巧和项目亮点
- 中间件云环境项目依赖可以直接接入使用
- 面试后复盘被问住的问题可以继续交流
- 远程问题解决项目启动问题可协助排查
