使用mycat实现mysql读写分离

一、mycat概述

1、mycat

         mycat是一个开源的分布式数据库中间件,是一个实现了MySQL 协议的的Server,前端用户可以把它看作是一个数据库代理,用MySQL 客户端工具和命令行访问,而其后端可以用MySQL 原生(Native)协议与多个MySQL 服务器通信,也可以用JDBC 协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N 个小表,存储在后端MySQL 服务器里或者其他数据库里。官网地址为http://www.mycat.io/

2、原理

         Mycat 的原理的核心是“拦截”,它拦截了用户发送过来的SQL 语句,首先对SQL 语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL 发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。

3、mycat的主要特性

(1)支持 SQL 92标准

(2)支持Mysql集群,可以作为Proxy使用

(3)支持JDBC连接多数据库

(4)支持各种数据库,包括Mysql 、mongodb、oracle、sqlserver 、hive 、db2 、 postgresql。

(5)支持galera for mysql集群,percona-cluster或者mariadb cluster,提供高可用性数据分片集群

(6)自动故障切换,高可用性

(7)支持读写分离,支持Mysql双主多从,以及一主多从的模式

(8)支持全局表,数据自动分片到多个节点,用于高效表关联查询

(9)支持独有的基于E-R 关系的分片策略,实现了高效的表关联查询

(10)支持一致性Hash分片,有效解决分片扩容难题

(11)多平台支持,部署和实施简单

(12)支持Catelet开发,类似数据库存储过程,用于跨分片复杂SQL的人工智能编码实现

(13)支持NIO与AIO两种网络通信机制,Windows下建议AIO,Linux下目前建议NIO

(14)支持Mysql存储过程调用

(15)以插件方式支持SQL拦截和改写

(16)支持自增长主键、支持Oracle的Sequence机制

4、mycat的应用场景

(1)单纯的读写分离,此时配置最为简单,支持读写分离,主从切换;

(2)分表分库,对于超过1000 万的表进行分片,最大支持1000 亿的单表分片;

(3)多租户应用,每个应用一个库,但应用程序只连接Mycat,从而不改造程序本身,实现多租户化;

(4)报表系统,借助于Mycat 的分表能力,处理大规模报表的统计;

(5)替代Hbase,分析大数据;

(6)作为海量数据实时查询的一种简单有效方案

二、mycat的安装

1、安装前环境准备

(1)安装java jdk1.7及以上版本

(2)确保本机的hostname在/etc/hosts里存在

(3)需要安装mysql环境

2、下载安装mycat

(1)下载安装mycat

# 下载mycat
]# wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
# 解压并拷贝至/etc/local目录下即可使用
]# tar -xf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
]# mv mycat /usr/local/

(2)mycat工作目录说明

         Bin:程序存放目录

         Conf:配置文件存放目录,主要的配置文件有server.xml(Mycat服务器参数调整和用户授权的配置文件),schema.xml(逻辑库定义和表以及分片定义的配置文件),rule.xml(分片规则的配置文件)

         lIb:主要存放mycat依赖的一些jar文件

         Logs:日志文件存放目录,日志每天会进行切割

(3)mycat的启动

         启动mycat时直接运行mycat的bin目录下的mycat即可启动mycat。Mycat启动后默认监听8066(数据端口)和9066(管理端口)两个端口。

# 启动mysql
]# bin/mycat start
Starting Mycat-server...

(4)登录mycat

         登录mycat同登录mysql类似,但需要指定主机和端口。登录的用户为在server.xml配置文件中定义的用户。

]# mysql -h127.0.0.1 -uuser -puser -P8066

三、配置mycat

1、与mycat相关的一些概念

(1)数据库中间件

         Mycat没有存储引擎,所以并不是完全意义的分布式数据库系统,而是介于数据库与应用之间,进行数据处理与交互的中间服务。

(2)逻辑库(schema)

         对实际应用来说,并不需要知道中间件的存在,业务开发人员只需要知道数据库的概念,所以数据库中间件可以被看做是一个或多个数据库集群构成的逻辑库。

(3)逻辑表

         逻辑表:分布式数据库中,对应用来说,读写数据的表就是逻辑表。逻辑表,可以是数据切分后,分布在一个或多个分片库中,也可以不做数据切分,不分片,只有一个表构成。

         分片表:指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所有分片构成了完整的数据。

         非分片表:不需要进行数据切分的表。

         ER 表:子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组(Table Group)保证数据Join 不会跨库操作。

         全局表:所有将字典表或者符合字典表特性的一些表定义为全局表

