从零学MyCat(二)MyCat的安装及使用

MyCat的安装及使用

一、MyCat

1.1、环境准备

使用的虚拟机环境是centos6.5
首先准备四台虚拟机,安装好mysql,方便后续做读写分离和主从复制。
安装jdk  [jdk的安装](https://blog.csdn.net/Yangsir_java/article/details/125635555)

1.2、MyCat的安装

从官网下载需要的安装包,并且上传到具体的虚拟机中,我们在使用的时候将包上传到node01这台虚拟机,由node01充当mycat。

下载地址为:http://dl.mycat.org.cn/1.6.7.5/2020-4-10/
解压文件到/usr/local文件夹下
tar -zxvf  Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz -C /usr/local
配置环境变量
vi /etc/profile
添加如下配置信息:
export MYCAT_HOME=/usr/local/mycat
export PATH=$MYCAT_HOME/bin:$PATH:$JAVA_HOME/bin

当执行到这步的时候,其实就可以启动了,但是为了能正确显示出效果,最好修改下mycat的具体配置,让我们能够正常进行访问。

1.3、MyCat的配置及文件解析

进入到/usr/local/mycat/conf目录下,修改该文件夹下的配置文件
1.3.1、修改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/">
	<user name="root" defaultAccount="true">
		<property name="password">123456</property>
		<property name="schemas">TESTDB</property>
		<property name="defaultSchema">TESTDB</property>
	</user>
</mycat:server>

user标签主要用于定义登录mycat的用户和权限。如上面定义用户名和密码均为user,该用户可以访问的schema只有TESTDB。
可以直接修改对应的属性值来修改密码,如果需要同时访问多个schema,则多个schema之间使用英文逗号隔开。

system标签,这个标签的属性与系统配置有关

  • charset属性,配置字符集时一定要保证mycat字符集与数据库字符集的一致性。

  • defaultSqlParser属性: 由于mycat最初是时候Foundation DB的sql解析器,而后才添加的Druid的解析器。所以这个属性用来指定默认的解析器。目前的可用的取值有:druidparser和 fdbparser。使用的时候可以选择其中的一种,目前一般都使用druidparser。mycat1.4之后的版本中fdbparser属性作废

  • defaultSqlParser属性: 由于mycat最初是时候Foundation DB的sql解析器,而后才添加的Druid的解析器。所以这个属性用来指定默认的解析器。目前的可用的取值有:druidparser和 fdbparser。使用的时候可以选择其中的一种,目前一般都使用druidparser。mycat1.4之后的版本中fdbparser属性作废

  • defaultSqlParser属性: 由于mycat最初是时候Foundation DB的sql解析器,而后才添加的Druid的解析器。所以这个属性用来指定默认的解析器。目前的可用的取值有:druidparser和 fdbparser。使用的时候可以选择其中的一种,目前一般都使用druidparser。mycat1.4之后的版本中fdbparser属性作废

  • processorBufferPool属性:该属性指定bufferpool的计算比例。由于每次执行NIO读,写操作都需要使用到buffer,所以mycat初始化时会建立一定长度的buffer池来加快NIO读,写效率,减少建立buffer的时间。mycat中有两个主要的buffer池:BufferPool,ThreadLocalPool。BufferPool使用ThreadLocalPool作为二级缓存,每次从BufferPool中获取时都会优先获取ThreadLocalPool中的buffer值,如果ThreadLocalPool未命中,则会获取BufferPool中的Buffer值。ThreadLocalPool中的Buffer在每个线程内部使用。然而,BufferPool是每个NIOProcessor共享的。

processorBufferPool的默认值为:bufferChunkSize(4096)XprocessorX1000.
processorBufferPoll的总长度为bufferpool与bufferchunk的比。如果bufferpool的长度不是bufferchunk的整数倍,则其总长度为前面计算得出的比值的整数部分加1.
假设系统线程数为4,其他属性为默认值。
bufferpool=409641000
processorBufferPoll=409641000/4096=4000

  • processorBufferLocalPercent属性:该属性用来控制ThreadLocalPool分配pool的比例大小,这个属性默认值是100.线程缓存百分比=bufferlocalpercent/processor.

例如,系统可以同时运行4个线程,使用默认值。根据上面的公式每个线程的百分比是25,最后根据这个百分比可以计算出具体的ThreadLocalPool的长度公式如下:
ThreadLocalPool=线程缓存百分比 X BufferPool长度/100
假设BufferPool的长度为4000,其他保持默认值,则最后每个线程ThreadLocalPool长度为100,即25*4000/100

  • processorExecutor属性: 这个属性主要用于指定NIOProcessor上共享的businessExecutor固定线程池大小。mycat在需要处理一些异步逻辑的时候会把任务提交到这个线程池中。新版本中这个连接池的使用频率不是很大了,可以设置一个较小的值。

  • sequenceHandlerType属性: 指定使用Mycat全局序列的属性。0为本地文件方式,1为数据库方式,2为本地时间戳方式,3为分布式zk ID生成器,4为zk递增ID生成。默认是使用本地文件方式,文件方式主要只是用于测试使用。从1.6增加两种zk的全局ID生成算法。

  • TCP连接相关属性

StandardSocketOptions.SO_RCVBUF
StandardSocketOptions.SO_SNDBUF
StandardSocketOptions.TCP_NODELAY     
以上三个属性衍生出针对前端和后端的TCP属性如下:
frontSocketSoRcvbuf: 默认值为10241024
frontSocketSoSndbuf:默认值为4
10241024 frontSocketNoDelay:默认值为1
backSocketSoRcvbuf:默认值为4
10241024 backSocketSoSndbuf:默认值为10241024
backSocketNoDelay:默认值1

mycat在每次建立前,后端连接都会使用这些参数初始化TCP属性。可以根据系统的实际情况适当地调整这些参数的大小。
  • MySQL连接相关属性:初始化MySQL的前后端连接所涉及的属性如下。

packetHeaderSize: 指定MySQL协议中报文长度,默认值为4个字符。
maxPacketSize:指定MySQL协议可以携带的数据的最大大小,默认值为16MB。
idleTimeout:指定连接的空闲时间的超时长度。如果某个连接的空闲时间超过idleTimeout的值,则该连接将关闭,并回收资源,单位为毫秒,默认为30分钟。
charset:初始化连接字符集,默认是utf8。
txIsolation:初始化连接的事务隔离级别。ru-1,rc-2,rr-3,se-4;这个值取整数,表示对应的隔离级别。
sqlExecuteTimeout:执行SQL语句的超时时间,若SQL语句的执行时间超过这个值,则会直接关闭连接,单位为秒,默认值为300秒。

  • 心跳属性

processorCheckPeriod: 清理NIOProcessor前后端空闲,超时,关闭连接的时间间隔,单位为毫秒,默认为1秒。
dataNodeidleCheckPeriod:对后端连接进行空闲,超时检查的时间间隔,单位毫秒,默认为300秒。
dataNodeHeaderbeatPeriod:对后端连接的所有读,写库发起心跳的间隔时间,单位为毫秒,默认为10秒

  • 服务相关属性 :这里介绍与mycat服务相关的属性,主要影响外部系统对mycat的感知

bindIP: 服务器监听的IP地址,默认为0.0.0.0
serverPort: 定义mycat的使用端口,默认值为8066
managerPort:定义mycat管理端口,默认值为9066

  • fakeMySQLversion属性:mycat使用mysql的通信协议模拟了一个mysql服务器,默认为5.6版本。若非特许,不需要更改,从Mycat1.6开始支持此属性。
  • 分布式事务开关属性: handleDistributedTransaction是分布式事务开关:0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务只涉及全举表,则不过滤);2为不过滤分布式事务,但是记录分布式事务日志。从mycat1.6版本开始支持此属性。
  • useOffHeapForMerge属性: 该属性用于配置是否启用非堆内存处理跨分片结果集,1为开启,0为关闭,mycat从1.6开始支持。
  • 全局表一致性检测: 其原理是通过在全局表中增加_MYCAT_OP_TIME字段来进行一致性检测,为bigint类型。create语句通过mycat执行时会自动添加上该字段,其他情况需要手动添加。1为开启,0为关闭,mycat从1.6版本开始支持。

