Mycat(一)介绍部署与读写分离实现

Mycat介绍部署与读写分离及高可用实现

文章目录


mycat官方网站

  • Mycat主要是做数据分布式存储,也有Atlas普通版的读写分离功能,其最重要还是分布式
  • Mycat是java开发的

mycat管理端口:9066
mycat数据端口:8066

Mycat介绍:
  • Mycat是什么?
  • Mycat背后是阿里曾经开源的知名产品——Cobar,Cobar是阿里巴巴研发的关系型数据的分布式处理系统
  • 从定义和分类来看,它是一个开源的分布式数据库系统,是一个实现了MySQL协议的的Server,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生(Native)协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里
  • 支持 SQL 92标准
  • 支持Mysql集群,可以作为Proxy使用
  • 支持JDBC连接多数据库
  • 支持各种数据库,包括Mysql、mongodb、oracle、sqlserver、hive 、db2 、 postgresql。
  • 支持galera for mysql集群,percona-cluster或者mariadb cluster,提供高可用性数据分片集群
  • 自动故障切换,高可用性
  • 支持读写分离,支持Mysql双主多从,以及一主多从的模式
  • 支持全局表,数据自动分片到多个节点,用于高效表关联查询
  • 支持独有的基于E-R 关系的分片策略,实现了高效的表关联查询
  • 支持一致性Hash分片,有效解决分片扩容难题
  • 多平台支持,部署和实施简单
  • 支持Catelet开发,类似数据库存储过程,用于跨分片复杂SQL的人工智能编码实现
  • 支持NIO与AIO两种网络通信机制,Windows下建议AIO,Linux下目前建议NIO
  • 支持Mysql存储过程调用
  • 以插件方式支持SQL拦截和改写
  • 支持自增长主键、支持Oracle的Sequence机制
  • Mycat的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。

img

  • 上述图片里,Orders表被分为三个分片datanode(简称dn),这三个分片是分布在两台MySQL Server上(DataHost),即datanode=database@datahost方式,因此你可以用一台到N台服务器来分片,分片规则为(sharding rule)典型的字符串枚举分片规则,一个规则的定义是分片字段(sharding column)+分片函数(rule function),这里的分片字段为prov而分片函数为字符串枚举方式。
  • 当Mycat收到一个SQL时,会先解析这个SQL,查找涉及到的表,然后看此表的定义,如果有分片规则,则获取到SQL里分片字段的值,并匹配分片函数,得到该SQL对应的分片列表,然后将SQL发往这些分片去执行,最后收集和处理所有分片返回的结果数据,并输出到客户端。以select * from Orders where prov=?语句为例,查到prov=wuhan,按照分片函数,wuhan返回dn1,于是SQL就发给了MySQL1,去取DB1上的查询结果,并返回给用户。
Mycat功能介绍:
  • 01、遵守Mysq!原生协议,跨语言,跨数据库的通用中间件代理
  • 02、基于心跳的自动故障切换,支持读写分离,支持M0L一双主多从,以及一主多从
  • 03、有效管理数据源连接,基于数据分库,而不是分奉的模式
  • 04、基于Nio实现,有效管理线程,高并发问题
  • 05、支持数据的多片自动路由与聚合,支持sum, count,max等常用的聚合函数。
  • 06、支持2表join,甚至基于 callet的多表 JoIne
  • 07、支持通过全局表,ER关系的分片策略,实现了高效的多表join查询
  • 08、支持多租户方秦
  • 09、支持分布式事务(弱xa)
  • 10、支持全局序列号,解决分布式下的主键生成问题
  • 11、分片规则丰富,插件化开发,易于扩展。
  • 12、虽大的web,命令行监控
  • 13、支持前端作为mvsq通用代理,后端JDBC方式支持 Oracle、DB2、 SOL Server、ongood、巨杉。
  • 14、集群基于 ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发
Mycat应用场景:
Mycat几个典型的应用场景:
  • 单纯的读写分离,此时配置最为简单,支持读写分离主从切换
  • 分表分库,对于超过1000万的表进行分片,最大支持1000亿的单表分片
  • 多租户应用,每个应用一个库,但应用程序只连接Mycat,从而不改造程序本身,实现多 租户化
  • 报表系统,借助于Mycat的分表能力,处理大规模报表的统计