(4)分片节点(dataNode)

         数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点。

(5)节点主机(dataHost)

         一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost)。

(6)分片规则(rule)

         一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到某个分片的规则就是分片规则。

(7)全局序列号(sequence)

         数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence)。

2、schema.xml文件的配置

(1)schema标签的配置

         schema标签用于定义MyCat实例中的逻辑库,MyCat可以有多个逻辑库,每个逻辑库都有自己的相关配置。可以使用 schema 标签来划分这些不同的逻辑库。 如果不配置 schema 标签,所有的表配置,会属于同一个默认的逻辑库。

需要配置的属性:

         name:定义逻辑数据库库名

         dataNode:用于绑定逻辑库到某个具体的数据节点上

         checkSQLschema:值为true时,会将操作语句中的逻辑库名去掉,如果库名不是定义的逻辑库名则会发往后端数据库;值false时,则会把语句原封不动的发往最终的MySQL执行。

         sqlMaxLimit:当该schema中有分片表时,才会生效 当该值设置为某个数值时。每条执行的SQL语句,如果没有加上limit语句,MyCat也会自动的加上所对应的值。

(2)table标签

         Table标签写在schema标签中,Table 标签定义了MyCat中的逻辑表,所有需要拆分的表都需要在这个标签中定义。

配置属性:

         Name:定义需要拆分的表的表名

         Rule:该属性用于指定逻辑表要使用的规则名字,规则名字在rule.xml中定义,必须与tableRule标签中name属性属性值一一对应。

         dataNode:要拆分到的数据节点名称

         Type:该属性定义了逻辑表的类型,目前逻辑表只有“全局表”和”普通表”两种类型

(3)dataNode标签

         dataNode 标签定义了MyCat中的数据节点,用于绑定逻辑库到某个具体的database。一个dataNode标签就是一个独立的数据分片。

配置属性:

         Name:定义数据节点的名字,这个名字需要是唯一的,我们需要在table标签上应用这个名字,来建立表与分片对应的关系。

         dataHost:该属性用于定义该分片属于哪个数据库实例的,属性值是引用dataHost标签上定义的name属性。

         Database:该属性用于定义该分片属性哪个具体数据库实例上的具体库

(4)dataHost标签

         该标签在mycat逻辑库中作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句

配置属性:

         name:唯一标识dataHost标签,供上层的标签使用。

         maxCon:指定每个读写实例连接池的最大连接

         minCon:指定每个读写实例连接池的最小连接,初始化连接池的大小

         balance:负载均衡类型,目前的取值有3种:当balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上;当balance="1",全部的readHost与stand by writeHost参与select语句的负载均衡;balance="2",所有读操作都随机的在writeHost、readhost上分发。

         writeType:写操作的负载均衡配置,目前的取值有2种:当writeType="0", 所有写操作发送到配置的第一个writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为准;当writeType=“1”,所有写操作都随机的发送到配置的writeHost,但不推荐使用。

         switchType:当master故障时是否自动切换,当值为”-1”时表示不自动切换,”1”为默认值,表示自动切换,当值为”2”时基于MySQL主从同步的状态决定是否切换,心跳语句为 show slave status。

         tempReadHostAvailable:如果配置了这个属性writeHost 下面的readHost 仍旧可用,默认0 可配置(0、1)

(5)heartbeat标签

         Heartbeat标签写在dataHost标签内,这个标签内指明用于和后端数据库进行心跳检查的语句。

(6)writeHost标签、readHost标签

         这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。writeHost标签写在dataHost标签内,readHost标签写在writeHost标签内,用于指定写实例下的读实例。

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

配置属性:

         host:用于标识不同实例,一般writeHost使用*M1,readHost用*S1

         url:后端实例连接地址,如果是使用native的dbDriver,则一般为address:port这种形式。用JDBC或其他的dbDriver,则需要特殊指定。

         user:后端存储实例需要的用户名字

         password:后端存储实例需要的密码

         weight:权重 配置在readhost 中作为读节点的权重

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">
          <table name="tb_item" dataNode="dn1,dn2" rule="auto-sharding-long" />
  </schema>
  <dataNode name="dn1" dataHost="localhost1" database="course" />
  <dataNode name="dn2" dataHost="localhost1" database="course2" />
  <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
                     writeType="0" dbType="mysql" dbDriver="native" switchType="1">
          <heartbeat>select user()</heartbeat>
          <!-- can have multi write hosts -->
          <writeHost host="M1" url="192.168.16.151:3306" user="testuser" password="mysql">
                   <!-- can have multi read hosts -->
                   <readHost host="S1" url="192.168.16.152:3306" user="testuser" password="mysql" />
          </writeHost>
  </dataHost>