<property name="useGlobaleTableCheck">0</property>
全局表一致性检测功能的使用说明及步骤如下:
1:在所有全局表中增加一个BIGINT类型的内部列,列名为_mycat_op_time,同时建议在该列添加索引。
2:在对全局表进行crud时,可以将内部列当做不存在,建议不要对内部列进行update,insert等操作,否则会在log日志出现警告语句“不用操作内部列”
3:因为全局表中多了一个内部列,所以在对全局表进行insert时必须带有列名。

  • useSqlStat属性: 开启SQL实时统计,1为开启,0为关闭。
1.3.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" dataNode="dn1">
        </schema>
        <dataNode name="dn1" dataHost="host1" database="msb" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostM1" url="192.168.85.111:3306" user="root"
                                   password="123456">
                        <readHost host="hostS1" url="192.168.85.112:3306" user="root" password="123456"></readHost>
                </writeHost>
        </dataHost>
</mycat:schema>

schema.xml作为mycat中重要的配置文件之一,涵盖了mycat的逻辑库,表,分片规则,分片节点及数据源。schema.xml配置文件中有7个标签。

  • schema标签:schema标签用于定义mycat实例中的逻辑库,mycat可以有多个逻辑库,每个逻辑库都有自己的相关配置。可以使用schema标签来划分这些不同的逻辑库。如果不配置schema标签,所有的表配置,会属于同一个默认的逻辑库。
    逻辑库的概念和mysql数据库中Datebase的概念相同,我们在查询这两个逻辑库中的表的时候,需要切换到该逻辑库下才可以查到所需要的表。
