haha,首先这不是一篇入门Mycat的博客但小编感觉又很入门的博客!这篇博客主要讲解Mycat中数据分片的相关知识,同时小编将会在本机数据库上进行测试验证,图文并茂展示出来。
数据库分区分表,咋一听非常地高大上,总有一种高高在上,望尘莫及的感觉,但小编想说的是,其实,作为一个开发人员,该来的总是会来,该学的东西你还是得学,区别只是时间先后顺序的问题。
一、分区分表
分区就是把一个数据表的文件和索引分散存储在不同的物理文件中。
mysql支持的分区类型包括Range、List、Hash、Key,其中Range比较常用:
RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。
LIST分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。
HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。
KEY分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值。
分表是指在逻辑上将一个表拆分成多个逻辑表,在整体上看是一张表,分表有水平拆分和垂直拆分两种,举个例子,将一张大的存储商户信息的表按照商户号的范围进行分表,将不同范围的记录分布到不同的表中。
二、Mycat 数据分片的种类
Mycat 的分片其实和分表差不多意思,就是当数据库过于庞大,尤其是写入过于频繁且很难由一台主机支撑是,这时数据库就会面临瓶颈。我们将存放在同一个数据库实例中的数据分散存放到多个数据库实例(主机)上,进行多台设备存取以提高性能,在切分数据的同时可以提高系统的整体性。
数据分片是指将数据全局地划分为相关的逻辑片段,有水平切分、垂直切分、混合切分三种类型,下面主要讲下Mycat的水平和垂直切分。有一点很重要,那就是Mycat是分布式的,因此分出来的数据片分布到不同的物理机上是正常的,靠网络通信进行协作。
水平切分
就是按照某个字段的某种规则分散到多个节点库中,每个节点中包含一部分数据。可以将数据水平切分简单理解为按照数据行进行切分,就是将表中的某些行切分到一个节点,将另外某些行切分到其他节点,从分布式的整体来看它们是一个整体的表。
垂直切分
一个数据库由很多表构成,每个表对应不同的业务,垂直切分是指按照业务将表进行分类并分不到不同的节点上。垂直拆分简单明了,拆分规则明确,应用程序模块清晰、明确、容易整合,但是某个表的数据量达到一定程度后扩展起来比较困难。
混合切分
为水平切分和垂直切分的结合。
三、Mycat 垂直切分、水平切分实战
1、垂直切分
上面说到,垂直切分主要是根据具体业务来进行拆分的,那么,我们可以想象这么一个场景,假设我们有一个非常大的电商系统,那么我们需要将订单表、流水表、用户表、用户评论表等分别分不到不同的数据库中来提高吞吐量,架构图大概如下:
由于小编是在一台机器上测试,因此就只有host1这个节点,但不同的表还是依旧对应不同的数据库,只不过是所有数据库属于同一个数据库实例(主机)而已,后期不同主机只需增加
<dataHost>节点即可。
mycat配置文件如下:
server.xml
<user name="root"> <property name="password">root</property> // 对应四个逻辑库 <property name="schemas">order,trade,user,comment</property> </user>
schema.xml
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <!-- 4个逻辑库,对应4个不同的分片节点 --> <schema name="order" checkSQLschema="false" sqlMaxLimit="100" dataNode="database1" /> <schema name="trade" checkSQLschema="false" sqlMaxLimit="100" dataNode="database2" /> <schema name="user" checkSQLschema="false" sqlMaxLimit="100" dataNode="database3" /> <schema name="comment" checkSQLschema="false" sqlMaxLimit="100" dataNode="database4" /> <!-- 四个分片,对应四个不同的数据库 --> <dataNode name="database1" dataHost="localhost1" database="database1" /> <dataNode name="database2" dataHost="localhost1" database="database2" /> <dataNode name="database3" dataHost="localhost1" database="database3" /> <dataNode name="database4" dataHost="localhost1" database="database4" /> <!-- 实际物理主机,只有这一台 --> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="localhost:3306" user="root" password="root"> </writeHost> </dataHost> </mycat:schema>
登陆本机mysql,创建
order,trade,user,comment4个数据库:
create database database1 character set utf8; create database database2 character set utf8; create database database3 character set utf8; create database database4 character set utf8;
执行
bin目录下的
startup_nowrap.bat文件,如果输出下面内容,则说明已经启动mycat成功,如果没有,请检查
order,trade,user,comment4个数据库是否已经创建。
采用下面语句登陆Mycat服务器:
mysql%20-uroot%20-proot%20-P8066%20-h127.0.0.1
在
comment数据库中创建
Comment表,并插入一条数据
上图1处新建一个
Comment表,2处插入一条记录,3处查看记录插入到哪个数据节点中,即
database4。
2、水平切分
server.xml
<user name="root"> <property name="password">root</property> <property name="schemas">TESTDB</property> </user>
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"> <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" /> </schema> <dataNode name="dn1" dataHost="localhost1" database="db1" /> <dataNode name="dn2" dataHost="localhost1" database="db2" /> <dataNode name="dn3" dataHost="localhost1" database="db3" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" 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"> </writeHost> </dataHost> </mycat:schema>
rule.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:rule SYSTEM "rule.dtd"> <mycat:rule xmlns:mycat="http://io.mycat/"> <tableRule name="auto-sharding-long"> <rule> <columns>id</columns> <algorithm>rang-long</algorithm> </rule> </tableRule> <function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong"> <property name="mapFile">autopartition-long.txt</property> </function> </mycat:rule>
conf目录下的
autopartition-long.txt
# range start-end ,data node index# K=1000,M=10000.0-500M=0 500M-1000M=1 1000M-1500M=2
上面的配置创建了一个名为
TESTDB的逻辑库,并指定了需要切分的表
<table>标签,表名为
travelrecord,分区的策略采用
rang-long算法,即根据
id数据列值的范围进行切分,具体的规则在
autopartition-long.txt文件中定义,即
id在
0-500*10000范围内的记录存放在
db1的
travelrecord表中,
id在
500*10000%20-%201000*10000范围内的记录存放在
db2数据库的
travelrecord表中,下面我们插入两条数据,验证是否和分片规则一致。
创建
db1,db2,db3数据库
create database db1 character set utf8; create database db2 character set utf8; create database db3 character set utf8;
登陆Mycat服务器
mysql%20-uroot%20-proot%20-P8066%20-h127.0.0.1
创建
travelrecord表并插入
id等于1,
id等于5000010两条记录
创建数据表后,数据库结构如下:
插入两条记录:
可以看到,
id等于1的记录被插入到
db1中,
id等于5000010的记录被插入到
db2中,那么数据库是否真的是这样呢?
确实是这样的,到此我们就完成了mycat数据库的水平切分,这个例子只是演示按照id列值得范围进行切分,mycat还支持很多的分片算法,如取模、一致性哈希算法、按日期分片算法等等,大家可以看《分布式数据库架构及企业实战----基于Mycat中间件》这本书深入学习。
为什么需要读写分离
至于为什么需要读写分离,在我之前的文章有介绍过了,相信看到这篇文章的人也知道为什么需要读写分离了,当然如果你也需要了解一下,那么欢迎查看我之前的文章 SpringBoot%20Mybatis%20读写分离配置,顺便也可以了解一下怎么通过代码进行读写分离的
MySQL主从复制
主从复制是读写分离的关键,不管通过什么方式进行读写分离,前提就是MySQL有主从复制,当前双机主从也行,但是关键的关键,是要能保证2个库的数据能一致(出掉刚写入主库从库还未能及时反应过来的情况),如果2个库的数据不一致,那么读写分离也有没有任何意义了,具体MySQL怎么做主从复制可以查看我之前的文章 MySQL主从复制搭建,基于日志(binlog)
Mycat读写分离设置
配置Mycat用户
Mycat的用户就跟MySQL用户是同一个意思,主要配置链接到Mycat的用户名以及密码,以及能使用的逻辑库,用户信息主要在server.xml中配置的,具体如下
<?xml version="1.0" encoding="UTF-8"?> <!-- - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. --><!DOCTYPE mycat:server SYSTEM "server.dtd"> <mycat:server xmlns:mycat="http://io.mycat/"> <system> <property name="defaultSqlParser">druidparser</property> <!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议--> <!-- <property name="processorBufferChunk">40960</property> --> <!-- <property name="processors">1</property> <property name="processorExecutor">32</property> --> <!--默认是65535 64K 用于sql解析时最大文本长度 --> <!--<property name="maxStringLiteralLength">65535</property>--> <!--<property name="sequnceHandlerType">0</property>--> <!--<property name="backSocketNoDelay">1</property>--> <!--<property name="frontSocketNoDelay">1</property>--> <!--<property name="processorExecutor">16</property>--> <!-- <property name="mutiNodeLimitType">1</property> 0:开启小数量级(默认) ;1:开启亿级数据排序 <property name="mutiNodePatchSize">100</property> 亿级数量排序批量 <property name="processors">32</property> <property name="processorExecutor">32</property> <property name="serverPort">8066</property> <property name="managerPort">9066</property> <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property> <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> --> </system> <user name="raye"> <property name="password">rayewang</property> <property name="schemas">separate</property> </user> </host> </mycat:server>
其中
<user%20name="raye">定义了一个名为raye的用户,标签user中的
<property%20name="password">rayewang</property>定义了用户的密码,
<property%20name="schemas">separate</property>定义了用户可以使用的逻辑库
配置Mycat逻辑库
Mycat的配置有很多,不过因为我们只是使用Mycat的读写分类的功能,所以用到的配置并不多,只需要配置一些基本的,当然本文也只是会介绍到读写分离相关的配置,其他配置建议读者自己查看一下文档,或者通过其他方式了解,逻辑库是在
schema.xml中配置的
首先介绍Mycat逻辑库中的一些配置标签
schema
schema 标签是用来定义逻辑库的,
schema有四个属性
dataNode,
checkSQLschema,
sqlMaxLimit,
name
dataNode 标签属性用于绑定逻辑库到某个具体的%20database%20上,1.3%20版本如果配置了%20dataNode,则不可以配置分片表,1.4%20可以配置默认分片,只需要配置需要分片的表即可
name是定义当前逻辑库的名字的,方便
server.xml中定义用户时的引用
checkSQLschema当该值设置为%20true%20时,如果我们执行语句select%20*%20from%20separate.users;则%20MyCat%20会把语句修改%20为select%20*%20from%20users;。即把表示%20schema%20的字符去掉,避免发送到后端数据库执行时报(ERROR%201146%20(42S02):%20Table%20‘separate.users’%20doesn’t%20exist)。 不过,即使设置该值为%20true%20,如果语句所带的是并非是%20schema%20指定的名字,例如:select%20*%20from%20db1.users; 那么%20MyCat%20并不会删除%20db1%20这个字段,如果没有定义该库的话则会报错,所以在提供%20SQL语句的最好是不带这个字段。
sqlMaxLimit当该值设置为某个数值时。每条执行的%20SQL%20语句,如果没有加上%20limit%20语句,MyCat%20也会自动的加上所对应的值。例如设置值为%20100,执行select%20*%20from%20users;的效果为和执行select%20*%20from%20users%20limit%20100;相同。设置该值的话,MyCat%20默认会把查询到的信息全部都展示出来,造成过多的输出。所以,在正常使用中,还是建议加上一个值,用于减少过多的数据返回。当然%20SQL%20语句中也显式的指定%20limit%20的大小,不受该属性的约束。需要注意的是,如果运行的%20schema%20为非拆分库的,那么该属性不会生效。需要手动添加%20limit%20语句。
schema标签中有标签
table用于定义不同的表分片信息,不过我们只是做读写分离,并不会用到,所以这里就不多介绍了
dataNode
dataNodedataNode%20标签定义了%20MyCat%20中的数据节点,也就是我们通常说所的数据分片。一个%20dataNode%20标签就是一个独立的数据分片,
dataNode有3个属性:
name,
dataHost,
database。
name定义数据节点的名字,这个名字需要是唯一的,此名字是用于
table标签和
schema标签中引用的
dataHost该属性用于定义该分片属于哪个数据库实例的,属性值是引用%20dataHost%20标签上定义的%20name%20属性
database该属性用于定义该分片属性哪个具体数据库实例上的具体库,因为这里使用两个纬度来定义分片,就是:实例+具体的库。因为每个库上建立的表和表结构是一样的。所以这样做就可以轻松的对表进行水平拆分
dataHost
dataHost是定义真实的数据库连接的标签,该标签在%20mycat%20逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句,
dataHost有7个属性:
name,
maxCon,
minCon,
balance,
writeType,
dbType,
dbDriver,有2个标签
heartbeat,
writeHost,其中
writeHost标签中又包含一个
readHost标签
name唯一标识%20dataHost%20标签,供
dataNode标签使用
maxCon指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的%20writeHost、readHost%20标签都会使用这个属性的值来实例化出连接池的最大连接数
minCon指定每个读写实例连接池的最小连接,初始化连接池的大小
balance 读取负载均衡类型
-
balance="0",%20不开启读写分离机制,所有读操作都发送到当前可用的%20writeHost%20上。
-
balance="1",全部的%20readHost%20与%20stand%20by%20writeHost%20参与%20select%20语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且%20M1%20与%20M2%20互为主备),正常情况下,M2,S1,S2%20都参与%20select%20语句的负载均衡。
-
balance="2",所有读操作都随机的在%20writeHost、readhost%20上分发。
-
balance="3",所有读请求随机的分发到%20wiriterHost%20对应的%20readhost%20执行,writerHost%20不负担读压力
writeType写入负载均衡类型,目前的取值有%203%20种:
-
writeType="0",%20所有写操作发送到配置的第一个%20writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties%20.
-
writeType="1",所有写操作都随机的发送到配置的%20writeHost
dbType 指定后端连接的数据库类型,目前支持二进制的%20mysql%20协议,还有其他使用%20JDBC%20连接的数据库。例如:mongodb、oracle、spark%20等
dbDriver指定连接后端数据库使用的%20Driver,目前可选的值有%20native%20和%20JDBC。使用%20native%20的话,因为这个值执行的%20是二进制的%20mysql%20协议,所以可以使用%20mysql%20和%20maridb。其他类型的数据库则需要使用%20JDBC%20驱动来支持。从%201.6%20版本开始支持%20postgresql%20的%20native%20原始协议。%20如果使用%20JDBC%20的话需要将符合%20JDBC%204%20标准的驱动%20JAR%20包放到%20MYCAT\lib%20目录下,并检查驱动%20JAR%20包中包括如下目录结构的文件:META-INF\services\java.sql.Driver。在这个文件内写上具体的%20Driver%20类名,例如:%20com.mysql.jdbc.Driver。
heartbeat这个标签内指明用于和后端数据库进行心跳检查的语句。例如,MYSQL%20可以使用%20select%20user(),Oracle%20可以使用%20select%201%20from%20dual%20等。%20这个标签还有一个%20connectionInitSql%20属性,主要是当使用%20Oracla%20数据库时,需要执行的初始化%20SQL%20语句就这个放到这里面来。例如:alter%20session%20set%20nlsdateformat='yyyy-mm-dd%20hh24:mi:ss'
writeHost,
readHost这两个标签都指定后端数据库的相关配置给%20mycat,用于实例化后端连接池。唯一不同的是,writeHost%20指定写实例、readHost%20指定读实例,组着这些读写实例来满足系统的要求。%20在一个%20dataHost%20内可以定义多个%20writeHost%20和%20readHost。但是,如果%20writeHost%20指定的后端数据库宕机,那么这个%20writeHost%20绑定的所有%20readHost%20都将不可用。另一方面,由于这个%20writeHost%20宕机系统会自动的检测到,并切换到备用的%20writeHost%20上去,这2个标签属性都一致,拥有
host,
url,
password,
user,
weight,
usingDecrypt等属性
host用于标识不同实例,一般%20writeHost%20我们使用M1,readHost%20我们用S1
url真实数据库的实例的链接地址,如果是使用%20native%20的%20dbDriver,则一般为%20address:port%20这种形式。用%20JDBC%20或其他的dbDriver,则需要特殊指定。当使用%20JDBC%20时则可以这么写:jdbc:mysql://localhost:3306/
user真实数据库实例的链接用户名
password真实数据库实例的链接密码
weight权重%20配置在%20readhost%20中作为读节点的权重,主要用于多台读取的数据库实例机器配置不同的情况,可以根据权重调整访问量
usingDecrypt是否对密码加密默认%200%20否%20如需要开启配置%201,同时使用加密程序对密码加密
注意,readHost是在writeHost标签内的,不是单独的
以下是我的读写分离配置文件
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="separate" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/> <dataNode name="dn1" dataHost="localhost1" database="test" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="192.168.1.126:3307" user="root" password="123456"> <!-- can have multi read hosts --> <readHost host="hostS2" url="192.168.1.126:3308" user="root" password="123456" /> </writeHost> </dataHost></mycat:schema>
前面已经差不多都解释清楚了,因为我只是用的基本的主从复制,所以我的将
dataHost的
balance设置成了3
启动mycat,然后用数据库连接工具连接到mycat,可以测试是否配置成功,最简单的就是通过修改从库的数据,这样方便查看到底是运行到哪个库上面了,另外由于我是基于docker启动的mycat,所以如果是直接在系统中运行的mycat的,可以去看官方文档,看看到底怎么启动mycat
微信公众号【黄小斜】大厂程序员,互联网行业新知,终身学习践行者。关注后回复「Java」、「Python」、「C++」、「大数据」、「机器学习」、「算法」、「AI」、「Android」、「前端」、「iOS」、「考研」、「BAT」、「校招」、「笔试」、「面试」、「面经」、「计算机基础」、「LeetCode」%20等关键字可以获取对应的免费学习资料。
%20 %20 %20 %20 %20 %20 %20 %20 %20 %20