Mycat分片规则:
  • 分表分库虽然能解决大表对数据库系统的压力,但它并不是万能的,也有一些不利之处,因此首要问题是,分不分库,分哪些库,什么规则分,分多少分片。
  • 总体上来说,分片的选择是取决于最频繁的查询SQL的条件,因为不带任何W here语句的查询SQL,会便利所有的分片,性能相对最差,因此这种SQL越多,对系统的影响越大,所以我们要尽量避免这种SQL的产生。
原则一:
  • 能不分就不分,1000万以内的表,不建议分片,通过合适的索引,读写分离等方式,可以很好的解决性能问题。
原则二:
  • 分片数量尽量少,分片尽量均匀分布在多个DataHost上,因为一个查询SQL跨分片越多,则总体性能越差,虽然要好于所有数据在一个分片的结果,只在必要的时候进 行扩容,增加分片数量。
原则三:
  • 分片规则需要慎重选择,分片规则的选择,需要考虑数据的增长模式,数据的访 问模式,分片关联性问题,以及分片扩容问题,最近的分片策略为范围分片,枚举分片, 一致性Hash分片,这几种分片都有利于扩容。
原则四:
  • 尽量不要在一个事务中的SQL跨越多个分片,分布式事务一直是个不好处理的问题。
原则五:
  • 查询条件尽量优化,尽量避免Select * 的方式,大量数据结果集下,会消耗大量 带宽和CPU资源,查询尽量避免返回大量结果集,并且尽量为频繁使用的查询语句建立索引。
数据拆分分类:
垂直拆分数据:
  • 一个库中有3张表,垂直拆分就是把3张表拆到3个库中
  • 缺点:user表访问量大,就会导致压力不均匀

img

水平拆分数据:
  • user表中的数据再次进行拆分到多个库中,效果很好

img

MySQL-Mycat安装及读写分离:
  • 当 writeHost的节点挂掉后默认 readHost也会不使用。
  • 当前为MySQL-5.7版本环境
安装java环境:
yum -y install java-openjdk
下载mycat软件包:
wget http://dl.mycat.io/1.6.6.1/Mycat-server-1.6.6.1-release-20181031195535-linux.tar.gz
解压到/usr路径:
tar xf Mycat-server-1.6.6.1-release-20181031195535-linux.tar.gz -C /usr/local/
配置环境变量:
echo 'export PATH=/usr/local/mycat/bin:$PATH' >> /etc/profile
source /etc/profile
启动Mycat:
mycat start

img

进入Mycat程序:(默认用户root、密码123456)
mysql -uroot -p123456 -h127.0.0.1 -P8066

日志文件说明:
#'/usr/local/mycat/logs目录
mycat.log     Mycat工作日志
mycat.pid     pid文件
switch.log
wrapper.log   Mycat启动相关日志
配置文件说明:
#'/usr/local/mycat/conf目录
schema.xml    主配置文件(读写分离、高可用、分表、节点控制)
server.xml    mycat软件本身相关的配置
rule.xml      分片规则配置文件(分片规则列表、使用方法)
配置读写分离:
备份并编写配置文件:
mv /usr/local/mycat/conf/schema.xml /usr/local/mycat/conf/schema.xml.bak
vim /usr/local/mycat/conf/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="localhost1" database="olda" />
    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
    <writeHost host="mycat-02" url="10.0.0.20:3307" user="root" password="redhat">
        <readHost host="mycat-02" url="10.0.0.20:3309" user="root" password="redhat" />
    </writeHost>
    </dataHost>
</mycat:schema>
配置文件说明:
01)TESTDB == dn1
02)dn1 == localhost1 + olda库
03)localhost1 == 10.0.0.20:3307这个可写数据库实例的组,一个可写组可以附带多个可读数据库实例,写节点宕机,读节点也就不可用了
#上一行所调用的逻辑名称,一定是下行所定义的名称
#一个真实可写主机为一个组,可以对应多个可读节点