<schema name="TESTDB" checkSQLschema="false" >
.....
</schema>

1 dataNode属性:该属性用于绑定逻辑库到某个具体的database上,如果定义了这个属性,那么这个逻辑库就不能工作在分库分表模式下了。也就是说对这个逻辑库的所有操作会直接作用到绑定的dataNode上,这个schema就可以用作读写分离和主从切换,具体如下配置:

<schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<!—这里不能配置任何逻辑表信息-->
</schema>

那么现在USERDB就绑定到dn1所配置的具体database上,可以直接访问这个database。当然该属性只能配置绑定到一个database上,不能绑定多个dn。

2 checkSQLschema属性:当该值设置为 true 时,如果我们执行语句select * fromTESTDB.travelrecord;则MyCat会把语句修改为select * from
travelrecord;
。即把表示schema的字符去掉,避免发送到后端数据库执行时报**(ERROR 1146 (42S02): Table‘testdb.travelrecord’ doesn’t exist)**不过,即使该值设置为true,如果语句所带的schema名字不是shcema指定的名字,那么mycat不会删除这个schema。

3 sqlMaxlimit属性: 当该值设置为某个数值时。每条执行的sql语句,如果没有加上limit语句,mycat也会自动的加上所对应的值。如果不设置该值,mycat会默认把查询到的信息全部展示处理,造成过多的输出。所以,正常使用中,还是尽量加入该值,用于减少过多的数据返回。如果sql语句中显式指定了limit的大小,不受该属性的约束。需要注意的是,如果运行的schema为非拆分库的,那么该属性不会生效。需要手动添加limit语句。

  • table标签: table标签定义了逻辑表,所有需要拆分的表都需要在这个标签中定义。
<table name="address" primaryKey="autoIndex" rule="sharding-by-murmur" dataNode="dn1,dn2" />

table标签的属性如下:
1 name属性:定义逻辑表的表名,这个名字就如同在数据库中执行create table命令指定的名字一样,同一个schema标签中定义的表名必须是唯一的。
2 dataNode属性: 定义这个逻辑表所属的dataNode,该属性的值需要和dataNode标签中name属性的值相互对应。
3 rule属性:该属性用于指定逻辑表要使用的规则的名字,规则名字在rule.xml中定义,必须与tableRule标签中name属性属性值对应。
4 ruleRequired属性:该属性用于指定表是否绑定分片规则,如果配置为true,但没有配置具体rule的话,程序会报错。
5 primaryKey属性:该逻辑表对应真实表的主键,例如:分片的规则是使用非主键进行分片的,那么在使用主键查询的时候,就会发送查询语句到所有配置的DN上,如果使用该属性配置真实表的主键。难么MyCat会缓存主键与具体DN的信息,那么再次使用非主键进行查询的时候就不会进行广播式的查询,就会直接发送语句给具体的DN,但是尽管配置该属性,如果缓存并没有命中的话,还是会发送语句给具体的DN,来获得数据。
6 type属性:该属性定义了逻辑表的类型,目前逻辑表只有“全局表”和“普通表”两种。 全局表:global。 普通表:不指定该值为global的所有表
7 autoincrement属性:MySQL对于自增长主键使用last_insert_id()是不会返回结果的,只会返回0.所以,只有对定义了自增长主键的表应用last_insert_id()才可以返回主键的值。mycat目前提供了自增长主键功能,但是如果对应的mysql没有定义auto_increment属性,那么mycat层调用last_insert_id()也是不会返回结果的。由于insert操作时没有带入分片键,所以mycat会先取下这个表对应的全局序列,然后赋值给分片键。如果要使用这个功能,则最好配合数据库模式的全局序列。使用autoIncrement="true"指定这个表使用自增长主键,这样mycat才不会抛出“分片键找不到”的异常。这个功能默认是禁用的,值为false。
8 subTables: 使用subTable="t_order$1-2, t_order3"方式添加,目前mycat在1.6版本以后才开始支持分表,并且dataNode在分表条件下只能配置一个,不支持各种条件的join查询。
9 needAddlimit限制:指定表是否需要自动的在每个语句后面添加limit限制,由于使用了分库分表,数据量有时会特别巨大,这时候执行查询语句,如果恰巧又忘记了添加数量限制,那么就会查询所有的数据。所以mycat就自动的为我们加上limit 100.如果,语句中有limit就不会再次添加了。该属性默认值为true。

  • childTable标签: childTable标签用于定义E-R分片的子表,通过标签上的属性与父表进行关联。

