任何有一定规模的系统,迟早都会面临“单机性能不够”的问题。MySQL 在扩展性上的优势,不在于它提供了什么颠覆性的黑科技,而在于它的扩展方案经过了长期、大规模的实战验证,方案成熟、组件丰富、路径清晰,大部分公司都可以按部就班地实施。
主从复制:最基础的横向扩展方式
主从复制是 MySQL 扩展能力的基石。它的工作方式很直观:
- 主库(Master)上所有提交的事务,都会被记录到二进制日志(Binlog)中。
- 从库(Slave)通过一个 I/O 线程连接到主库,把主库的 Binlog 拉取过来,写到本地的中继日志(Relay Log)中。
- 从库的 SQL 线程再读取中继日志,重放里面的操作,最终达到与主库数据同步。
这套机制带来的直接价值是数据多副本和读写分离。搭建主从复制不需要额外的中间件,原生配置就能完成。一般来说,一个主库可以挂多个从库,读请求可以水平扩展。
实际使用中,主从复制主要分三种模式:
- 异步复制:主库提交事务后不等待从库确认,直接返回客户端。性能最好,但如果主库突然宕机,已经提交的事务可能还没同步到从库,存在数据丢失风险。这是 MySQL 5.5 及之前唯一的方式,现在仍然广泛用于对数据绝对一致性要求不高的场景(如日志、流水记录)。
- 半同步复制:在 MySQL 5.5 中引入,5.7 后增强。主库提交事务后,必须等待至少一个从库把 Binlog 写入中继日志并返回确认,主库才向客户端返回成功。这大大降低了数据丢失的风险,代价是写入延迟略有增加(通常是毫秒级)。大多数金融、交易类场景都推荐使用半同步复制。
- 组复制(MGR):MySQL 5.7 开始提供的多主复制方案,基于 Paxos 协议,多个节点可以同时接受写入,自动进行冲突检测和一致性协商。适合对高可用和多活有强烈需求的场景,但运维复杂度相对更高。
在运维上,你需要监控主从延迟(Seconds_Behind_Master),如果这个值持续很大,说明从库追不上主库的写入速度,可能需要进一步优化或扩容。
读写分离:用多台从库分担读压力
绝大多数互联网业务都是“读多写少”:一个用户下单写一次,但这个商品可能被浏览上千次;一条微博发一次,但被阅读上万次。主从复制天然适合把读流量分摊到从库,写请求仍然只发生在主库。
实现读写分离,主要有两种思路:
- 中间件代理:应用代码不需要关心主从,直接连接代理中间件,由中间件根据 SQL 的类型(SELECT 还是 INSERT/UPDATE/DELETE)自动路由。常用的开源方案包括:
- ProxySQL:专为 MySQL 设计的智能代理,支持读写分离、查询缓存、连接池、故障切换,性能高且配置灵活,是现在社区里比较推崇的方案。
- MyCat:诞生更早,功能很全,不仅能读写分离,还能做分库分表,但 SQL 兼容性不如 ProxySQL,在边界场景需要注意。
- ShardingSphere-Proxy:Apache 顶级项目,同样支持读写分离与分片,生态活跃,云原生友好。
- 应用层路由:代码里显式地配置两个数据源,一个“写数据源”指向主库,一个“读数据源”指向从库,由 ORM 框架或手写代码来选择。这种方式更轻量,没有代理节点的额外维护成本,但逻辑分散在代码中,修改时要重新发布应用。
选择哪种方案,核心取决于团队规模和复杂度容忍度。小团队、简单架构可以直接在应用层处理;当从库数量多、切换频繁时,代理中间件会是更好的选择。
需要注意的是,读写分离引入了一个固有问题——主从延迟。如果用户刚写入一条数据,紧接着去从库读,可能还没同步过来,导致“写后读”不命中。一般的应对方法是:对时效性要求极高的场景(如个人订单、账户余额),在写完后的核心操作仍然强制从主库读取,也就是所谓的“读写分离 + 少量读主”。
分库分表:突破单机容量与性能天花板
主从复制和读写分离能分担读压力,但如果写入量也大到单机扛不住,或者单表数据达到几千万甚至上亿行,SQL 性能明显下降,那就需要分库分表了。
分库分表的本质是把原来一个大的数据库逻辑上拆分成多个小数据库,每个小数据库只承担一部分数据,从而达到横向扩展的目的。通常分为两个维度:
- 垂直拆分:按业务模块把不同的表放到不同的库。比如用户库、订单库、商品库分开部署。这往往是最先实施的一步,可以降低单库的耦合度和压力,并且边界清晰,实施难度较低。
- 水平拆分:同一个表的数据,按某个字段(通常叫分片键)分散到多个库里。比如订单表按用户 ID 哈希取模,分散到 8 个库,每个库的订单表结构完全相同,只是数据范围不同。这是真正扛住大规模数据量和写入压力的手段。
分库分表固然有效,但它也带来了巨大的复杂度,需要谨慎评估是否真的有必要。实施前,你要考虑至少以下几个问题:
- 分片键的选择:它决定了数据分布的均匀程度和后续查询的便捷性。最好选择大多数查询都携带的列(如 user_id),尽量避免跨分片查询。
- 分布式 ID 生成:原来的自增主键在多个分片库中会冲突,需要使用雪花算法(Snowflake)、号段模式、ZooKeeper 序列等全局唯一 ID 方案。
- 跨分片操作:如果业务需要跨分片 JOIN、分页排序、聚合统计,SQL 在原地已经无法执行,需要通过中间件将查询分发到各个分片,汇总结果。这种操作性能会大打折扣,设计时要尽可能避免。
- 事务一致性:分库后,原来一个本地事务变成了跨库分布式事务。Seata 等分布式事务框架可以提供支持,但性能和复杂度和单机事务不在一个量级,业务层往往需要配合使用柔性事务、最终一致性等方案。
好在这些复杂度通常由中间件来屏蔽。国内使用最广泛的分库分表中间件是 ShardingSphere 和 MyCat。它们会伪装成一个 MySQL 实例,应用连接它就像连接单机数据库一样,实际的路由、结果归并、分布式 ID 生成都由中间件内部完成。
高可用架构:当一台服务器不够稳时
扩展性不止是为了分担压力,也是为了让系统更健壮。主从复制如果只有主库单点,主库宕机整个服务就不可写了。高可用方案的目标就是让数据库在单机故障时依然能对外服务。
常见的 MySQL 高可用方案包括:
- MHA(Master High Availability):一套相对成熟的故障切换脚本框架,能在主库宕机时自动选择最新的从库提升为主库,并补全差异日志。业界积累了大量案例,部署和维护成本可控。
- Orchestrator + VIP/DNS:Orchestrator 是 GitHub 开源的 MySQL 高可用管理工具,可以自动检测故障、进行拓扑调整,配合 VIP 漂移或 DNS 切换,实现应用透明的主从切换。它在复杂的复制拓扑中比 MHA 更灵活。
- InnoDB Cluster:MySQL 官方在 5.7 之后推出的一体化高可用方案,底层基于组复制(MGR),配合 MySQL Router 或 MySQL Shell 管理。多主模式、自动故障检测、分布式恢复都内建支持,是目前官方主推的现代高可用架构。
- 云上托管:如果你用的是云 RDS,这些复杂性基本被屏蔽了。云厂商默认提供了主备架构、自动故障切换、备份等功能,你只需要选择实例规格、配置高可用策略即可。
扩展性的价值,总结起来就是一句话:你不用在项目第一天就上分库分表,但选择 MySQL 意味着当你需要时,有一套清晰的、可落地的演进路线,而且路上已经有无数先行者的经验可以参考。 从小网站到千万日活,MySQL 的扩展方案都能兜得住底。