balance属性:
负载均衡类型,目前的取值有3种
1· balance="0",不开启读写分离机制,所有读操作都发送到当前可用的 writeHost上。
2. balance="1",全部的 readhost与 standby writeHost参与se1ect语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->s2,并且M1与M2互为主备),正常情况下,M2,S1,S2都参与 select语句的负载均衡。
3. balance="2",所有读操作都随机的在 writehost、 readhost上分发。

writeType属性
负载均衡类型,目前的取值有2种:
1. writeType="0",所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个 writehost,重新启动后己切换后的为主,切换记录在配置文件中: dnindex, properties
2. writeType="1",所有写操作都随机的发送到配置的 writeHost,但不推荐使用

switchType属性
1. switchType=-1 表示不自动切换
2. switchType=1 默认值,自动切换
3. switchType=2 基于MySg主从同步的状态决定是否切换,心跳语句为 show slave status
# mycat版本表示
<?xml version="1.0"?>
# 不用看
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
# mycat官网
<mycat:schema xmlns:mycat="http://io.mycat/">
# 运维人员定义mycat工作库TESTDB是mycat的一个逻辑库,可以自定义,但是涉及另外一个配置文件。不检查库。查看TESTDB库数据时,定义最大显示100行。TESTDB逻辑库对应dn1这个数据节点
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
# 运维人员定义mycat工作库配置结束(固定语法)
</schema>
# 定义名为dn1这个数据节点的逻辑主机地址。和真实的后端数据库中的olda库名。
    <dataNode name="dn1" dataHost="localhost1" database="olda" />
# 定义localhost1这个逻辑主机的最大并发连接数。最小连接(类似预热数据,提前连接好,节省临时连接的消耗)。balance默认为1,为负载均衡到所有从库读操作。writeType默认为0,写操作只分配到第一个writeHost数据库实例组。指定后端数据库软件类型。dbDriver是驱动。switchType="1"是主库宕机,自动切换到其他预备主数据库实例组
# dbDriver(使用native的话,因为这个值执行的是二进制的mysql协议,所以可以使用mysql和maridb,其他类型的则需要使用JDBC驱动来支持。)
    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
# mycat监控后端mysql是否可用,走的心跳信息
        <heartbeat>select user()</heartbeat>
# 定义localhost1逻辑主机中的真实主机,这是逻辑主机中的一个真实“可写”节点
    <writeHost host="mycat-02" url="10.0.0.20:3307" user="root" password="redhat">
# 定义localhost1逻辑主机中的真实主机,这是逻辑主机中的一个真实“可读”节点
        <readHost host="mycat-02" url="10.0.0.20:3309" user="root" password="redhat" />
# 定义真实可写主机节点的结速行(固定语法)
    </writeHost>
# 定义逻辑主机的结束行(固定语法)
    </dataHost>
# 定义mycat逻辑TESTDB库的结束行(固定格式)
</mycat:schema>

# 设置当 writeHost节点挂掉后 readHost还可以使用 tempReadHostAvailable="1"  ,默认该参数是 0
<dataHost name="node1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" tempReadHostAvailable="1">
创建root用户:
  • Mycat启动前创建用户完毕,自动同步密码到从节点(mycat-02节点3307实例)
mysql -S /data/3307/mysql.sock -e "grant all on *.* to root@'10.0.0.%' identified by 'redhat';"
Mycat创建库:
  • Mycat启动前创建完毕
mysql -S /data/3307/mysql.sock -e "create database olda;"
重启Mycat:
mycat restart
查看Mycat读写状态:
  • Mycat9006端口执行
[root@mycat-02 ~]# mysql -uroot -p123456 -h127.0.0.1 -P9066 -e "show @@datasource;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------+----------+-------+-----------+------+------+--------+------+------+---------+-----------+------------+
| DATANODE | NAME     | TYPE  | HOST      | PORT | W/R  | ACTIVE | IDLE | SIZE | EXECUTE | READ_LOAD | WRITE_LOAD |
+----------+----------+-------+-----------+------+------+--------+------+------+---------+-----------+------------+
| dn1      | mycat-02 | mysql | 10.0.0.20 | 3307 | W    |      0 |   10 | 1000 |      38 |         0 |          0 |
| dn1      | mycat-02 | mysql | 10.0.0.20 | 3309 | R    |      0 |    3 | 1000 |      32 |         1 |          0 |
+----------+----------+-------+-----------+------+------+--------+------+------+---------+-----------+------------+
查看当前可用数据节点的主机:
[root@db-mycat conf]# cat /usr/local/mycat/conf/dnindex.properties 
#update
#Wed Oct 30 11:12:13 CST 2019
node1=0
Mycat创建表:
  • Mycat8006端口执行(mycat-02节点)