name属性 定义子表的表名
joinKey属性: 插入子表的时候会使用这个列的值查找父表存储的数据节点。
parentKey属性:属性指定的值一般为与父表建立关联关系的列名。程序首先获取joinkey的值,再通过parentKey属性指定的列名产生的查询语句,通过执行该语句得到父表存储在那个分片上,从而确定子表存储位置。
primarykey属性: 同table标签
needAddLimit属性: 同table标签

  • dataNode标签: dataNode标签定义了mycat中的数据节点,也就是数据分片。一个dataNode标签就是一个独立的数据分片。
<dataNode name="dn2" dataHost="host02" database="db" />

#使用host02主机上数据实例中db物理数据库,这就组成一个数据分片,使用dn2标识这个分片。

name属性,定义数据节点的名字,这个名字需要是唯一的,我们需要在table标签上应用这个名字,来建立表与分片对应的关系。
dataHonet属性:该属性用于定义该分片属于那个数据库实例,属性值是引用datahost标签定义的name属性。
database属性:该属性用于定义该分片属于那个具体数据库实例上的具体库,因为这里使用两个纬度来定义分片,就是:实例+具体的库。因为每个库上建立的表和表结构是一样的。所以这样做就可以轻松的对表进行水平拆分。

  • dataHost标签: 作为Schema.xml中最后的一个标签,该标签在mycat逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。现在我们就解析下这个标签。一个dataHost标签的属性如下:
 <dataHost name="host1" maxCon="1000" minCon="10" balance="0"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.85.111:3306" user="root"
                                   password="123456">
         	<readHost host="hostS1" url="192.168.85.112:3306" user="root" password="123456"></readHost>
       </writeHost>
</dataHost>
  1. name属性: 唯一标识dataHost标签,供上层标签使用。
  2. macCon属性:指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数。
  3. minCon属性:指定每个读写实例连接池的最小连接,初始化连接池的大小。
  4. balance属性: 负载均衡类型,目前的取值有以下4种。

balance=0: 不开启读写分离,所有读操作都发送到当前可用的writeHost上。
balance=1:全部的readHost与Stand by writeHost都参与select语句的负载均衡,简而言之,当双主双从模式(M1–>S1,M2—>S2,并且M1与M2互为主备)时,在正常情况下,M2,S1和S2都参与select的负载均衡。
balance=2:所有的读操作都随机在writeHost,readHost上分发。
balance=3:所有的读请求都随机分配到writeHost对应的readHost上执行,writeHost不负担读压力,注意balance=3只在mycat1.4之后版本中有效。

  1. writeType属性:负载均衡类型,目前的取值有3种:
  1. writeType=“0”, 所有写操作都发送到可用的writeHost上。
  2. writeType=“1”,所有写操作都随机的发送到readHost。
  3. writeType=“2”,所有写操作都随机的在writeHost、readhost分上发。
  1. dbType属性:指定后端连接的数据库类型,目前支持二进制的mysql协议,还有其他使用JDBC连接的数据库。如mongodb,spark等。
  2. dbDriver属性: 指定连接后端数据库使用的Driver,目前可选的值有native和JDBC。使用native的话,因为这个值执行的是二进制的mysql协议,所以可以使用mysql和maridb。其他类型的数据库则需要使用JDBC驱动来支持。
  3. switchType属性:

