MyBatisPlus
+ShardingSphereJDBC
进行读写分离,以及利用MySQL
进行一主一从的主从复制。具体步骤包括:MySQL
主从复制环境准备(Docker
)ShardingShpereJDBC
+MyBatisPlus
+Druid
环境OpenJDK 17.0.3
Spring Boot 2.7.0
MyBatis Plus 3.5.1
MyBatis Plus Generator 3.5.2
Druid 1.2.10
ShardingSphereJDBC 5.1.1
MySQL 8.0.29
(Docker
)MySQL
上实现,相信会不如一台MySQL
写,另外两台MySQL
读这样的配置性能高。另一方面,在很多时候都是读操作的请求要远远高于写操作,这样就显得读写分离非常有必要了。MySQL
,这里就说一下MySQL
主从复制的原理,如下图所示:
工作流程如下:binlog
I/O
线程读取主库的binlog
,并拷贝到从库本地的binlog
中binlog
被SQL
线程读取,执行其中的内容并同步到从库中SQL
进行必要的操作,比如读写分离选择走主库还是从库,分库分表select
后如何聚合结果。优点是实现简单,天然去中心化,缺点是支持语言较少,版本升级困难Cobar
:阿里开源的关系型数据库分布式服务中间件,已停更DRDS
:脱胎于Cobar
,全称分布式关系型数据库服务
MyCat
:开源数据库中间件,目前更新了MyCat2
版本Atlas
:Qihoo 360
公司Web
平台部基础架构团队开发维护的一个基于MySQL
协议的数据中间层项目,同时还有一个NoSQL
的版本,叫Pika
tddl
:阿里巴巴自主研发的分布式数据库服务Sharding-JDBC
:ShardingShpere
的一个子产品,一个轻量级Java
框架MySQL
主从复制环境准备MySQL
主从复制的环境,基于Docker
+MySQL
官方文档搭建。docker pull mysql docker run -itd -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name master mysql docker exec -it master /bin/bash 在主库中进行更新镜像源,安装
vim
以及net-tools
的操作:cd /etc/apt echo deb http://mirrors.aliyun.com/debian/ buster main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib deb http://mirrors.aliyun.com/debian-security buster/updates main deb-src http://mirrors.aliyun.com/debian-security buster/updates main deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib > sources.list apt update && apt upgrade apt install vim net-tools
vim /etc/mysql/my.cnf 添加下面两行数据:
[mysqld] server-id=1 # 全局唯一,取值[1,2^32-1],默认为1 binlog-do-db=test # 表示需要复制的是哪个库 修改完成后重启。
CREATE DATABASE test; USE test; CREATE TABLE user( id BIGINT PRIMARY KEY, name VARCHAR(30) NOT NULL, );
mysql_native_password
,否则会导致从库一直处于连接状态:CREATE USER 'repl'@'172.17.0.3' IDENTIFIED WITH mysql_native_password BY '123456'; GRANT REPLICATION slave ON *.* TO 'repl'@'172.17.0.3'; 具体的地址请根据从库的地址修改,可以先看后面的从库配置部分。
FLUSH TABLES WITH READ LOCK; 开启主库的另一个终端,使用
mysqldump
导出:mysqldump -u root -p --all-databases --master-data > dbdump.db 导出完成后,解除读锁:
UNLOCK TABLES;
SHOW MASTER STATUS;
需要把
File
以及Position
记录下来,后面从库的配置需要用到。docker pull mysql docker run -itd -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --name slave mysql docker exec -it slave /bin/bash 进入容器后,像主库一样更新源然后安装
vim
和net-tools
:cd /etc/apt echo deb http://mirrors.aliyun.com/debian/ buster main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib deb http://mirrors.aliyun.com/debian-security buster/updates main deb-src http://mirrors.aliyun.com/debian-security buster/updates main deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib > sources.list apt update && apt upgrade apt install vim net-tools
vim /etc/mysql/my.cnf 添加如下两行:
[mysqld] server-id=2 # 全局唯一,不能与主库相同 replicate-do-db=test # 与主库相同,表示对该库进行复制 修改完成后重启。
ip
地址ip
地址,用于给主库设置同步的用户:ifconfig 输出:
inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255 那么主库中用于复制的用户就可以是
repl@172.17.0.3
。mysqldump -u root -p --all-databases < dbdump.db
CREATE DATABASE test; USE test; CREATE TABLE user( id BIGINT PRIMARY KEY, name VARCHAR(30) NOT NULL, );
change master to
/change replication source to
(8.0.23+
)命令:CHANGE REPLICATION SOURCE TO source_host='172.17.0.2', # 可以使用ifconfig查看主库ip source_user='repl', # 之前主库创建的用户 source_password='123456', # 密码 source_log_file='binlog.000003', # 之前在主库上使用show master status查看的日志文件 source_log_pos=594; # 同样使用show master status查看
START SLAVE; SHOW SLAVE STATUSG 新版本(
8.0.22+
)可使用:START REPLICA; SHOW REPLICA STATUSG 需要
IO
和SQL
线程显示Yes
才算成功:
INSERT INTO user VALUES(1,"name",3); 然后从库就能
select
到了:
Spring Boot
环境Spring Boot
项目,并引入如下依赖:implementation 'com.alibaba1.2.10' implementation 'com.baomidou3.5.1' implementation 'org.freemarker2.3.31' implementation 'com.baomidou3.5.2' implementation 'org.apache.shardingsphere5.1.1'
Maven
版本:<dependency> <groupId>com.baomidougroupId> <artifactId>mybatis-plus-boot-starterartifactId> <version>3.5.1version> dependency> <dependency> <groupId>com.baomidougroupId> <artifactId>mybatis-plus-generatorartifactId> <version>3.5.2version> dependency> <dependency> <groupId>org.freemarkergroupId> <artifactId>freemarkerartifactId> <version>2.3.31version> dependency> <dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.2.10version> dependency> <dependency> <groupId>org.apache.shardingspheregroupId> <artifactId>sharding-jdbc-spring-boot-starterartifactId> <version>5.1.1version> dependency>
import com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; public class Generator { public static void main(String[] args) { FastAutoGenerator.create("jdbc//localhost:3306/test", "root", "123456") .globalConfig(builder -> builder.author("author").outputDir(System.getProperty("user.dir") + "/src/main/java").build()) .packageConfig(builder -> builder.parent("com.example.demo").moduleName("user").build()) .strategyConfig(builder -> builder.addInclude("user").entityBuilder().enableLombok().disableSerialVersionUID().build()) .templateEngine(new FreemarkerTemplateEngine()) .execute(); } } 直接运行
main
方法即可生成代码,配置请根据个人需要进行更改。spring: shardingsphere: mode: type: Memory # 内存模式,元数据保存在当前进程中 datasource: names: master,slave # 数据源名称,这里有两个 master: # 跟上面的数据源对应 type: com.alibaba.druid.pool.DruidDataSource # 连接池 url: jdbc//127.0.0.1:3306/test # 连接url username: root password: 123456 slave: # 跟上面的数据源对应 type: com.alibaba.druid.pool.DruidDataSource url: jdbc//127.0.0.1:3306/test username: root password: 123456 rules: readwrite-splitting: # 读写分离规则 data-sources: # 数据源配置 random: # 这个名字随便起 type: Static # 静态类型 load-balancer-name: round_robin # 负载均衡算法名字 props: write-data-source-name: master # 写数据源 read-data-source-names: slave # 读数据源 load-balancers: # 负载均衡配置 round_robin: # 跟上面负载均衡算法的名字对应 type: ROUND_ROBIN # 负载均衡算法 props: sql-show: true # 打印SQL 因为配置文件的内容比较多,以下进行分开说明。
spring.shardingsphere.mode.type
,模式有三种:Memory
:内存模式,初始化配置或执行SQL
等操作均在当前进程生效Standalone
:单机模式,可以将数据源和规则等元数据信息持久化,但是这些元数据不会在集群中同步Cluster
:集群模式,提供了多个Apache ShardingSphere
实例之间元数据共享以及分布式场景下的状态协调的能力,也提供水平扩展以及高可用的能力spring.shardingsphere.mode.type=Standalone
:设置单机模式spring.shardingsphere.mode.repository.type=
:持久化仓库的类型,单机模式适用类型为File
spring.shardingsphere.mode.repository.props.path=
:元数据存储路径,默认.shardingsphere
spring.shardingsphere.mode.overwrite=
:是否覆盖spring.shardingsphere.mode.type=Cluster
:设置集群模式spring.shardingsphere.mode.repository.type=
:持久化仓库类型,集群模式支持ZooKeeper
以及Etcd
持久化spring.shardingsphere.mode.repository.props.namespace=
:注册中心命名空间spring.shardingsphere.mode.repository.props.server-lists=
:注册中心服务器列表spring.shardingsphere.mode.overwrite=
:是否覆盖spring.shardingsphere.mode.repository.props.=
:注册中心的属性配置,对于ZooKeeper
,可以配置retryIntervalMilliseconds
(重试间隔毫秒)、maxRetries
(客户端连接最大重试数)、timeToLiveSeconds
(临时数据存活秒数)、operationTimeoutMilliseconds
(客户端操作超时毫秒数)、digest
(登录密码),对于Etcd
,可以配置timeToLiveSeconds
(临时数据存活秒数)、connectionTimeout
(连接超时秒数)spring.shardingsphere.datasource.names
,后面接数据源的名称,使用,
分隔,比如此处有两个数据源:master
slave
type
:数据库连接池类型,这里使用的是Druid
username
:用户名password
:密码jdbc-url
:连接url
,注意,对于此处使用的Druid
连接池,需要使用url
而不是jdbc-url
spring.shardingsphere.rules.readwrite-splitting
,需要配置其中的数据源以及负载均衡类型:spring.shardingsphere.rules.readwrite-splitting.data-sources
spring.shardingsphere.rules.readwrite-splitting.load-balancers
random
,然后需要配置三个属性:spring.shardingsphere.rules.readwrite-splitting.data-sources.random.type
:读写分离的类型,可选值为Static
与Dynamic
,这里选择Static
,如果选择Dynamic
,也就是动态数据源,请配合dynamic-datasource-spring-boot-starter
使用spring.shardingsphere.rules.readwrite-splitting.data-sources.random.props.write-data-source-name
:写数据源spring.shardingsphere.rules.readwrite-splitting.data-sources.random.props.read-data-source-name
:读数据源spring.shardingsphere.rules.readwrite-splitting.data-sources.random.load-balancer-name
:负载均衡算法的名称,这里写的是round_robin
spring.shardingsphere.rules.readwrite-splitting.data-sources.random.load-balancer-name
属性对应,比如这里是round_robin
,那么需要配置的就是spring.shardingsphere.rules.readwrite-splitting.load-balancers.round_robin
。然后下一步就是配置具体的负载均衡算法。内置的负载均衡算法有三个:ROUND_ROBIN
,配置type=ROUND_ROBIN
即可,也就是spring.shardingsphere.rules.readwrite-splitting.load-balancers.round_robin.type=ROUND_ROBIN
RANDOM
,配置type=RANDOM
WEIGHT
,配置type=WEIGHT
,同时需要配置props
,在其中配置各个读节点的权重spring.shardingsphere.props.sql-show=true
,也就是打印SQL
,其他支持的属性有:spring.shardingsphere.props.sql-simple
:是否打印简单风格的SQL
,默认为false
spring.shardingsphere.props.kernel-exector-size
:设置任务处理线程池大小,默认为infinite
spring.shardingsphere.props.max-connections-size-per-query
:每次查询所能使用的最多数据库连接数,默认为1
spring.shardingsphere.props.check-table-metadata-enabled
:启动时是否检查分片元数据的一致性,默认为false
spring.shardingsphere.props.check-duplicate-table-enabled
:启动时是否检查重复表,默认为false
spring.shardingsphere.props.sql-federation-enabled
:是否开启联邦查询,默认为false
Controller
@RestController @RequestMapping("/user") @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class UserController { private final UserServiceImpl userService; @GetMapping("/select") public User select() { return userService.getById(1); } @GetMapping("/insert") public boolean insert() { return userService.saveOrUpdate(User.builder().id(3L).name("name3").build()); } }
http://localhost:8080/user/insert
,可以看到写操作在主库进行:访问http://localhost:8080/user/select
,可以看到读操作在从库进行:这样读写分离就算是完成了。
全部0条评论
快来发表一下你的评论吧 !