数据库读写分离解决方案介绍
概述
读写分离要做的事情就是决定一条 SQL 该到哪个数据库去执行,至于谁来做决定数据库这件事,要么数据库中间件去做,要么应用程序自己去做。首先针对应用程序自己去做的场景,读写分离的职责应该属于数据访问层而不是业务层,其次读写分离不应该入侵到代码中。因此在 Service—DAO—ORM— 数据库驱动的调用链中,要想做到代码弱入侵性或者零入侵性,只能将读写分离写在 ORM 层或者数据库驱动层,写在 ORM 层就和具体 ORM 框架耦合,写在数据库驱动层,就和具体数据库耦合。至于在 ORM 层还是在数据库驱动层实现读写分离,主要看更换 ORM 框架和数据库哪个成本更高和实现的难易程度。一般来讲,读写分离的核心方案主要有以下几种:
- 第一种构建多套环境,优势是方便控制也容易集成一些简单的分布式事务,缺点是非动态同时代码量较多,配置难度大;
- 第二种是依靠数据库中间件(例如:MyCat),由中间件做读写分离,优势是对整个应用程序都是透明的,缺点是降低性能,不支持多数据源事务;
- 第三种是应用程序自己去做,例如使用支持读写分离的数据库驱动、使用 Spring 原生提供的 AbstractRoutingDataSource。后者需要控制只读事务和读写事务切换到主库,写操作切换到主库,读操作切换到从库;同时保证单个事务里面所有的 SQL 都是在同一个数据源里执行。缺点是多数据源的配置不灵活,不支持多数据源事务。具体实现方式可参考 基于 Service 层的 Spring 路由数据源 + AOP / Annotation、基于 ORM 层的 Spring 路由数据源 + Mybatis 插件 / Annotation。
数据库中间件介绍
读写分离、分库分表中间件通常分为 Proxy 层和 Client 层两种类型,不同中间件的优缺点如下。
读写分离中间件
- 出身:淘宝团队研发,大概在 2008 年左右就在淘宝内部投入使用,是一种 Client 层方案。
- 状态:目前已很久未更新,已几乎被废弃,不建议使用。
- 优势:支持基本 CRUD 操作和读写分离。
- 局限:不支持 JOIN 和多表查询,依赖淘宝内部的 Diamond 配置系统,社区采用不多,适用性有限。
- 出身:奇虎 360 开源,是一种 Proxy 层方案。
- 状态:目前已很久未更新,已几乎被废弃,不建议使用。
- 局限:功能上较为简单,仅支持 MySQL 协议代理,主要实现读写分离、简单分表,不支持复杂的分库分表场景。
- 出身:由美团点评公司的 DBA 团队开发维护,是在 Atlas(奇虎 360)的基础上改造 / 重构而来。
- 状态:在美团内部广泛用于生产环境,功能较为成熟、稳定,但是目前已很久未更新,已几乎被废弃,不建议使用。
- 局限:仅支持 MySQL(Percona
5.5/5.6)的读写分离;虽然支持「分表 (Table‑Sharding)」,但「分库 (DataBase‑Sharding)」功能仍是 “正在内测中 / 不完善”,对于复杂的大规模分库分表、跨库事务、动态扩容 / 迁移等场景支持有限。
- 出身:国外开源社区开发,专注于高性能 MySQL 代理,是一种 Proxy 层方案。
- 优势:支持读写分离、负载均衡、查询路由、连接池、查询缓存等功能;部署灵活,性能高,可支持高并发场景;多语言客户端透明接入。
- 局限:需要额外部署和运维中间件,网络跳转会带来一定延迟;对复杂分库分表逻辑需要额外配置,学习成本相对较高;社区活跃度高,但中文文档和案例相对少。
- 出身:Google 开发,用于构建云原生、水平可扩展的分布式数据库系统,主要是 Proxy/Cluster 层方案。
- 优势:支持主从分离的读写分离,提供分库分表(水平切分)能力,透明处理 SQL 分布式查询,支持事务;适合大规模、高并发 MySQL 场景;云原生友好,可与 Kubernetes 等集群管理系统集成。
- 局限:架构相对复杂,需要额外的运维和学习成本;主要面向大规模场景,对小型项目可能过于重量级;部分高级功能(如跨分片事务)需要谨慎使用。
分库分表中间件
- 出身:阿里巴巴 B2B 团队开发,诞生时间大约在 2009~2010 年,后来在 2012 年开源,是一种 Proxy 层方案。
- 状态:目前已很久未更新,已几乎被废弃,不建议使用。
- 局限:不支持读写分离、存储过程、跨库 JOIN、跨库分页等功能。
- 出身:基于 Cobar 改造,是一种 Proxy 层方案。
- 优势:功能全面,支持事务、跨库分片、聚合计算等,不少企业已有应用案例。
- 局限:社区更新不算频繁,相较 ShardingSphere 较年轻,稳定性和成熟度略逊,最新公开版本发布时间较早。
- 出身:Google 开发,用于构建云原生、水平可扩展的分布式数据库系统,主要是 Proxy/Cluster 层方案。
- 优势:支持主从分离的读写分离,提供分库分表(水平切分)能力,透明处理 SQL 分布式查询,支持事务;适合大规模、高并发 MySQL 场景;云原生友好,可与 Kubernetes 等集群管理系统集成。
- 局限:架构相对复杂,需要额外的运维和学习成本;主要面向大规模场景,对小型项目可能过于重量级;部分高级功能(如跨分片事务)需要谨慎使用。
- 项目源起:
- 由 Sharding-JDBC 演化成如今的 Apache ShardingSphere,包含多个组件:JDBC(Client 层)、Proxy(Proxy 层)、Sidecar 等。
- Sharding-JDBC(Client 层方案):
- 优点:以
.jar形式嵌入项目,运维轻松,性能接近原生 JDBC,低侵入性。 - 局限:仅支持 Java,升级依赖分散到各个应用,需要统一发布更新。
- 优点:以
- ShardingSphere-Proxy(Proxy 层方案):
- 优点:作为独立进程部署,支持多语言客户端,接入透明,便于统一管理、运维,适合 OLAP 操作和 DBA 管理。
- 局限:多了网络跳转,性能略逊于 JDBC,且需额外部署、维护中间件。
- 社区活跃度:社区活跃、版本持续迭代,功能丰富,包括读写分离、分布式事务、治理、安全、多数据源等。
- 项目源起:
目前常见的分库分表中间件,主要建议考虑 Sharding-JDBC 和 MyCat / ShardingSphere-Proxy 这几个。
Sharding-JDBC(Client 层方案):
- 优点:无需单独部署中间件,运维成本低,不涉及代理层的二次转发,性能高。
- 缺点:如果版本升级,需要每个业务系统单独升级并重新发布,而且各个系统必须耦合 Sharding-JDBC 的依赖。
ShardingSphere-Proxy / MyCat(Proxy 层方案):
- 优点:作为独立中间件部署,对各个项目透明,系统接入方便。如果需要升级,只需要在中间件层处理即可,不需要各业务系统修改。
- 缺点:需要额外部署和运维中间件,运维成本更高。
适用场景:
- 中小型公司:推荐使用 Sharding-JDBC 这类 Client 层方案。因为系统复杂度相对较低,项目数量不多,运维人力有限,使用 Client 层方案更轻便,维护成本低。
- 中大型公司:更适合 ShardingSphere-Proxy / MyCat 这类 Proxy 层方案。因为系统和项目数量多,团队规模大,可以安排专人研究和维护 MyCat,而大量项目能直接透明接入,整体更易管理。
读写分离解决方案
客户端解决方案
方案的概述
客户端解决方案(持久化层):TDDL、ShardingSphere-JDBC