-1:表示不自动切换。
1 :默认值,表示自动切换
2:表示基于MySQL主从同步状态决定是否切换,心跳语句: show slave status.
3:表示基于mysql galary cluster的切换机制,适合mycat1.4之上的版本,心跳语句show status like “%esrep%”;

  1. tempReadHostAvailable属性: 如果配置了writehost,下面的readhost依旧可用。
  • heratbeat标签: 这个标签内指明用于和后端数据库进行心跳检查的语句。例如,MYSQL可以使用select user(),Oracle可以使用select 1 from dual等。mycat1.4中主从切换语句必须是show slave status.
  • writeHost标签,readHost标签:这两个标签指定后端数据库的相关配置给mycat,用于实例化后端连接池。唯一不同的是,writeHost指定写实例、readHost指定读实例,组合这些读写实例来满足系统的要求。

在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去。

host属性:用于标识不同的实例,对于writehost,一般使用M1;对于readhost一般使用S1.
url属性:后端实例连接地址,如果使用native的dbDriver,则一般为address:port这种形式,用JDBC或其他的dbDriver,则需要特殊指定。当使用JDBC时则可以这么写:jdbc:mysql://localhost:3306/。
user属性:后端存储实例的用户名。 password属性:后端存储实例的密码
weight属性:在readHost中作为读节点的权重(mycat1.4版本之后才有的)
usingDecrypt属性:同server.xml中。

1.3.3、rule配置文件

rule.xml里面就定义了我们对表进行拆分所涉及到的规则定义。我们可以灵活的对表使用不同的分片算法,或者对表使用相同的算法但具体的参数不同。这个文件里面主要有tableRule和function这两个标签。在具体使用过程中可以按照需求添加tableRule和function。

<tableRule name=rule>
	<rule>
		<columns>id</columns>
		<algorithm>func1</algorithm>
	</rule>
</tableRune>
  • tableRule标签: 这个标签定义表规则。定义的表的规则在schema.xml中引用。

name属性指定唯一的名字,用于标识不同的表规则,内嵌的rule标签则指定对物理表中的那一列进行拆分和使用什么路由算法。columns内指定要拆分的列名字。
algorithm使用function标签中的name属性。连接表规则和具体路由算法。当然,多个表规则可以连接到同一个路由算法上。

  • function标签:
<function name="crc32" class="io.mycat.route.function.PartitonByCRC32reSlot">
	<property name="count">2</property> -- 要分片的数据库节点数量,必须指定否则没法分片
</function>

name指定算法的名字。
class指定路由算法具体的类名字。
property为具体算法需要用到的一些属性。

1.4、启动MyCat

mycat的启动有两种方式,一种是控制台启动,一种是后台启动,在初学的时候建议大家使用控制台启动的方式,当配置文件写错之后,可以方便的看到错误,及时修改,但是在生产环境中,使用后台启动的方式比较稳妥。

​ 控制台启动:去mycat/bin目录下执行 ./mycat console

​ 后台启动:去mycat/bin目录下执行 ./mycat start

​ 按照如上配置在安装的时候应该不会报错,如果出现错误,根据错误的提示解决即可。

1.5、登录验证

	管理窗口的登录

从另外的虚拟机去登录访问当前mycat,输入如下命令即可

mysql -uroot -p123456 -P 9066 -h 192.168.85.111
此时访问的是mycat的管理窗口,可以通过show @@help查看可以执行的命令

数据窗口的登录
从另外的虚拟机去登录访问mycat,输入命令如下:

mysql -uroot -p123456 -P8066 -h 192.168.85.111
当都能够成功的时候以为着mycat已经搭建完成。

二、 MySQL安装

三、读写分离

通过mycat和mysql的主从复制配合搭建数据库的读写分离,可以实现mysql的高可用性,下面我们来搭建mysql的读写分离。

3.1、一主一从

3.1.1、在node01上修改/etc/my.cnf的文件
#mysql服务唯一id,不同的mysql服务必须拥有全局唯一的id
server-id=1
#启动二进制日期
log-bin=mysql-bin
#设置不要复制的数据库
binlog-ignore-db=mysql
binlog-ignore-db=information-schema
#设置需要复制的数据库
binlog-do-db=msb
#设置binlog的格式
binlog_format=statement
3.1.2、在node02上修改/etc/my.cnf文件
#服务器唯一id
server-id=2
#启动中继日志
relay-log=mysql-relay
3.1.3、重新启动mysql服务
3.1.4、在node01上创建账户并授权slave
grant replication slave on *.* to 'root'@'%' identified by '123456';
--在进行授权的时候,如果提示密码的问题,把密码验证取消
set global validate_password_policy=0;
set global validate_password_length=1;
3.1.5、查看master的状态

