数据库读写分离解决方案介绍

概述

读写分离要做的事情就是决定一条 SQL 该到哪个数据库去执行,至于谁来做决定数据库这件事,要么数据库中间件去做,要么应用程序自己去做。首先针对应用程序自己去做的场景,读写分离的职责应该属于数据访问层而不是业务层,其次读写分离不应该入侵到代码中。因此在 Service—DAO—ORM— 数据库驱动的调用链中,要想做到代码弱入侵性或者零入侵性,只能将读写分离写在 ORM 层或者数据库驱动层,写在 ORM 层就和具体 ORM 框架耦合,写在数据库驱动层,就和具体数据库耦合。至于在 ORM 层还是在数据库驱动层实现读写分离,主要看更换 ORM 框架和数据库哪个成本更高和实现的难易程度。一般来讲,读写分离的核心方案主要有以下几种:

  • 第一种构建多套环境,优势是方便控制也容易集成一些简单的分布式事务,缺点是非动态同时代码量较多,配置难度大;
  • 第二种是依靠数据库中间件(例如:MyCat),由中间件做读写分离,优势是对整个应用程序都是透明的,缺点是降低性能,不支持多数据源事务;
  • 第三种是应用程序自己去做,例如使用支持读写分离的数据库驱动、使用 Spring 原生提供的 AbstractRoutingDataSource。后者需要控制只读事务和读写事务切换到主库,写操作切换到主库,读操作切换到从库;同时保证单个事务里面所有的 SQL 都是在同一个数据源里执行。缺点是多数据源的配置不灵活,不支持多数据源事务。具体实现方式可参考 基于 Service 层的 Spring 路由数据源 + AOP / Annotation基于 ORM 层的 Spring 路由数据源 + Mybatis 插件 / Annotation

数据库中间件介绍

读写分离、分库分表中间件通常分为 Proxy 层和 Client 层两种类型,不同中间件的优缺点如下。

读写分离中间件

  • TDDL

    • 出身:淘宝团队研发,大概在 2008 年左右就在淘宝内部投入使用,是一种 Client 层方案。
    • 状态:目前已很久未更新,已几乎被废弃,不建议使用。
    • 优势:支持基本 CRUD 操作和读写分离。
    • 局限:不支持 JOIN 和多表查询,依赖淘宝内部的 Diamond 配置系统,社区采用不多,适用性有限。
  • Atlas

    • 出身:奇虎 360 开源,是一种 Proxy 层方案。
    • 状态:目前已很久未更新,已几乎被废弃,不建议使用。
    • 局限:功能上较为简单,仅支持 MySQL 协议代理,主要实现读写分离、简单分表,不支持复杂的分库分表场景。
  • DBProxy

    • 出身:由美团点评公司的 DBA 团队开发维护,是在 Atlas(奇虎 360)的基础上改造 / 重构而来。
    • 状态:在美团内部广泛用于生产环境,功能较为成熟、稳定,但是目前已很久未更新,已几乎被废弃,不建议使用。
    • 局限:仅支持 MySQL(Percona 5.5 / 5.6)的读写分离;虽然支持「分表 (Table‑Sharding)」,但「分库 (DataBase‑Sharding)」功能仍是 “正在内测中 / 不完善”,对于复杂的大规模分库分表、跨库事务、动态扩容 / 迁移等场景支持有限。
  • ProxySQL

    • 出身:国外开源社区开发,专注于高性能 MySQL 代理,是一种 Proxy 层方案。
    • 优势:支持读写分离、负载均衡、查询路由、连接池、查询缓存等功能;部署灵活,性能高,可支持高并发场景;多语言客户端透明接入。
    • 局限:需要额外部署和运维中间件,网络跳转会带来一定延迟;对复杂分库分表逻辑需要额外配置,学习成本相对较高;社区活跃度高,但中文文档和案例相对少。
  • Vitess

    • 出身:Google 开发,用于构建云原生、水平可扩展的分布式数据库系统,主要是 Proxy/Cluster 层方案。
    • 优势:支持主从分离的读写分离,提供分库分表(水平切分)能力,透明处理 SQL 分布式查询,支持事务;适合大规模、高并发 MySQL 场景;云原生友好,可与 Kubernetes 等集群管理系统集成。
    • 局限:架构相对复杂,需要额外的运维和学习成本;主要面向大规模场景,对小型项目可能过于重量级;部分高级功能(如跨分片事务)需要谨慎使用。

