数据分片如何做?

访客 性能优化 2

本文目录导读:

  1. 第一步:确定分片键
  2. 第二步:选择分片算法
  3. 第三步:选择分片架构
  4. 第四步:处理分片带来的挑战
  5. 第五步:最佳实践建议
  6. 一个典型的分片设计流程

数据分片(Sharding)是指将一个大数据库中的数据水平切分到多个独立的数据库实例(节点)上,从而突破单机存储、性能或并发瓶颈。

做数据分片通常遵循以下步骤和原则:

第一步:确定分片键

这是最关键的一步,分片键决定了数据如何分布,直接影响查询性能和扩展性。

  • 选择依据:选择查询频率最高、分布最均匀、业务中最核心的字段,面向用户的系统常用 user_id;面向订单的系统常用 order_iduser_id
  • 原则
    • 均匀性:数据尽量均匀分布到各个分片,避免“热点”(某个分片数据量或访问量远大于其他分片)。
    • 单一性:大多数业务查询都能带上这个分片键,减少跨分片查询。

第二步:选择分片算法

算法决定了如何根据分片键计算出数据应该去哪个库。

  1. 范围分片

    • 原理:根据ID或时间范围划分,用户ID 1-1万的去分片1,1万-2万的去分片2;或者按月分片。
    • 优点:扩展容易(增加分片只需调整范围);范围查询高效(可直接定位到连续分片)。
    • 缺点:容易造成数据不均(如新用户全在最后一个分片)。
  2. 哈希分片

    • 原理:对分片键计算哈希值,然后对分片数量取模(hash(key) % N)。
    • 优点:数据分布非常均匀,简单直接。
    • 缺点扩展困难,如果从N个分片扩展到N+1个,大部分数据需要重哈希(迁移),通常叫做“扩缩容陷阱”。
    • 改进方案一致性哈希,它引入虚拟节点,扩展时只影响少量相邻节点,大大减少了迁移数据量。
  3. 地理位置分片

    • 原理:根据用户或数据的地理位置分片,如按省、市、国家。
    • 优点:天然符合地域性业务需求,利于就近访问和法规遵从。
    • 缺点:容易导致热点(如北京数据量远大于西藏)。
  4. 时间/日期分片

    • 原理:按时间维度(年、月、日)分片。
    • 优点:适合日志、流水等时序数据;便于过期数据的归档和删除。
    • 缺点:对实时查询和跨时间范围查询不友好,且易产生热数据集中于最新表。

第三步:选择分片架构

分片策略确定后,需要考虑如何管理分片,即分片的“路由”方式。

  1. 客户端分片(直连模式)

    • 原理:应用程序直接连数据库,应用代码或轻量级中间件(如ShardingSphere-JDBC、TSharding)内置路由规则,计算后直接连接对应分片。
    • 优点:性能高(无中间代理层)、部署简单。
    • 缺点:分片逻辑写死在应用代码中,升级需要修改代码。
  2. 代理中间件分片(Proxy模式)

    • 原理:应用程序连接一个代理服务器(如MyCAT、ShardingSphere-Proxy、Vitess、KingShard),代理解析SQL并路由到后端分片。
    • 优点:应用无感知;支持多语言;便于管理、监控和账号权限控制。
    • 缺点:引入网络开销;存在性能瓶颈和单点故障风险(可通过集群解决)。
  3. 分布式数据库原生分片

    • 原理:使用原生支持分布式的数据库(如TiDB、CockroachDB、OceanBase、YugabyteDB)。
    • 优点:自动分片、自动平衡、全ACID事务支持;开发者几乎不用关心分片细节。
    • 缺点:学习和运维成本较高;硬件资源需求较大。

第四步:处理分片带来的挑战

分片解决了容量和性能问题,但引入了新的复杂性,需要配套方案:

  1. 分布式ID生成

    • 分片后,自增ID无法全局唯一且需要分布式生成。
    • 方案:雪花算法(Snowflake)、UUID(但太长,影响索引性能)、Redis自增、数据库号段模式。
  2. 跨分片查询 / 全局表

    • 问题JOINORDER BYCOUNTGROUP BY 等操作需要跨多个分片汇总。
    • 方案
      • 全局表:将字典表、配置表等数据量小、变更少的表,在每个分片都复制一份(全量冗余),查询时在本地分片就能JOIN。
      • 广播表:类似全局表,所有分片都存,插入/更新时同步到所有分片。
      • 中间层聚合:在应用层或代理层,将查询下发到所有分片,然后合并结果并排序。
  3. 分布式事务

    • 一个业务操作可能跨多个分片,传统数据库事务不再适用。
    • 方案
      • XA(两阶段提交):强一致性,但性能较差。
      • TCC(Try-Confirm-Cancel):业务侵入性强。
      • Saga模式:通过补偿操作来保证最终一致性。
      • Seata(阿里开源):AT模式,自动代理数据库SQL,对业务侵入低。
  4. 数据迁移与扩缩容

    • 问题:分片数预先规划不足,需要扩容;或需要重新均衡数据。
    • 方案
      • 停机迁移:简单粗暴,适用于可维护窗口。
      • 双写迁移:同时写入旧库和新库,逐步追平并切换。
      • 使用一致性哈希:减少迁移量。
      • 使用原生分布式数据库:自动完成搬迁。

第五步:最佳实践建议

  1. 能不不分,尽量不分:分片带来的复杂度(跨分片查询、事务、运维)很高,在单表达到千万级或性能瓶颈之前,优先考虑读写分离、缓存、优化SQL、升级硬件。
  2. 选好分片键,减少跨片操作:尽量让80%以上的查询落在单一分片上。
  3. 冗余设计:高频的关联查询,优先用全局表或数据冗余来解决。
  4. 监控关键指标:监控每个分片的连接数、QPS(每秒查询率)、磁盘空间、慢查询,以便及时发现热点或倾斜。
  5. 保留二次分片能力:哈希法建议提前规划好分片总数(例如直接取2的N次方,用位运算代替取模),设计好哈希槽范围,方便未来静态扩展。

一个典型的分片设计流程

  1. 分析业务模型:找到主要查询和写入模式。
  2. 选择分片键:如上,常用 user_id
  3. 选择算法:常用哈希(均匀但扩展麻烦)或日期(适合归档)。
  4. 设计架构:一般项目首选客户端分片(如ShardingSphere-JDBC)或原生分布式数据库(如TiDB)。
  5. 处理副作用:实现分布式ID(雪花算法)、处理跨库查询(中间层聚合)、解决跨库事务(AT模式)。
  6. 长期运维:监控分片健康度,做好扩缩容预案。

标签: 分片策略

抱歉,评论功能暂时关闭!