show master status

3.1.6、在node02上配置需要复制的主机
CHANGE MASTER TO MASTER_HOST='192.168.85.111',MASTER_USER='root',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=437;
3.1.7、启动从服务器复制功能

start slave;

3.1.8、查看从服务器状态

show slave status\G

当执行完成之后,会看到两个关键的属性Slave_IO_Running,Slave_SQL_Running,当这两个属性都是yes的时候,表示主从复制已经准备好了,可以进行具体的操作了

3.2、一主一从验证

下面我们通过实际的操作来验证主从复制是否完成。

--在node01上创建数据库
create database msb;
--在node01上创建具体的表
create table mytbl(id int,name varchar(20));
--在node01上插入数据
insert into mytbl values(1,'zhangsan');
--在node02上验证发现数据已经同步成功,表示主从复制完成

通过mycat实现读写分离

在node01上插入如下sql语句,

-- 把主机名插入数据库中
insert into mytbl values(2,@@hostname);
-- 然后通过mycat进行数据的访问,这个时候大家发现无论怎么查询数据,最终返回的都是node01的数据,为什么呢?
select * from mytbl;
在之前的mycat基本配置中,其实我们已经配置了读写分离,还记得readHost和writeHost两个标签吗?
<writeHost host="hostM1" url="192.168.85.111:3306" user="root"
				   password="123456">
	<readHost host="hostS1" url="192.168.85.112:3306" user="root" password="123456"></readHost>
</writeHost>

其实我们已经配置过了这两个标签,默认情况下node01是用来完成写入操作的,node02是用来完成读取操作的,但是刚刚通过我们的验证发现所有的读取都是node01完成的,这是什么原因呢?

​ 原因很简单,就是因为我们在进行配置的时候在 dataHost 标签中缺失了一个非常重要的属性balance,此属性有四个值,用来做负载均衡的,下面我们来详细介绍

1、balance=0 :不开启读写分离机制,所有读操作都发送到当前可用的writehost上
​ 2、balance=1:全部的readhost和stand by writehost参与select语句的负载均衡,简单的说,当双主双从模式下,其他的节点都参与select语句的负载均衡
​ 3、balance=2:所有读操作都随机的在writehost,readhost上分发
​ 4、balance=3:所有读请求随机的分发到readhost执行,writehost不负担读压力
​ 当了解了这个参数的含义之后,我们可以将此参数设置为2,就能够看到在两个主机上切换执行了。

3.3、双主双从

在上述的一主一从的架构设计中,很容易出现单点的问题,所以我们要想让生产环境中的配置足够稳定,可以配置双主双从,解决单点的问题。

架构图如下所示:

在这里插入图片描述

在此架构中,可以让一台主机用来处理所有写请求,此时,它的从机和备机,以及备机的从机复制所有读请求,当主机宕机之后,另一台主机负责写请求,两台主机互为备机。

主机分布如下:
编号角色ip主机名
1master1192.168.85.111node01
2slave1192.168.85.112node02
3master2192.168.85.113node03
4slave2192.168.85.114node04
下面开始搭建双主双从。
3.3.1、修改node01上的/etc/my.cnf文件
#主服务器唯一ID
server-id=1
#启用二进制日志
log-bin=mysql-bin
# 设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
#设置需要复制的数据库
binlog-do-db=msb
#设置logbin格式
binlog_format=STATEMENT
# 在作为从数据库的时候, 有写入操作也要更新二进制日志文件
log-slave-updates
#表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1, 取值范围是1 .. 65535
auto-increment-increment=2
# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535
auto-increment-offset=1
3.3.2、修改node03上的/etc/my.cnf文件
#主服务器唯一ID
server-id=3
#启用二进制日志
log-bin=mysql-bin
# 设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
#设置需要复制的数据库
binlog-do-db=msb
#设置logbin格式
binlog_format=STATEMENT
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
#表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1,取值范围是1 .. 65535
auto-increment-increment=2
# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535
auto-increment-offset=2
3.3.3、修改node02上的/etc/my.cnf文件
#从服务器唯一ID
server-id=2
#启用中继日志
relay-log=mysql-relay
3.3.4、修改node04上的/etc/my.cnf文件
#从服务器唯一ID
server-id=4
#启用中继日志
relay-log=mysql-relay
3.3.5、所有主机重新启动mysql服务
3.3.6、在两台主机node01,node03上授权同步命令
GRANT REPLICATION SLAVE ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
3.3.7、查看两台主机的状态
show master status;
3.3.8、在node02上执行要复制的主机
CHANGE MASTER TO MASTER_HOST='192.168.85.111',MASTER_USER='root',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=154;
3.3.9、在node04上执行要复制的主机
CHANGE MASTER TO MASTER_HOST='192.168.85.113',MASTER_USER='root',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=154;
3.3.10、启动两个从机的slave并且查看状态,当看到两个参数都是yes的时候表示成功
start slave;
show slave status;
3.3.11、完成node01跟node03的相互复制
--在node01上执行
CHANGE MASTER TO MASTER_HOST='192.168.85.113',MASTER_USER='root',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=442;
--开启slave
start slave
--查看状态
show slave status\G
--在node03上执行
CHANGE MASTER TO MASTER_HOST='192.168.85.111',MASTER_USER='root',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000002',MASTER_LOG_POS=442;
--开启slave
start slave
--查看状态
show slave status\G

