Z 轴扩展:数据分区
X 轴复制了服务实例,Y 轴拆分了业务功能,但数据还是存在一起。当数据量增长到单机无法存储时,X 轴和 Y 轴都无能为力。Z 轴扩展,就是解决「数据量太大」问题的方案。
什么是 Z 轴扩展
Z 轴扩展是按数据属性对数据进行分区(Sharding)。不同的数据子集存储在不同的分片中,每个分片存储一部分数据,负载分散到多个存储节点。
与 X 轴的区别:X 轴每个节点有完整数据,只是处理不同请求;Z 轴每个节点只有部分数据。
按数据属性分区
Z 轴的核心是选择正确的「分区维度」。这个维度叫分片键(Shard Key),数据按分片键的值决定归属哪个分片。
常见分片键
用户 ID 哈希:最常用的分片键。用户请求总是携带用户 ID,按用户 ID 路由,天然实现用户数据隔离。
地区/地域:适合有地域属性的业务,如用户按省份分区、订单按发货仓库分区。
时间/日期:适合时间序列数据,如日志、监控数据、交易记录。按月或按年分区。
字母前缀:按用户名的首字母分区,实现相对均匀的分布。
分片键选择原则
分片键的选择直接影响系统性能和数据分布均匀度。
错误示例:按性别分两个分片——数据不均匀不说,每次查询几乎都要跨分片。
正确示例:按用户 ID 分片——高基数、数据分布均匀、查询总是定位到单个分片。
分片键设计
分片键一旦确定,修改代价极高。需要仔细设计。
单分片键 vs 复合分片键
单分片键:用一个字段作为分片键。简单,但可能无法满足复杂查询需求。
复合分片键:用多个字段组合作为分片键。例如 region_userid,既能按地区路由,又能区分用户。
分片键与查询模式
分片键的选择应该匹配最常见的查询模式。
如果查询总是带用户 ID:user_id 是合适的分片键。
如果查询总是带时间范围:create_time 或 year_month 是合适的分片键。
如果查询条件多样(有时按用户、有时按地区):考虑两个方案——维护多个分片键的索引,或接受跨分片查询的性能损耗。
分片键修改的代价
分片键修改意味着数据需要重新分布。这是一个灾难性的操作:
- 需要迁移所有历史数据
- 迁移期间服务需要继续运行
- 迁移完成后需要验证数据一致性
解决方案是在初期预留足够的分片数,并使用「逻辑分片 + 物理分片」的二层架构:
适用场景
Z 轴扩展适合特定的数据问题,不是所有数据都需要分片。
适合 Z 轴扩展的场景
数据量巨大:单表数据超过千万级、单机磁盘容量不足。MySQL 单表建议控制在千万以内,MongoDB 单分片建议控制在 TB 级以内。
单用户数据隔离:每个用户只访问自己的数据,按用户 ID 分片效率最高。
合规要求:数据按地区隔离(如金融行业的属地化要求)。
性能瓶颈在存储:数据库成为系统瓶颈,水平扩展服务实例无效。
不适合 Z 轴扩展的场景
数据量中等:几百万数据,加索引、加缓存就能解决,没必要引入分片复杂性。
跨实体查询多:如果大部分查询需要跨多个分片聚合,分片的优势会被抵消。
业务早期:业务模型还不稳定,分片键选错后修改成本极高。
团队能力不足:分片带来运维复杂性(数据迁移、跨分片查询、热点问题),需要配套工具和经验。
Z 轴扩展的代价
Z 轴扩展解决了数据量问题,但引入了新的复杂性。
跨分片查询:单次查询可能需要访问多个分片,然后归并结果。性能损耗严重。
分片间平衡:数据增长不均匀时,部分分片可能成为热点,需要重新平衡。
分布式事务:涉及多个分片的数据变更,需要分布式事务机制(如 Seata)。
运维复杂度:备份、恢复、监控都需要考虑分片维度。
X/Y/Z 三轴对比
常见误区
误区一:过早分片
分片是最后手段,不是首选方案。单机数据库能支持的数据量远比你想象的大(合理的 SQL、合适的索引、充足的内存),不应该一上来就分片。
误区二:分片键选择随意
分片键影响数据分布和查询性能。选错分片键可能导致热点分片、跨分片查询,性能反而下降。
误区三:分片数固定不变
业务增长,分片数必然要调整。选择支持动态扩容的分片方案,避免未来数据迁移的痛苦。
误区四:忽视分片带来的查询问题
分片后,跨分片的查询(JOIN、聚合、分页)变得极其复杂。在决定分片前,评估你的查询模式是否适合分片。
延伸思考
Z 轴扩展的核心挑战是「数据分布」和「查询路由」。好的分片设计应该让数据均匀分布、查询路由简单。
实践中,Z 轴通常与 X/Y 轴组合使用。先按 Y 轴拆服务,每个服务的数据库再按 Z 轴分片。例如:用户服务拆出来,用户库按用户 ID 分 4 个分片;订单服务拆出来,订单库按用户 ID 分 8 个分片。
理解每个轴的边界和代价,才能做出正确的架构决策。Z 轴不是银弹,它解决了一类问题,但带来了另一类问题。在决定 Z 轴之前,问自己:数据量真的大到单机存不下了吗?有没有其他方案(归档、冷热分离、索引优化)?