数据库读写分离解决方案介绍
概述
读写分离要做的事情就是决定一条 SQL 该到哪个数据库去执行,至于谁来做决定数据库这件事,要么数据库中间件去做,要么应用程序自己去做。首先针对应用程序自己去做的场景,读写分离的职责应该属于数据访问层而不是业务层,其次读写分离不应该入侵到代码中。因此在 Service—DAO—ORM— 数据库驱动的调用链中,要想做到代码弱入侵性或者零入侵性,只能将读写分离写在 ORM 层或者数据库驱动层,写在 ORM 层就和具体 ORM 框架耦合,写在数据库驱动层,就和具体数据库耦合。至于在 ORM 层还是在数据库驱动层实现读写分离,主要看更换 ORM 框架和数据库哪个成本更高和实现的难易程度。一般来讲,读写分离的核心方案主要有以下几种:
- 第一种构建多套环境,优势是方便控制也容易集成一些简单的分布式事务,缺点是非动态同时代码量较多,配置难度大;
- 第二种是依靠数据库中间件(例如:MyCat),由中间件做读写分离,优势是对整个应用程序都是透明的,缺点是降低性能,不支持多数据源事务;
- 第三种是应用程序自己去做,例如使用支持读写分离的数据库驱动、使用 Spring 原生提供的 AbstractRoutingDataSource。后者需要控制只读事务和读写事务切换到主库,写操作切换到主库,读操作切换到从库;同时保证单个事务里面所有的 SQL 都是在同一个数据源里执行。缺点是多数据源的配置不灵活,不支持多数据源事务。具体实现方式可参考 基于 Service 层的 Spring 路由数据源 + AOP / Annotation、基于 ORM 层的 Spring 路由数据源 + Mybatis 插件 / Annotation。
读写分离解决方案
客户端解决方案
方案概述
客户端解决方案(持久化层)
: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、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-Router(Oracle)
- Atlas (Qihoo 360)
- Atlas-sharding (Qihoo 360)
- Cobar(是阿里巴巴 B2B 部门开发)
- MyCat(基于阿里开源的 Cobar 产品而研发)
- TDDL Smart Client 的方式(淘宝)
- Oceanus(58 同城数据库中间件)
- OneProxy(原支付宝首席架构师楼方鑫开发)
- Vitess(谷歌开发的数据库中间件)
- Heisenberg(百度)
- TSharding(蘑菇街白辉)
- xx-dbproxy(金山的 Kingshard、当当网的 Sharding-Jdbc )
- ProxySQL(国外开源的 MySQL 中间件)
- amoeba
MySQL 常用解决方案总结
1 | MySQL 复制方案: |