这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战
前言
写这篇博客纯属玩耍,如果有不对的地方,大家看看就好。目前后台的分库分表领域两个标志性的中间件就是sharding jdbc和mycat,今天咱就来分别搭一下,看看都怎么玩。如果你以面试为目的的话,这篇文章应该不是很适合,如果你项目中最近后台架构要改为分库分表,那么这篇文章能使你快速的搭建起来一个分库分表的框架。 玩耍开始。
数据库准备
我准备的数据库是mysql,版本是5.7.35,太老的版本不支持主从复制,建议5.6版本以上大家自行下载即可。如果你安装的是比较新的版本,安装过程中可能会出现这个错误
是因为新版本对密码的校验比较严格,只需要返回上一步重新输入密码重新check,让ckeck不通过一下然后在输入通过的密码就可以了,在回到这一步就应该能通过了。
数据库主从同步
安装完数据库之后咱得搞一套主从同步的机制,因为sharding jdbc只能路由到主库和从库,并不能实现主从数据的同步,主从的同步机制还是得依靠mysql自身的机制。开始搞。
1 新增mysql实例
因为我主从全都在本机所以我复制了一份mysql文件如下图所示
然后修改my.ini文件,然后你会发现目录下并没有my.ini文件
这就很尴尬了是吧,网上10个有9个半的主从复制都是目录下有my.ini文件的,不要急,这么整,因为新版本的mysql他的my.ini文件默认已经不在文件目录下了,在哪呢? 在这
但是这个ProgramData文件是隐藏的,所以你得设置一下隐藏文件可见。ok 咱复制一份含有ini文件的目录,如下
取名为MySQL Server 5.7s1 和主库做一个区分,然后修改以下从库的my.ini文件
prot = 3307
basedir="C:/Program Files/MySQL/MySQL Server 5.7s1/"
datadir=C:/ProgramData/MySQL/MySQL Server 5.7s1/Data
修改完后把从库安装为windows服务,命令如下
然后就能在服务列表中看到了
2 修改主库从库的ini文件,新增如下内容
一、 主库
#开启日志
log-bin=mysql-bin
#服务id 主从不能一致
server-id=1
#需要同步的数据库
binlog_do_db=ds0
binlog_do_db=ds1
二、从库
#开启日志
log-bin=mysql-bin
#服务id 主从不能一致
server-id=2
#需要同步的数据库
replicate_wild_do_table=ds0.%
replicate_wild_do_table=ds1.%
然后重新启动主库和从库
三、主从复制授权账号
登录主库后执行授权命令
grant replication slave on . to myslave@localhost identified by 'myslave';
然后刷新权限
FLUSH PRIVILEGES;
然后看以下文件名和位点
show master status;
显示如下
记录一下file和position,配置从库的时候会用到。
四、设置从库同步主库数据
#先停止从库
stop slave;
#修改从库指向主库
change master to
master_host='localhost',
master_user='myslave',
master_password='myslave',
master_log_file='mysql-bin.000006',
master_log_pos=15626542;
#启动
start slave;
#查看从库状态
show slave status;
显示如下
当看见两个都是yes的时候就是主从同步成功了。如果你们从库是复制的主库的话这里的Slave_IO_Running应该为No,只需要把从库的Data下面的auto.cnf中的uuid改为和主库不一样就行了,如下
sharding-jdbc
数据库主从同步搭完了接下来开始搞sharding-jdbc。
一、springboot整合sharding-jdbc
1.新建一个springboot工程,然后加入sharding-jdbc的jar包,具体pom文件如下所示
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>liuxc-jdbc</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/sharding-jdbc-core -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
项目的结构大致为
要想使用sharding-jdbc,主要的一个工作就是配置分片规则,在配置分片规则之前我先创建一些库表,如图我在主库和从库中分别创建了两个库ds0和ds1,每个库中的表都是t_user1和t_user2
然后配置sharding-jdbc分片规则,在application.properties中进行配置
server.port=8080
spring.application.name=sharding-springboot
mybatis.mapper-locations=classpath:mapper/*.xml
spring.shardingsphere.datasource.names= m1,m2,s1,s2
spring.shardingsphere.datasource.m1.type= com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name= com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url= jdbc:mysql://localhost:3306/ds0
spring.shardingsphere.datasource.m1.username= root
spring.shardingsphere.datasource.m1.password= root
spring.shardingsphere.datasource.s1.type= com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s1.driver-class-name= com.mysql.jdbc.Driver
spring.shardingsphere.datasource.s1.url= jdbc:mysql://localhost:3307/ds0
spring.shardingsphere.datasource.s1.username= root
spring.shardingsphere.datasource.s1.password= root
spring.shardingsphere.datasource.m2.type= com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name= com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m2.url= jdbc:mysql://localhost:3306/ds1
spring.shardingsphere.datasource.m2.username= root
spring.shardingsphere.datasource.m2.password= root
spring.shardingsphere.datasource.s2.type= com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s2.driver-class-name= com.mysql.jdbc.Driver
spring.shardingsphere.datasource.s2.url= jdbc:mysql://localhost:3307/ds1
spring.shardingsphere.datasource.s2.username= root
spring.shardingsphere.datasource.s2.password= root
#主库从库
spring.shardingsphere.sharding.master-slave-rules.ds1.master-data-source-name=m1
spring.shardingsphere.sharding.master-slave-rules.ds1.slave-data-source-names=s1
spring.shardingsphere.sharding.master-slave-rules.ds2.master-data-source-name=m2
spring.shardingsphere.sharding.master-slave-rules.ds2.slave-data-source-names=s2
# 库配置分片键和分片算法
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2+1}
# 表配置分片键和分片算法
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ds$->{1..2}.t_user$->{1}
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user$->{1}
spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE
spring.shardingsphere.props.sql.show=true
logging.level.root=info
logging.level.org.springframework.web=info
m1、m2对应主库的ds0、ds1。 s1、s2对应从库的ds0、ds1。 主要介绍下主从的配置和分库分表的配置
#用master-data-source-name和slave-data-source-names来标明是主库和从库
spring.shardingsphere.sharding.master-slave-rules.ds1.master-data-source-name=m1
spring.shardingsphere.sharding.master-slave-rules.ds1.slave-data-source-names=s1
spring.shardingsphere.sharding.master-slave-rules.ds2.master-data-source-name=m2
spring.shardingsphere.sharding.master-slave-rules.ds2.slave-data-source-names=s2
# 库配置分片键和分片算法
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2+1}
其中ds$->{user_id % 2+1} 一种groovy语法 user_id为偶数 结果就是ds1,基数就为ds2,注意其中的ds1或ds2指的是如下的逻辑节点
分表的配置
# 表配置分片键和分片算法
#指定表的分布情况,配置数据节点 目前只指点了一个表t_user1,要想指定t_user1和t_user2只需要
t_user$->{1..2}即可
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ds$->{1..2}.t_user$->{1}
#指定表的分片键和分片算法
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.t_user.tablestrategy.inline.algorithm-expression=t_user$->{1}
#指定表的主键生成策略为雪花算法
spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE
ok配置介绍完了,咱写个插入的方法,然后启动项目,看看效果,插入的方法如下
注意一点 sql中的表名必须是逻辑表名,即为这个
然后咱们浏览器访问下看看
显示成功,咱去数据库看看
发现user_id为偶数的都在ds0的t_user1表中,user_id为奇数的都在ds1的t_user1表中,日志中也能看出数据全部插入了主库
然后咱写一个查询的方法看看是不是从从库查出来的,偷个懒直接从主库中取一个id查询
@RequestMapping("/getUser")
@ResponseBody
public User getUser() {
User user = userMapper.get(633690716052127744l);
return user;
}
看日志,说明是从从库查询的
那说明咱们的sharding-jdbc 主从复制、读写分离就成功了,其实还有好知识点没涉及到,就像分片策略我们这里用的是inline,在之前的东家那里做医疗电商的时候我们用的是complex 复合分片策略的等等,每种策略的特点和用法等等,具体的大家就自行去学习吧。
mycat
1 下载mycat
下载mycat之前需要确保安装jdk1.7以上版本,然后从官网下载mycat,下载后解压如下
主要看conf下的三个文件
1.server.xml
下载下来后,应该默认如上图,有一个逻辑库,名字为TESTDB,有两个用户,root和user,默认即可
2.schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- auto sharding by id (long) rule="auto-sharding-long" -->
<table name="t_user1" primaryKey="user_id" dataNode="dn1,dn2" rule="crc32slot"/>
<table name="t_user2" primaryKey="user_id" dataNode="dn1,dn2" rule="crc32slot1"/>
</schema>
<dataNode name="dn1" dataHost="localhost1" database="ds0" />
<dataNode name="dn2" dataHost="localhost1" database="ds1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root"
password="root">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="localhost:3307" user="root" password="root" />
</writeHost>
</dataHost>
</mycat:schema>
上部分定义了表名、主键、分布节点和分片算法,下部分定义了读写的路由。这个大家一看就懂就不再赘述了。
3.rule.xml 该文件主要是定义分片规则,上面的crc32slot规则就是这个文件里面定义的,这里需要注意的点是如果有表用了这个方法那么就不能在用了,需要复制一份改个名字在用,就像下面这样
启动mycat
管理员身份在bin目录下运行
mycat.bat install
查看服务列表
然后用navicat登录一下 用户名 密码就是server.xml里面配置的
登录mycat
执行以下看看效果,在mycat中新增一条数据
发现它插入了主库的ds0里面的t_user1
再插入一条
发现在ds1中多了一条
说明咱搞的mycat的分库分表没啥问题,mycat这部分其实写的比较笼统,准备的好多点都没有写进去,像balance赋值 0,1,2,3的各种区别等等 。主要是篇幅太长了,而且最后我还想用jmeter再来各自测以下着两种数据中间件,想深入研究的朋友们自己去学习吧。springboot集成mycat的话其实只需要把数据源换成mycat的就行如图
最后咱们用jmeter压一下这两种方式
sharding-jdbc
100个线程数循环10次,方法中每次插入10条数据,总共插入10000条数据,来咱试试
ds0中是4992条
ds1中是5008条
吞吐量在116左右
mycat
吞吐量在60多
总结
哈哈看到这的都是帅仔。从测试数据来看mycat比sharding-jdbc还是差点,当然这和服务器的配置有很大关系,你们测的话可能就不一样了啊,我只是按照我测试的数据来说的,其实写这篇文章主要就是为了玩,所以大家不要太较真。接下来的计划是每周更一篇,下篇写啥还没想好,下周见吧