方案的优缺点
优点
- 数据源方便由应用直接管理
- 运维不需要额外维护中间件
- 理论上支持任何数据库(SQL 标准)
缺点
- 增加了开发成本、对代码有一定的入侵性
- 不能做到动态增加数据源
- 开发人员开发完成后,运维人员参与不了
中间件解决方案
方案的概述
中间件解决方案(代理层):MySQL Proxy、MyCat、Altas

方案的优缺点
优点
- 持久化层不需要管数据库方面的事情
- 数据源增加了对应用没有任何影响(不需要重启应用)
缺点
- 应用依赖了中间件,导致切换数据库变得困难
- 增加了 Proxy 中间件,导致数据库性能下降
- 增加了维护难度、高可用等问题
读写分离最佳实践
ShardingSphere
ShardingSphere 是 Apache 的一款分布式的数据库生态系统,它包含两大产品:ShardingSphere-Proxy、ShardingSphere-JDBC。值得一提的是,ShardingSphere-JDBC 提供了读写分离、数据分片等功能的支持。
ShardingSphere-Proxy
ShardingSphere-Proxy 被定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。代理层介于应用程序与数据库间,每次请求都需要做一次转发,请求会存在额外的时延。这种方式对于应用非常友好,应用基本零改动,和语言无关,可以通过连接共享减少连接数消耗。

ShardingSphere-JDBC
ShardingSphere-JDBC 是 ShardingSphere 的第一个产品,也是 ShardingSphere 的前身,业界经常简称之为 Sharding-JDBC。它定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。它使用客户端直连数据库,以 Jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
- 适用于任何基于 JDBC 的 ORM 框架,如:JPA、Hibernate、Mybatis、Spring JDBC Template 或直接使用 JDBC。
- 支持任何第三方的数据库连接池,如:C3P0、DBCP、Druid、HikariCP、BoneCP 等。
- 支持任意实现 JDBC 规范的数据库,目前支持 MySQL、PostgreSQL、Oracle、SQL Server 以及任何可使用 JDBC 访问的数据库。