# 如果是MySQL-8.0版本之后,要在mycat节点的my.cnf配置文件中的 client标签下加入 default-auth=mysql_native_password
mysql -uroot -p123456 -h127.0.0.1 -P8066 -e "use TESTDB;CREATE TABLE stu(id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '学生学号',name VARCHAR(50) NOT NULL COMMENT '学生姓名',age TINYINT UNSIGNED NOT NULL DEFAULT 18 COMMENT '学生年龄',gender ENUM('男','女') NOT NULL DEFAULT '男' COMMENT '学 生.别',birthday DATETIME NOT NULL DEFAULT NOW() COMMENT '学生入学时间');"
插入500条数据:
  • Mycat8006端口执行(mycat-02节点)
#!/usr/bin/bash
count=0
for i in `seq 500`;do
  even=`expr $i % 2`
  if [ $even -eq 0 ];then
    gender="男"
  else
    gender="女"
  fi
  count=$((a++))
  age=`tr -cd "0-9" < /dev/urandom |head -c 2`
  mysql -uroot -p123456 -h127.0.0.1 -P8066 -e "use TESTDB;insert into stu(name,age,gender) values('olda_$count','$age','$gender');"
done
执行查询语句:
  • Mycat8006端口执行(mycat-02节点)
[root@mycat-02 ~]# mysql -uroot -p123456 -h127.0.0.1 -P8066 -e "use TESTDB;select * from stu where id='7';"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+--------+-----+--------+---------------------+
| id | name   | age | gender | birthday            |
+----+--------+-----+--------+---------------------+
|  7 | olda_5 |  35 || 2019-02-12 19:34:52 |
+----+--------+-----+--------+---------------------+
关闭mycat-02节点3307实例(主):(mycat-02节点)
systemctl stop mysqld-3307.service
再次查询与插入:(mycat-02节点)
  • 当前把3307实例宕机后不可写,但是mycat把读操作分流到从节点

img

启动mycat-02节点3307实例(主):(mycat-02节点)
systemctl start mysqld-3307.service
再次查询与插入:(mycat-02节点)
  • 当前主库可以连接,就可以插入数据到TESTDB虚拟库,然后mycat分流数据到后端主库的olda库,在schema.xml文件定义

img

配置读写分离高可用:
修改mycat配置文件:(mycat-02节点)
cp /usr/local/mycat/conf/schema.xml /usr/local/mycat/conf/schema.xml_rw
vim /usr/local/mycat/conf/schema.xml
#增加一组可写数据库实例,对应的是mycat-01节点的库,mycat-01与mycat-02的3307实例互为主从,所以mycat-01节点也有olda库的数据
#在mycat-02节点的可写数据库实例组没有宕机时,mycat-01节点的可写数据库实例组是只读功能,当mycat-02数据库宕掉,mycat-01节点的3307实例组就会接管写操作

<?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="localhost1" database="olda" />
    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
    <writeHost host="mycat-02" url="10.0.0.20:3307" user="root" password="redhat">
        <readHost host="mycat-02" url="10.0.0.20:3309" user="root" password="redhat" />
    </writeHost>
    <writeHost host="mycat-01" url="10.0.0.10:3307" user="root" password="redhat">
        <readHost host="mycat-01" url="10.0.0.10:3309" user="root" password="redhat" />
    </writeHost>
    </dataHost>