</mycat:schema>

3、server.xml文件的配置

         server.xml中用于定义登录mycat的用户和权限,定义一个登陆的用户配置文件如下: 

<user name="test"> 
          <property name="password">test</property> 
          <property name="schemas">testdb</property> 
          <property name="readOnly">true</property> 
          <property name="benchmark">11111</property> 
          <property name="usingDecrypt">1</property> 
          <privileges check="false"> 
                   <schema name="TESTDB" dml="0010" showTables="custome/mysql"> 
                            <table name="tbl_user" dml="0110"></table> 
                            <table name="tbl_dynamic" dml="1111"></table> 
                   </schema> 
          </privileges>
  </user>

(1)user标签配置

         User标签用来设定登陆的用户及用户登录权限

配置属性:

         name:user标签中name属性用来来指定用户名;

         password:指定密码;

         readOnly:职位true 或false来限制用户是否只是可读的;

         schemas:控制用户可访问的schema,同时访问多个schema的话使用逗号隔开

(3)其他的一些配置(定义在system标签下)

         packetHeaderSize : 指定Mysql协议中的报文头长度。默认4。

         maxPacketSize : 指定Mysql协议可以携带的数据最大长度。默认16M。

         idleTimeout : 指定连接的空闲超时时间。默认30分钟,单位毫秒。

         charset : 连接的初始化字符集。默认为utf8。

         txIsolation : 前端连接的初始化事务隔离级别,只在初始化的时候使用,后续会根据客户端传递过来的属性对后端数据库连接进行同步

         sqlExecuteTimeout:SQL执行超时的时间,默认时间为300秒,单位秒。

(3)与服务相关的一些配置(定义在system标签下)

         bindIp : mycat服务监听的IP地址,默认值为0.0.0.0。

         serverPort : 定义mycat的使用端口,默认值为8066

         managerPort : 定义mycat的管理端口,默认值为9066。

4、rule.xml文件的配置

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

(1)tableRule标签

         这个标签用来定义表规则。属性及嵌套的一些子标签的作用如下:

         name:指定唯一的名字,用于标识不同的表规则。

         rule标签:指定对物理表中的哪一列进行拆分和使用什么路由算法。

         columns标签:指定要拆分的列名字。

         algorithm标签:使用function标签中的name属性。连接表规则和具体路由算法。  多个表规则可以连接到同一个路由算法上。table标签内使用。让逻辑表使用这个规则进行分片。  

<tableRule name="auto-sharding-long">
          <rule>
                  <columns>id</columns>
                  <algorithm>rang-long</algorithm>
          </rule>
</tableRule>

(2)function标签

         主要的属性及子标签的作用如下:

         name:指定算法的名字。

         class:制定路由算法具体的类名字

         property:具体算法需要用到的一些属性。

四、mycat的分片

         在数据切分处理中,特别是水平切分中,中间件最终要的两个处理过程就是数据的切分、数据的聚合。选择合适的切分规则,至关重要,因为它决定了后续数据聚合的难易程度,甚至可以避免跨库的数据聚合处理。

1、全局表

         如果你的业务中有些数据类似于数据字典,比如配置文件的配置,常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大,而且大部分的业务场景都会用到,那么这种表适合于Mycat 全局表,无须对数据进行切分,只要在所有的分片上保存一份数据即可,Mycat 在Join 操作中,业务表与全局表进行Join 聚合会优先选择相同分片内的全局表join,避免跨库Join,在进行数据插入操作时,mycat 将把数据分发到全局表对应的所有分片执行,在进行数据读取时候将会随机获取一个节点读取数据。

         全局表的配置:在schema.xml表的table标签中通过type="global"配置,配置如下:

<table name="t_area" primaryKey="id" type="global" dataNode="dn1,dn2" />

2、常用的分片规则

(1)、ER 分片表

         在ER 分片表,子表的记录与所关联的父表记录需存放在同一个数据分片上,避免数据Join 跨库操作。在ER分片表中要指定join连接的列名,一般为外键。

         ER分片表的配置如下:

