windows下sharding jdbc 和 mycat谁更好用?来 咱试试

2,049 阅读7分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

前言


写这篇博客纯属玩耍,如果有不对的地方,大家看看就好。目前后台的分库分表领域两个标志性的中间件就是sharding jdbc和mycat,今天咱就来分别搭一下,看看都怎么玩。如果你以面试为目的的话,这篇文章应该不是很适合,如果你项目中最近后台架构要改为分库分表,那么这篇文章能使你快速的搭建起来一个分库分表的框架。 玩耍开始。

数据库准备


我准备的数据库是mysql,版本是5.7.35,太老的版本不支持主从复制,建议5.6版本以上大家自行下载即可。如果你安装的是比较新的版本,安装过程中可能会出现这个错误

image.png

是因为新版本对密码的校验比较严格,只需要返回上一步重新输入密码重新check,让ckeck不通过一下然后在输入通过的密码就可以了,在回到这一步就应该能通过了。

数据库主从同步


安装完数据库之后咱得搞一套主从同步的机制,因为sharding jdbc只能路由到主库和从库,并不能实现主从数据的同步,主从的同步机制还是得依靠mysql自身的机制。开始搞。

1 新增mysql实例

因为我主从全都在本机所以我复制了一份mysql文件如下图所示

image.png 然后修改my.ini文件,然后你会发现目录下并没有my.ini文件

image.png 这就很尴尬了是吧,网上10个有9个半的主从复制都是目录下有my.ini文件的,不要急,这么整,因为新版本的mysql他的my.ini文件默认已经不在文件目录下了,在哪呢? 在这

image.png 但是这个ProgramData文件是隐藏的,所以你得设置一下隐藏文件可见。ok 咱复制一份含有ini文件的目录,如下

image.png 取名为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服务,命令如下

image.png 然后就能在服务列表中看到了

image.png

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;

显示如下

image.png 记录一下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;

显示如下

image.png

当看见两个都是yes的时候就是主从同步成功了。如果你们从库是复制的主库的话这里的Slave_IO_Running应该为No,只需要把从库的Data下面的auto.cnf中的uuid改为和主库不一样就行了,如下

image.png

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>

项目的结构大致为

image.png

要想使用sharding-jdbc,主要的一个工作就是配置分片规则,在配置分片规则之前我先创建一些库表,如图我在主库和从库中分别创建了两个库ds0和ds1,每个库中的表都是t_user1和t_user2

image.png

然后配置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指的是如下的逻辑节点

image.png 分表的配置

# 表配置分片键和分片算法 
#指定表的分布情况,配置数据节点 目前只指点了一个表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配置介绍完了,咱写个插入的方法,然后启动项目,看看效果,插入的方法如下

image.png 注意一点 sql中的表名必须是逻辑表名,即为这个

image.png

image.png 然后咱们浏览器访问下看看

image.png

显示成功,咱去数据库看看

image.png

image.png

发现user_id为偶数的都在ds0的t_user1表中,user_id为奇数的都在ds1的t_user1表中,日志中也能看出数据全部插入了主库

image.png

然后咱写一个查询的方法看看是不是从从库查出来的,偷个懒直接从主库中取一个id查询

@RequestMapping("/getUser")
@ResponseBody
public User getUser() {
    User user = userMapper.get(633690716052127744l);
    return user;
}

看日志,说明是从从库查询的

image.png 那说明咱们的sharding-jdbc 主从复制、读写分离就成功了,其实还有好知识点没涉及到,就像分片策略我们这里用的是inline,在之前的东家那里做医疗电商的时候我们用的是complex 复合分片策略的等等,每种策略的特点和用法等等,具体的大家就自行去学习吧。

mycat


1 下载mycat

下载mycat之前需要确保安装jdk1.7以上版本,然后从官网下载mycat,下载后解压如下

image.png

主要看conf下的三个文件

image.png

1.server.xml

image.png

下载下来后,应该默认如上图,有一个逻辑库,名字为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规则就是这个文件里面定义的,这里需要注意的点是如果有表用了这个方法那么就不能在用了,需要复制一份改个名字在用,就像下面这样

image.png

启动mycat

管理员身份在bin目录下运行

mycat.bat install

查看服务列表

image.png

然后用navicat登录一下 用户名 密码就是server.xml里面配置的

image.png 登录mycat

image.png

执行以下看看效果,在mycat中新增一条数据

image.png 发现它插入了主库的ds0里面的t_user1

image.png 再插入一条

image.png 发现在ds1中多了一条

image.png 说明咱搞的mycat的分库分表没啥问题,mycat这部分其实写的比较笼统,准备的好多点都没有写进去,像balance赋值 0,1,2,3的各种区别等等 。主要是篇幅太长了,而且最后我还想用jmeter再来各自测以下着两种数据中间件,想深入研究的朋友们自己去学习吧。springboot集成mycat的话其实只需要把数据源换成mycat的就行如图

image.png

最后咱们用jmeter压一下这两种方式


sharding-jdbc

image.png

image.png

100个线程数循环10次,方法中每次插入10条数据,总共插入10000条数据,来咱试试

image.png ds0中是4992条

image.png

ds1中是5008条

image.png

吞吐量在116左右

mycat

image.png

image.png 吞吐量在60多

image.png

总结

哈哈看到这的都是帅仔。从测试数据来看mycat比sharding-jdbc还是差点,当然这和服务器的配置有很大关系,你们测的话可能就不一样了啊,我只是按照我测试的数据来说的,其实写这篇文章主要就是为了玩,所以大家不要太较真。接下来的计划是每周更一篇,下篇写啥还没想好,下周见吧