4、双主双从验证

在node01上执行如下sql语句:
create database msb;
create table mytbl(id int,name varchar(20));
insert into mytbl values(1,'zhangsan');
--完成上述命令之后可以去其他机器验证是否同步成功
当上述操作完成之后,我们可以验证mycat的读写分离,此时我们需要进行重新的配置,修改schema.xml文件。
在当前mysql架构中,我们使用的是双主双从的架构,因此可以将balance设置为1

除此之外我们需要注意,还需要了解一些参数:

​ 参数writeType,表示写操作发送到哪台机器,此参数有两个值可以进行设置:

​ writeType=0:所有写操作都发送到配置的第一个writeHost,第一个挂了切换到还生存的第二个

​ writeType=1:所有写操作都随机的发送到配置的writehost中,1.5之后废弃,

​ 需要注意的是:writehost重新启动之后以切换后的为准,切换记录在配置文件dnindex.properties中

​ 参数switchType:表示如何进行切换:

​ switchType=1:默认值,自动切换

​ switchType=-1:表示不自动切换

​ switchType=2:基于mysql主从同步的状态决定是否切换

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
	<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
	</schema>
	<dataNode name="dn1" dataHost="host1" database="msb" />
	<dataHost name="host1" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="hostM1" url="192.168.85.111:3306" user="root"
				   password="123456">
			<readHost host="hostS1" url="192.168.85.112:3306" user="root" password="123456"></readHost>
		</writeHost>
		<writeHost host="hostM2" url="192.168.85.113:3306" user="root"
				   password="123456">
			<readHost host="hostS2" url="192.168.85.114:3306" user="root" password="123456"></readHost>
		</writeHost>
	</dataHost>
</mycat:schema>

​ 下面开始进行读写分离的验证

--插入以下语句,使数据不一致
insert into mytbl values(2,@@hostname);
--通过查询mycat表中的数据,发现查询到的结果在node02,node03,node04之间切换,符合正常情况
select * from mytbl;
--停止node01的mysql服务
service mysqld stop
--重新插入语句
insert into mytbl values(3,@@hostname);
--开启node01的mysql服务
service mysqld start
--执行相同的查询语句,此时发现在noede01,node02,node04之间切换,符合情况

通过上述的验证,我们可以得到一个结论,node01,node03互做备机,负责写的宕机切换,其他机器充作读请求的响应。

做到此处,希望大家能够思考一个问题,在上述我们做的读写分离操作,其实都是基于主从复制的,也就是数据同步,但是在生产环境中会存在很多种情况造成主从复制延迟问题,那么我们应该如何解决延迟问题,这是一个值得思考的问题,到底如何解决呢

四、数据切片

数据切分指的是通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库上面,以达到分散单台设备负载的效果。

​ 数据的切分根据其切分规则的类型,可以分为两种切分模式。一种是按照不同的表来切分到不同的数据库之上,这种切可以称之为数据的垂直切分或者纵向切分,另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库上面,这种切分称之为数据的水平切分或者横向切分。

​ 垂直切分的最大特点就是 规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低,相互影响很小,业务逻辑非常清晰的系统。在这种系统中,可以很容易做到将不同业务模块所使用的表分拆到不同的数据库中。根据不同的表来进行拆分,对应用程序的影响也很小,拆分规则也会比较简单清晰。

