
分库分表架构的核心设计原则
当单表数据突破5000万行时,IO瓶颈就会开始显现。这时候需要考虑的不是”要不要分表”,而是”怎么科学地分表”。垂直分库按照业务维度拆分,比如把用户数据和订单数据分离到不同库;水平分表则是把相同业务的数据按规则分散存储,比如按用户ID哈希分片。
三种典型的分片策略各有优劣:
分片方式 | 适用场景 | 扩容难度 |
---|---|---|
哈希分片 | 无明显热点的均匀数据 | 高 |
范围分片 | 需要范围查询的业务 | 中 |
时间分片 | 日志/时序数据 | 低 |
分片键选择的实战技巧
选错分片键就像建房子选错地基,后期改造成本极高。用户ID是最常用的分片键,但要警惕大V用户产生的数据倾斜。某社交平台曾用用户ID哈希分片,结果发现1%的头部用户产生了60%的内容数据。
更聪明的做法是组合分片键:
遇到需要跨分片查询的情况,可以考虑:
分布式事务的解决方案
分库分表后最头疼的就是分布式事务。下单扣库存的场景,如果库存库和订单库分开,怎么保证数据一致性?目前主流方案有:
实际项目中,80%的场景其实不需要强一致性。比如用户发帖后异步更新统计数,短暂的数据不一致是可以接受的。关键是要根据业务特点选择合适的一致性级别。
性能优化的关键指标
分库分表不是银弹,配置不当反而会降低性能。需要重点监控这些指标:
某电商平台在分表后出现性能下降,排查发现是分片规则导致90%的查询都要跨3个以上分片。调整分片策略后,查询性能提升了5倍。这说明分表不是简单的数据拆分,必须配合查询模式来设计。
分库分表后,传统数据库自增ID就彻底不靠谱了——每个分片都自顾自地增长,分分钟给你整出重复ID来。这时候雪花算法就派上用场了,它把64位ID拆成时间戳、机器ID和序列号三部分,单机每秒能生成26万个不重复ID,而且自带时间顺序。不过要注意机器ID的配置,千万别让不同节点用了相同的ID,那可比数据库主键冲突刺激多了。
除了雪花算法,UUID也是个备选方案,但它的无序性会让索引效率下降30-50%。有些团队喜欢用Redis的原子incr命令来生成ID,性能确实不错,但得考虑Redis挂掉时的容灾方案。还有个冷门但实用的招数是预生成ID池,提前批量生成10-20万个ID缓存在内存里,用完了再补充,这样既避免了实时生成的性能损耗,又能保证顺序性。
常见问题解答
分库分表的最佳时机是什么?
当单表数据量达到5000万-1亿行,或数据量超过服务器内存的50%时就应该考虑分表。具体还要看业务场景,如果查询性能已经明显下降,即使数据量没到阈值也需要提前规划。
如何解决分表后的跨库查询问题?
主要有三种方案:1)使用分布式查询中间件自动聚合结果;2)建立全局索引表记录关键字段与分片映射;3)对高频跨库查询采用数据冗余策略。实际项目中通常会组合使用这些方案。
分库分表后主键ID如何生成?
推荐使用雪花算法(Snowflake)生成分布式ID,避免使用数据库自增ID。也可以考虑UUID、Redis原子操作等方式,关键是要保证ID全局唯一且尽可能有序。
分片键选择不当如何补救?
如果已经上线,可以通过双写方案逐步迁移:1)保持旧分片规则继续运行;2)按新规则同步写入新分片;3)数据追平后切换查询路由。整个过程可能需要1-2周的过渡期。
分库分表对事务一致性有什么影响?
分布式事务性能会下降5-10倍, 尽量设计最终一致性方案。对于必须强一致的场景,可以使用Seata等框架实现TCC模式,但要注意控制事务粒度在100ms内完成。