<table name=“orders” dataNode=“dn1,dn2" rule="mod-long"> 
  <childTable name="order_detail" primaryKey="id" joinKey="order_id" parentKey="order_id" /> 
</table>

         上面的配置中order_detail 根据order_id进行数据切分,保证相同order_id的数据分到同一个分片上,在进行数据插入操作时,Mycat会获取order所在的分片,然后将order_detail也插入到order所在的分片。

(2)、分片枚举

         通过在配置文件中配置可能的枚举id,自己配置分片,此分片规则适用提前规划好分片字段某个范围属于哪个分片。

         rule.xml中的配置如下:

<tableRule name="auto-sharding-long"> 
  <rule> 
          <columns>user_id</columns> 
          <algorithm>rang-long</algorithm>
  </rule> 
</tableRule> 
<function name="rang-long" class="org.opencloudb.route.function.AutoPartitionByLong"> 
  <property name="mapFile">autopartition-long.txt</property> 
  <property name="defaultNode">0</property> 
</function>

         上面配置中各子标签及属性含义:

                   columns:标识将要分片的表字段

                   algorithm:分片函数

                   mapFile:配置文件路径

                   defaultNode:超过范围后的默认节点

         在schema.xml的table标签中配置如下:

  <table name="orders" dataNode="dn1,dn2" rule="auto-sharding-long"> </table>

partition-hash-int.txt 配置:

10000=0 
10010=1 DEFAULT_NODE=1

(3)、取模分片

         取摸分片是对分片字段求摸运算,然后根据取摸的结果将数据存放在不同的分片上。server.xml配置如下:

<tableRule name="mod-long"> 
  <rule> 
          <columns>user_id</columns> 
          <algorithm>mod-long</algorithm> 
  </rule> 
</tableRule>
<function name="mod-long" class="org.opencloudb.route.function.PartitionByMod"> 
  <!-- how many data nodes --> 
  <property name="count">3</property> 
</function>

         各字段的配置同上面的配置相同,count用来表示存储在几个分片中。

(4)按月份

         按月份列分区 ,每个自然月为一个分片,配置实例如下:

<tableRule name="sharding-by-month"> 
  <rule> 
          <columns>create_time</columns> 
          <algorithm>sharding-by-month</algorithm> 
  </rule>  
</tableRule> 
<function name="sharding-by-month" class="org.opencloudb.route.function.PartitionByMonth"> 
  <property name="dateFormat">yyyy-MM-dd</property> 
  <property name="sBeginDate">2014-01-01</property> 
</function>

         tableRule标签中的字段同上面相同,function标签字段属性如下:

                   dateFormat:日期字符串格式

                   sBeginDate:开始日期

3、使用分片时要注意的事项

(1)能不分则不分,1000万以内的表,不建议分片,通过合适的索引,读写分离等方式,可以很好的解决性能问题。

(2)分片数量尽量少

(3)分片规则需要慎重选择

(4)尽量不要在一个事务中的SQL跨越多个分片

(5)查询条件尽量优化,尽量避免Select * 的方式

五、使用mycat配置mysql读写分离

1、准备工作

(1)mysql节点的及mycat节点的准备

主机名

IP地址

作用

版本

复制用户

Mycats使用用户

mysql-master

192.168.16.151

Mysql主

5.7.23

repl

root

mysql-slave01

192.168.16.152

Mysql从

5.7.23

 

root

MYCAT

192.168.16.155

Mycat节点

1.6

 

dayi

(2)拓扑结构

        

2、配置主从同步

(1)配置主库

# 在主库上创建用于复制的用户
mysql> CREATE USER 'repl'@'192.168.16.%' IDENTIFIED BY 'replication';   
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.16.%';        
# 配置主库的server-id及开启binglog,配置完成后需要重启mysql
[mysqld]
log-bin=mysql-bin 
server-id=1
# mysql操作表时不区分大小写,不配置使用mycat时可能会报错
lower_case_table_names=1    
# 设置字符集及需要同步的库
replicate-do-db=course
character-set-server=utf8
init_connect='SET AUTOCOMMIT=0;set names utf8'
# 锁定所有的表,防止写入
mysql> FLUSH TABLES WITH READ LOCK;
# 获取当前日志信息
mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
             File: mysql-bin.000001
         Position: 1594