​ 水平切分与垂直切分相比,相对来说稍微复杂一些。因为要将同一个表中的不同数据拆分到不同的数据库中,对于应用程序来说,拆分规则本身就较根据表明来拆分更为复杂,后期的数据维护也会更为复杂一些。

4.1、垂直切分

一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据库上面,这样也就将数据或者压力分担到不同的库上面。
在这里插入图片描述
如上图所示,一个系统被切分成了用户系统、订单交易、支付系统等多个库。

​ 一个架构设计较好的应用系统,其总体功能肯定是又多个功能模块所组成的。而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相关质检的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。

​ 但是往往系统中有些表难以做到完全的独立,存在着跨库join的情况,对于这类的表,就需要去做平衡,是数据让步业务,共用一个数据源还是分成多个库,业务之间通过接口来做调用。在系统初期,数据量比较少,或者资源有限的情况下,会选择共用数据源,但是当数据发展到一定规模,负载很大的情况下就必须要做分割。

​ 一般来讲业务存在着复杂join的场景是难以切分的,往往业务独立的易于切分。如何切分,切分到何种程度是考验技术架构的一个难题。下面来分析下垂直切分的优缺点:

优点: ​
1、拆分后业务清晰,拆分规则明确
​2、系统之间整合或扩展容易
​3、数据维护简单
缺点:
1、部分业务表无法实现join,只能通过接口方式解决,提高了系统复杂度
2、受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高
​3、事务处理复杂

4.2、水平切分

相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行切分,就是将表中的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中
在这里插入图片描述
拆分数据就需要定义分片规则。关系型数据库是行列的二维模型,拆分的第一原则是找到拆分维度。比如从会员的角度来分析,商户订单交易类系统中查询会员某天某月某个订单,那么就需要按照会员结合日期来拆分,不同的数据按照会员id做分组,这样所有的数据查询join都会在单库内解决;如果从商户的角度来讲,要查询某个商家某天所有的订单数,就需要按照商户id做拆分;但是如果系统既想按照会员拆分,又想按照商家数据拆分,就会有一定的困难,需要综合考虑找到合适的分片。

几种典型的分片规则包括:

1、按照用户id取模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中;
2、按照日期,将不同月甚至日的数据分散到不同的库中;
3、按照某个特定的字段求模,或者根据特定范围段分散到不同的库中。

如图,切分原则都是根据业务找到适合的切分规则分散到不同的库,下图是用用户id求模的案例:

在这里插入图片描述数据做完了水平拆分之后也是有优缺点的。

优点: ​
1、拆分规则抽象好,join操作基本可以数据库做; ​
2、不存在单库大数据,高并发的性能瓶颈; ​
3、应用端改造较少;
​4、提高了系统的稳定性跟负载能力 ​
缺点: ​
1、拆分规则难以抽象 ​
2、分片事务一致性难以解决
​3、数据多次扩展跟维护量极大 ​
4、跨库join性能较差


总结

数据切分的两种方式,会发现每种方式都有自己的缺点,但是他们之间有共同的缺点,分别是:

​ 1、引入了分布式事务的问题

​ 2、跨节点join的问题

​ 3、跨节点合并排序分页的问题

​ 4、多数据源管理的问题

​ 针对数据源管理,目前主要有两种思路:

​ 1、客户端模式,在每个应用程序模块中配置管理自己需要的一个或多个数据源,直接访问各个数据库,在模块内完成数据的整合

​ 2、通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明;

​ 在实际的生产环境中,我们都会选择第二种方案来解决问题,尤其是系统不断变得庞大复杂的时候,其实这是非常正确的,虽然短期内付出的成本可能会比较大,但是对整个系统的扩展性来说,是非常有帮助的。

​ mycat通过数据切分解决传统数据库的缺陷,又有了nosql易于扩展的优点。通过中间代理层规避了多数据源的数据问题,对应用完全透明,同时对数据切分后存在的问题,也做了解决方案。

​ mycat在做数据切分的时候应该尽可能的遵循以下原则,当然这也是经验之谈,最终的落地实现还是要看具体的应用场景在做具体的分析

​ 第一原则:能不切分尽量不要切分

​ 第二原则:如果要切分一定要选择合适的切分规则,提前规划好

​ 第三原则:数据切分尽量通过数据冗余或表分组来降低跨库join的可能

​ 第四原则:由于数据库中间件对数据join实现的优劣难以把握,而且实现高性能难度极大,业务读取尽量少使用多表join。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值