⚙️ 一、分片策略选择(核心决策)

1. 按用户ID分片
  • 适用场景:用户维度的查询频繁(如查询个人订单列表、分页展示)。
  • 实现方式:
    • 分库:user_id % 64 路由到64个库(预留扩容空间)。
    • 分表:每个库内按user_id % 1024 分1024张表,单表控制在千万级数据量。
  • 优点:同一用户数据集中存储,避免跨分片查询。
  • 缺点:超级买家可能导致数据倾斜(如某用户订单量极大)。
  • 优化:冷热分离,3个月内热数据存MySQL,历史数据归档至HBase/ES。
2. 按订单号分片
  • 适用场景:需均匀分散写入压力,避免热点。
  • 实现方式:
    • 基因分片法:订单号末尾嵌入用户ID哈希值(如订单号=时间戳+用户ID后4位+随机数),直接根据订单号定位库表。
    • 分库分表:hash(order_id) % (库数量×表数量) 计算中间变量,再拆解库表序号。
  • 优点:数据分布均匀,支持高并发写入。
  • 缺点:按用户ID查询需跨分片,需额外设计索引表。
3. 按时间分片
  • 适用场景:时间范围查询为主(如统计月度订单)。
  • 实现方式:按月分库(orders_202301),库内再按用户ID或订单号分表。
  • 缺点:新表写入热点,历史数据查询需跨库。
  • 优化:结合哈希后缀分散写入(如订单号添加随机数)。

🔍 二、全局ID生成方案

  1. 雪花算法(Snowflake):
    • 64位结构:1符号位 + 41位时间戳 + 10位机器ID + 12位序列号。
    • 问题:时钟回拨需通过NTP同步或本地缓存解决。
  2. 号段模式:
    • 从数据库批量获取ID段(如每次分配1000个ID),减少DB压力。
  3. 嵌入分片信息:
    • 在订单号头部添加分库分表路由码(如库序号+表序号),实现无索引直接查询。

🔗 三、跨分片查询解决方案

  1. 索引表机制:
    • 建订单号→用户ID映射表,异步写入MQ更新,分库分表后按订单号取模分片。
    • 查询时先查索引表获取用户ID,再路由到对应分片。
  2. 数据冗余:
    • 多写异构:订单同时写入买家库(按user_id分片)和卖家库(按shop_id分片),通过MQ同步数据。
    • 字段冗余:订单表冗余商家名称、用户名称等高频字段,避免JOIN查询。
  3. 聚合查询:
    • 复杂统计(如全平台销售额)通过ETL同步至ES或Hive离线分析。

⚠️ 四、热点问题处理

  1. 秒杀订单:
    • 独立分片:秒杀订单单独分配至特定分库,避免影响常规订单。
    • 本地缓存+Redis预减库存,DB层异步落单。
  2. 数据倾斜:
    • 冷热分离:3个月内热数据存高性能库,历史数据转冷存储。
    • 动态扩容:按倍数扩容(如8库→16库),减少数据迁移量。

🧩 五、典型架构设计示例

客户端
应用层
分库分表中间件-ShardingSphere
订单库1-按user_id分片
订单库2-按user_id分片
...
热数据表
冷数据表
冷数据归档至HBase/ES
读写分离
主库-写
从库-读

关键组件:

  • 中间件:ShardingSphere实现SQL解析、分片路由、结果归并。
  • 读写分离:主库处理写入,从库负载读请求,通过binlog同步。

⚠️ 六、实施注意事项

  1. 分片键选择:
    • 避免低基数字段(如订单状态),优先选高频查询字段(用户ID、订单号)。
  2. 扩容方案:
    • 预分片:一次性创建足够多的逻辑表(如1024张),通过中间件管理物理映射。
    • 一致性哈希:减少扩容时数据迁移量。
  3. 事务一致性:
    • 分布式事务:TCC(Try-Confirm-Cancel)或Seata AT模式(基于全局锁+Undo Log)。
  4. 禁止操作:
    • 无分片条件全表扫描,必须带分片键查询。

💎 总结:方案选型建议

  • 主流方案:用户ID分库+时间分表,兼顾用户查询效率与时间范围统计。
  • 超高并发写入:订单号基因分片,分散写入压力。
  • 多角色查询:买家库+卖家库冗余,通过MQ同步数据。

💡 最终设计需结合业务流量模拟验证分片均匀性,优先使用ShardingSphere等中间件降低复杂度,冷热分离是应对数据膨胀的必备策略。

更多推荐