# 将主库上的数据导出并传到从库
~]# mysqldump --all-databases --master-data -u root -p > dbdump.db
~]# scp dbdump.db [email protected]:/data/mysql/data
# 释放主库锁
mysql> unlock tables;

(2)配置从库

# 配置从库的server-id并重启重库
[mysqld]
server-id=2
# 设置字符集及需要同步的库
replicate-do-db=course
character-set-server=utf8
init_connect='SET AUTOCOMMIT=0;set names utf8'
# mysql操作表时不区分大小写,不配置使用mycat时可能会报错
lower_case_table_names=1   
# 在从库上导入主库导出的数据
~]# mysql -uroot -p </data/mysql/data/dbdump.db
# 登录数据库开启主从同步
mysql> reset slave;
mysql> CHANGE MASTER TO
    -> MASTER_HOST='192.168.16.151',
    -> MASTER_PORT=3306,
    -> MASTER_USER='repl',
    -> MASTER_PASSWORD='replication',
    -> MASTER_LOG_FILE='mysql-bin.000003',
    -> MASTER_LOG_POS=194;
mysql> start slave;

3、配置mycat

(1)配置schema.xml文件

         Schema.xml文件的配置内容如下

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
  <!--定义逻辑库,TESTDB一定要大写。由于没有对表分片,不需要定义table,并且让语句原封不动的发往后端-->
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
  </schema>
  <!--数据节点dn1,对应的主机c1,对应是数据库db1 -->
    <dataNode name="dn0" dataHost="node1" database="course" />
    <!-- 定义主机C1,开启读写分离机制-->
    <dataHost name="node1" maxCon="1000" minCon="10" balance="1" writeType="0" switchType="1" dbType="mysql" dbDriver="native">
          <!--定义心跳检测机制-->
        <heartbeat>select user()</heartbeat>
        <!--定义MySQL的写的数据,master1 -->
        <writeHost host="M1" url="192.168.16.151:3306" user="root" password="DaYi@777">
            <!--定义MySQL读的数据库,slave1 -->
            <readHost host="S1" url="192.168.16.152:3306" user="root" password="DaYi@777" />
        </writeHost>
    </dataHost>
</mycat:schema>

(2)配置server.xml

         通过server.xml定义登录mycat的库以及登录用户,定义的逻辑库名与schema.xml中schema标签中的name字段定义的库名要相同。添加定义一个登录用户的配置文件如下:

<!--配置用户名-->
    <user name="root">
          <!--配置密码-->
         <property name="password">dayi123</property>
          <!--配置逻辑库-->
        <property name="schemas">testdb</property>
    </user>

(3)使用mycat

         由于没有使用分片功能所以不用配置rule.xml,配置完成后重启mycat后即可使用。

# 重启mycat
]# ./mycat restart
# 登录mycat
[root@MYCAT bin]# mysql -h192.168.16.155 -uroot -p -P8066   
# 通过mycat操作数据库
mysql> use TESTDB
Database changed
mysql> show tables;
+------------------+
| Tables_in_course |
+------------------+
| course           |
| dept             |
| score            |
| student          |

六、管理mycat

         Mycat安装完成后默认会监听两个端口,8066为数据端口,9066为管理端口登录方式同mysal登录方式类似。

# 登录mycat管理端口
]# mysql -h127.0.0.1 -uuser -puser -P9066

Mycat的主要管理命令如下:

         show @@help; 查看所有的命令

         reload @@config_all; 该命令用于更新配置文件

         show @@database; 该命令用于显示MyCAT的数据库的列表,对应schema.xml配置文件的schema子节点。

         show @@datanode; 该命令用于显示MyCAT的数据节点的列表,对应schema.xml配置文件的dataNode节点

         show @@heartbeat:该命令用于报告心跳状态

         show @@connection:该命令用于获取Mycat的前端连接状态,即应用与mycat的连接

         kill @@connection id,id,id :用于杀掉连接。

         show @@cache; 查看mycat缓存;SQLRouteCache为sql路由缓存。 TableID2DataNodeCache为缓存表主键与分片对应关系。 ER_SQL2PARENTID :为缓存ER分片中子表与父表关系。

         show @@datasource; 查看数据源状态,如果配置了主从,或者多主可以切换。

         switch @@datasource name:index:切换数据源,name为schema中配置的dataHost 中name。index为schema中配置的dataHost 的writeHost index 位标(按照配置顺序从上到下的一次顺 序,从0开始)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章