</mycat:schema>
重启mycat:(mycat-02节点)
mycat restart
查看后端数据库读写节点:
mysql> show @@datasource;
+----------+----------+-------+-----------+------+------+--------+------+------+---------+-----------+------------+
| DATANODE | NAME     | TYPE  | HOST      | PORT | W/R  | ACTIVE | IDLE | SIZE | EXECUTE | READ_LOAD | WRITE_LOAD |
+----------+----------+-------+-----------+------+------+--------+------+------+---------+-----------+------------+
| dn1      | mycat-02 | mysql | 10.0.0.20 | 3307 | W    |      0 |    1 | 1000 |     419 |         2 |          3 |
| dn1      | mycat-01 | mysql | 10.0.0.10 | 3307 | W    |      0 |    9 | 1000 |    1515 |       463 |          4 |
| dn1      | mycat-02 | mysql | 10.0.0.20 | 3309 | R    |      0 |    9 | 1000 |    1467 |       422 |          0 |
| dn1      | mycat-01 | mysql | 10.0.0.10 | 3309 | R    |      0 |    0 | 1000 |       0 |         0 |          0 |
+----------+----------+-------+-----------+------+------+--------+------+------+---------+-----------+------------+
测试mycat读写分离:(mycat-02节点)
mysql -uroot -p123456 -h127.0.0.1 -P8066 -e "show variables like 'server_id';"
带有一点负载均衡的功能:(mycat-02节点)

img

测试可读数据库高可用:(mycat-02节点)
正常状态插入数据

img

关闭mycat-02节点3307实例(主):(mycat-02节点)
依然可以插入数据,因为mycat-01节点3307数据库实例组已经被调度成写节点了

img

mycat-01节点查询刚刚插入的数据:(mycat-01节点)
mysql -uroot -p123456 -h10.0.0.20 -P8066 -e "use TESTDB;select * from stu where id='504';"

img

MySQL-8.0-Mycat版本:
  • 如果是MySQL-8.0版本之后,要在mycat节点的my.cnf配置文件中的 client标签下加入 default-auth=mysql_native_password

  • 或者直接命令行加参数

    mysql -uroot -p123456 -h172.18.1.100 -P8066 --default-auth=mysql_native_password
    
  • 当前环境为 4个MySQL实例,双主互为主从,还有两个slave从节点。( GTID模式 )

修改mycat配置文件:
[root@db-mycat conf]# cat schema.xml 
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="course" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
</schema>
    <dataNode name="dn1" dataHost="node1" database="course" />
    <dataHost name="node1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
    <writeHost host="db01" url="172.18.1.76:3306" user="root" password="123456">
        <readHost host="db03" url="172.18.1.78:3306" user="root" password="123456" />
    </writeHost>
    <writeHost host="db02" url="172.18.1.77:3306" user="root" password="123456">
        <readHost host="db04" url="172.18.1.79:3306" user="root" password="123456" />
    </writeHost>
    </dataHost>
</mycat:schema>
查看后端数据库读写节点:
mysql> show @@datasource;
+----------+------+-------+-------------+------+------+--------+------+------+---------+-----------+------------+
| DATANODE | NAME | TYPE  | HOST        | PORT | W/R  | ACTIVE | IDLE | SIZE | EXECUTE | READ_LOAD | WRITE_LOAD |
+----------+------+-------+-------------+------+------+--------+------+------+---------+-----------+------------+
| dn1      | db01 | mysql | 172.18.1.76 | 3306 | W    |      0 |   10 | 1000 |      23 |         0 |          0 |
| dn1      | db02 | mysql | 172.18.1.77 | 3306 | W    |      0 |    1 | 1000 |      18 |         5 |          0 |
| dn1      | db03 | mysql | 172.18.1.78 | 3306 | R    |      0 |    3 | 1000 |      21 |         5 |          0 |
| dn1      | db04 | mysql | 172.18.1.79 | 3306 | R    |      0 |    4 | 1000 |      24 |         8 |          0 |
+----------+------+-------+-------------+------+------+--------+------+------+---------+-----------+------------+
4 rows in set (0.01 sec)
测试mycat读写分离:(mycat-02节点)
  • 当前server_id=1的节点为主节点,server_id=2的master节点是备主库,所以备主库也暂时作为读库使用
  • 因为 balance="1"
mysql -uroot -p123456 -h127.0.0.1 -P8066 -e "show variables like 'server_id';"

img

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在输入中…………

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值