分库分表中间件

  • Cobar

    • 出身:阿里巴巴 B2B 团队开发,诞生时间大约在 2009~2010 年,后来在 2012 年开源,是一种 Proxy 层方案。
    • 状态:目前已很久未更新,已几乎被废弃,不建议使用。
    • 局限:不支持读写分离、存储过程、跨库 JOIN、跨库分页等功能。
  • MyCat / MyCat2

    • 出身:基于 Cobar 改造,是一种 Proxy 层方案。
    • 优势:功能全面,支持事务、跨库分片、聚合计算等,不少企业已有应用案例。
    • 局限:社区更新不算频繁,相较 ShardingSphere 较年轻,稳定性和成熟度略逊,最新公开版本发布时间较早。
  • Vitess

    • 出身:Google 开发,用于构建云原生、水平可扩展的分布式数据库系统,主要是 Proxy/Cluster 层方案。
    • 优势:支持主从分离的读写分离,提供分库分表(水平切分)能力,透明处理 SQL 分布式查询,支持事务;适合大规模、高并发 MySQL 场景;云原生友好,可与 Kubernetes 等集群管理系统集成。
    • 局限:架构相对复杂,需要额外的运维和学习成本;主要面向大规模场景,对小型项目可能过于重量级;部分高级功能(如跨分片事务)需要谨慎使用。
  • ShardingSphere

    • 项目源起:
      • 由 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-ProxyOracle 早期开源的 MySQL Proxy 项目,功能有限,长期不维护。
MySQL-Router(Oracle)MySQL-RouterOracle 官方的 MySQL Router,主要用于 InnoDB Cluster、复制拓扑路由。
Atlas(奇虎 360)Atlas360 开源的 MySQL Proxy 中间件,主要用于读写分离、简单分表,不支持复杂的分库分表场景,早期被广泛使用,但已停止维护。
DBProxy(美团点评)DBProxy 在奇虎 360 公司开源的 Atlas 基础上,修改了部分 Bug,并且添加了很多特性,目前只支持 MySQL(Percona)5.55.6,项目已停止维护。
TDDL(淘宝团队研发)TDDL 阿里早期开源的客户端层数据库中间件(Smart Client 模式),已停止维护。
Cobar(阿里巴巴 B2B 部门)Cobar 阿里早期开源的分布式数据库中间件,Proxy 方案,已停止维护。
MyCatMyCat 基于 Cobar 二次开发的数据库中间件,国内用户较多,但更新速度放缓。
Oceanus(58 同城)Oceanus58 同城开源的 MySQL 中间件,Proxy 方案,分库分表支持。
Heisenberg(百度工程师)Heisenberg 百度开源的数据库中间件,支持 MySQL 分库分表,已不活跃。
TSharding(蘑菇街)TSharding 蘑菇街工程师白辉开发的分库分表中间件,更新停滞。
Kingshard(金山)Kingshard 金山云团队开源的 MySQL Proxy 中间件,支持读写分离。
Sharding-JDBC(当当)Sharding-JDBC 当当网开源,后并入 Apache 基金会,发展为 ShardingSphere 生态。
Vitess(Google)VitessGoogle 开源的云原生分布式数据库中间件,Kubernetes 生态支持完善。
ProxySQLProxySQL 国外流行的高性能 MySQL Proxy 中间件,活跃度高,支持企业生产环境。

MySQL 常用解决方案总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
MySQL 复制方案:
1.一主一从,高可用
2.一主一从,读写分离
3.一主多从,读写分离
4.一主多从,负载均衡
5.主主复制,单写
6.主主复制,双写
7.双主双从

MySQL 高性能架构方案:
1.代码级别
2.读写分离架构(读性能较高)
MySQL Proxy(Atlas、MySQL-Router、ProxySQL、MaxScale 等)
3.分布式架构(读写性能都提高)
分库分表--->Cobar--->DRDS
MyCat---->自主研发等
NewSQL--->TiDB

MySQL 高可用架构方案:
单活:MMM架构--->mysql-mmm(Google)
单活:MHA架构--->mysql-master-ha(日本DeNa),T-MHA
多活:MGR 架构 --->mysql 5.7 新特性 MySQL Group Replication(5.7.17)--->Innodb Cluster
多活:
MySQL Cluster(Oracle RAC)
Galera Cluster for MySQL
Percona XtraDB Cluster(PXC)
MariaDB Galera Cluster(MGC)

Oracle 高可用架构方案:
1.RAC
2.DG
3.OGG

其他 MySQL 中间件开源项目

参考文献