Dynamic-Datasource
Dynamic-Datasource 是 MyBatis-Plus 官方的读写分离框架。如果数据源较少,场景不复杂,不需要使用多数据源事务,可以选择上述任意一种读写分离方案。如果需要更多特性,又不想引入数据库中间件,可尝试 Dynamic-Datasource,具体的使用方式建议阅读 官方文档一、官方文档二。
优势:
- 项目启动后支持动态增减数据源
- 简化 Druid 和 HikariCp 配置,提供全局参数配置
- 提供自定义数据源来源(默认使用 yml 或 properties 配置)
- 数据源分组,适用于多种场景,包括纯粹多库、读写分离、一主多从、多主多从、混合模式
- 使用 Spel 动态参数解析数据源,如从 session,header 和参数中获取数据源。(多租户架构神器)
- 简单集成 Druid 数据源监控多数据源,简单集成 Mybatis-Plus 简化单表,简单集成 P6sy 格式化 SQL,简单集成 Jndi 数据源
- 使用正则匹配或 Spel 表达式来切换数据源(实验性功能)
- 默认支持通过 @DS 注解来动态选择数据源(代码入侵性强),额外支持使用 MyBatis 插件在 ORM 层实现纯读写分离(代码零入侵性),但两者不能同时使用
- 使用 @DS 注解的时候,支持多层数据源嵌套切换。(一个业务 ServiceA 调用 ServiceB,ServiceB 调用 ServiceC,每个 Service 都是不同的数据源)
劣势
- 不支持多数据源事务(同一个数据源下支持事务),网上绝大多数普通方案(基于 Spring 路由数据源 )也都不能支持
- 如果需要使用到分布式事务,那么架构应该到了微服务化的时候
- 提示:如果项目中只有几个数据库,但是有强烈使用分布式事务的需求,建议还是使用传统方式自己构建多套环境集成 Atomic 这类方案
约定
- 只做切换数据源这件核心的事情,并不限制具体操作,切换了数据源可以做任何 CRUD 操作
- 配置文件中所有以下划线 _ 分割的数据源,首部即为组的名称,相同组名称的数据源会放在一个组下
- 切换数据源即可以是组名,也可以是具体数据源名称,切换时默认采用负载均衡机制切换
- 默认的数据源名称为 master,可以通过 spring.datasource.dynamic.primary 修改
- 方法上的注解优先于类上注解
扩展阅读
MySQL 中间件汇总
MySQL 读写分离与分库分表的中间件有以下这些:
| 名称 | 代码仓库地址 | 简介 |
|---|---|---|
| MySQL-Proxy(Oracle) | MySQL-Proxy | Oracle 早期开源的 MySQL Proxy 项目,功能有限,长期不维护。 |
| MySQL-Router(Oracle) | MySQL-Router | Oracle 官方的 MySQL Router,主要用于 InnoDB Cluster、复制拓扑路由。 |
| Atlas(奇虎 360) | Atlas | 360 开源的 MySQL Proxy 中间件,主要用于读写分离、简单分表,不支持复杂的分库分表场景,早期被广泛使用,但已停止维护。 |
| DBProxy(美团点评) | DBProxy | 在奇虎 360 公司开源的 Atlas 基础上,修改了部分 Bug,并且添加了很多特性,目前只支持 MySQL(Percona)5.5 和 5.6,项目已停止维护。 |
| TDDL(淘宝团队研发) | TDDL | 阿里早期开源的客户端层数据库中间件(Smart Client 模式),已停止维护。 |
| Cobar(阿里巴巴 B2B 部门) | Cobar | 阿里早期开源的分布式数据库中间件,Proxy 方案,已停止维护。 |
| MyCat | MyCat | 基于 Cobar 二次开发的数据库中间件,国内用户较多,但更新速度放缓。 |
| Oceanus(58 同城) | Oceanus | 58 同城开源的 MySQL 中间件,Proxy 方案,分库分表支持。 |
| Heisenberg(百度工程师) | Heisenberg | 百度开源的数据库中间件,支持 MySQL 分库分表,已不活跃。 |
| TSharding(蘑菇街) | TSharding | 蘑菇街工程师白辉开发的分库分表中间件,更新停滞。 |
| Kingshard(金山) | Kingshard | 金山云团队开源的 MySQL Proxy 中间件,支持读写分离。 |
| Sharding-JDBC(当当) | Sharding-JDBC | 当当网开源,后并入 Apache 基金会,发展为 ShardingSphere 生态。 |
| Vitess(Google) | Vitess | Google 开源的云原生分布式数据库中间件,Kubernetes 生态支持完善。 |
| ProxySQL | ProxySQL | 国外流行的高性能 MySQL Proxy 中间件,活跃度高,支持企业生产环境。 |
MySQL 常用解决方案总结
1 | MySQL 复制方案: |
