更多优质内容
请关注公众号

Mysql进阶之Mycat中间件(一) mycat的安装和初步使用-张柏沛IT博客

正文内容

Mysql进阶之Mycat中间件(一) mycat的安装和初步使用

栏目:数据库 系列:Mysql进阶系列 发布时间:2020-01-29 10:12 浏览量:3502

Mycat中间件

我们知道水平分表会给业务层带来很多麻烦,例如

有一个记录获奖人员的表,每年都会有获奖新人录入到这个表中
我们以时间为维度进行表的切分,形式如下:

t_archieve_2016
t_archieve_2017
t_archieve_2018
...

如果想要进行新增,我们要获取当前的年份,根据当前年份找到对应的表进行插入

如果想根据id查询,我们就要进行union联合查询。

如果上面的表不是在同一个节点而是分布在不同的节点,那么业务层的判断会更多。

为了解决这个问题,Mycat就出现了。有了Mycat之后,Mycat连接数据库服务(Mycat可能是连一个节点的数据库也可能是连多个节点的数据库),而业务层直接连接Mycat服务而不直接连接mysql服务。无论是分库还是分表,无论分库分表是否在同一个节点,Mycat提供给业务层的都只是一个正常的库和一张正常的表。查询语句该找哪个节点的哪个表是Mycat该做的事,不是业务层该关心的事。这样一来业务层的逻辑就会减少很多判断,简单很多。

由于mycat是处于Web应用和MySQL之间的一个桥梁角色,所以mycat是一种中间件。中间件连接着Web应用和MySQL,Web应用和MySQL不直接连接。

Mycat使用的也是mysql的协议,换句话说就是,任何mysql客户端的命令,语法对Mycat都是有效的。我们可以用mysql -uroot -p来连接Mycat客户端,可以用select语句在mycat查询等。

 

Mycat的安装

Mycat是基于Java实现的,所以要先安装Java。

到官网下载Java SE 的rpm包。
官网下载mycat

# 安装Java
rpm -ivh jdk-13.0.2_linux-x64_bin.rpm

# 安装mycat
tar -xzf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz

mv mycat /usr/local

mycat命令是/usr/local/mycat/bin/mycat,将其写入环境变量中

# 启动
mycat console       # 前台运行

* 启动时报错说
Unrecognized VM option 'AggressiveOpts'
Error: Could not create the Java Virtual Machine.
关键是第一句,说虚拟机识别不了AggressiveOpts参数。
第二句说启动不了Java虚拟机。

# 修改mycat配置文件
vi /usr/local/mycat/conf/wrapper.conf

找到
wrapper.java.additional.3=-XX:+AggressiveOpts
将其注释即可。

* 作者遇到的启动报错是:
Invalid maximum heep size: -Xmx4G
Error: Could not create the Java Virtual Machine.
是配给Java的内存过高,我的服务器的内存不够

# 修改mycat配置文件
vi /usr/local/mycat/conf/wrapper.conf

找到
wrapper.java.additional.4=-XX:MaxDirectMemorySize=2G

wrapper.java.additional.9=-Xmx4G
wrapper.java.additional.10=-Xms1G

将2G、4G、1G改为512M即可

# 将所有的真实节点的MySQL设置为忽略表名大小写,否则后面会有很多问题,只需在mysql配置文件的[mysqld]加一条
lower_case_table_names=1 

记得重启
可以通过 show variables like "%case%";  查看是否开启忽略大小写

忽略表名大小写其实是将你在sql语句中的表名转为小写。
所以如果你的表名一开始是大写的,之后才开启忽略大小写,那么无论你的sql语句里的表名是大写还是小写,都会提示报错说找不到这个表,因为他都转成小写了,而你的表名是大写的。

如果MySQL没有开启忽略大小写,在mycat中创建表的时候,即使你的sql是小写的表名,在mysql真实节点中创建的都是大写的表名。

# 启动 
mycat console 

# 启动成功后,mycat监听了8066端口,此时可以在本地连接mycat(要开放8066端口的防火墙);我是在204.175.124.51这个机器上安装的mycat
mysql -h204.175.124.51 -uroot -P8066 -p123456

此时连的是mycat而不是mysql,mysql是3306端口。

mycat连接的默认用户和密码是 root、123456,其配置在/usr/local/mycat/conf/server.xml
mycat中有一个初始的库默认是TESTDB这个库(是一个虚拟库,真实不存在这样的库),其配置在/usr/local/mycat/conf/schema.xml

这两个配置文件至关重要 

 

mycat初认识:

现在我们要解决3个问题:
1.root/123456用户是怎么生成的
2.TESTDB这个库和里面的表是怎么生成的


第一个问题:Mycat中的用户如何生成
Mycat中的用户是在server.xml这个配置文件中添加并通过重启mycat服务生成的。
先来看一下server.xml这个文件里面关于用户的配置如下

<user name="root" defaultAccount="true">
    <property name="password">123456</property>
    <property name="schemas">TESTDB</property>
    <property name="defaultSchema">TESTDB</property>
    <!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
    
    <!-- 表级 DML 权限设置 -->
    <!--         
    <privileges check="false">
        <schema name="TESTDB" dml="0110" >
            <table name="tb01" dml="0000"></table>
            <table name="tb02" dml="1111"></table>
        </schema>
    </privileges>        
     -->
</user>

<user name="user">
    <property name="password">user</property>
    <property name="schemas">TESTDB</property>
    <property name="readOnly">true</property>
    <property name="defaultSchema">TESTDB</property>
</user>
 


这里设置了两个用户并赋予他们权限:
用户 root 密码 123456 该用户能对表TESTDB有增删改查操作
用户 user 密码 user   该用户只能对TESTDB进行读操作

我们可以在下面继续添加用户:

<user name="hello">
    <property name="password">hello</property>
    <property name="schemas">TESTDB,db2</property>      <!-- 指定能操作的数据库,这里可以通过逗号隔开指定操作多个数据库 -->
</user>

这是最简单的添加mycat用户的方法。这里是在mycat添加用户,但并没有对MySQL添加用户。一般来说,添加用户是为了管理schema(虚拟表),每个schema都需要在server.xml中定义(创建)一个用户来对该schema进行管理,此时只有该用户可以对该schema进行操作。

 

第二个问题:mycat中的库和表怎么生成的虚拟表是在schema.xml这个配置文件中指定,然后通过重启mycat而生成的。

<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
    <!-- auto sharding by id (long) -->
    <!--splitTableNames 启用<table name 属性使用逗号分割配置多个表,即多个表使用这个配置-->
    <table name="travelrecord,address" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" splitTableNames ="true"/>
    <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
        /> -->
</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="123456">
    </writeHost>
    <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>

-----------------------------------
<schema>指定了TESTDB这个虚拟库,里面<table>指定TESTDB这个虚拟库中要生成哪些虚拟表。这里指定生成 travelrecord 和 address这两个虚拟表。<table>的dataNode属性表示,这两个虚拟表要和哪些节点的真实物理表进行关联。
-----------------------------------
<dataHost>用于指定mycat要连接的Mysql的节点信息,包括节点IP,用户和密码。
<heartbeat>用于隔一段时间探测所连接的MySQL节点是否已断掉。
<writeHost>指定写节点
<readHost>指定读节点
------------------------------------

<dataNode>指定分片节点,即真实的数据库是哪个节点(dataHost属性)的哪个库(database属性)。


注意点:
虚拟表和真实物理表的表名相同。
可以在mycat登录的客户端中创建真实表,其对应的所有真实节点都会创建这个表。

 

 

下面做一个小实例:
mycat下创建一个shop虚拟数据库,该库下面创建product虚拟表,对应本机节点的shop1,shop2和shop3这3个库(即Mycat和Mysql都在一台主机上)。product表结构如下:

create table product (
    id int primary key auto_increment,
    name varchar(255),
    price decimal(10,2)
)engine=innodb;


下面是实操的步骤:1.修改schema.xml 

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="shop" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
        <!-- auto sharding by id (long) -->
        <!--splitTableNames 启用<table name 属性使用逗号分割配置多个表,即多个表使用这个配置-->
        <table name="product" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" splitTableNames ="true"/>
        <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
            /> -->
    </schema>
    <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
        /> -->
    <dataNode name="dn1" dataHost="h1" database="shop1" />
    <dataNode name="dn2" dataHost="h1" database="shop2" />
    <dataNode name="dn3" dataHost="h1" database="shop3" />
    
    <dataHost name="h1" 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="xxxx">
            <readHost host="hostM2" url="localhost:3306" user="root" password="xxxx"></readHost>
        </writeHost>
        <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
    </dataHost>
</mycat:schema>

定义了写节点和读节点,这两个节点是同一个节点同一个MySQL服务。
如果不创建读节点<readHost>,那么你在mycat中只能写入,不能查询。
writeHost和readHost使用的用户是MySQL真实用户而非mycat的登录用户。

2.为shop这个虚拟库创建一个用户,该用户专门用来操作shop虚拟库
在server.xml中,添加:

<user name="zbp">
    <property name="password">123456</property>
    <property name="schemas">shop</property>
</user> 

PS:已知server.xml定义了一个root/123456的用户,该用户专门用来操作TESTDB虚拟库。
但是如果schema.xml中没有定义TESTDB这个虚拟库,那么启动mycat时就会报错。

3.重启mycat服务。4.在本地连接203.195.174.151的mycat服务,并创建product真实物理表。

mysql -h203.195.174.151 -uzbp -P8066 -p123456

show databases;
+----------+
| DATABASE |
+----------+
| shop     |
+----------+

use shop;

show tables;
+----------------+
| Tables in shop |
+----------------+
| product        |
+----------------+

# 此时在MySQL中还没有创建shop1,shop2,shop3这3个真实的库,但是在mycat中依然能看到shop虚拟库和product虚拟表
但是如果对product虚拟表查询,会报错说不存在这个表。

# 现在在mysql中创建shop1,shop2,shop3这3个库

create database shop1;
create database shop2;
create database shop3;

# 在本地mycat客户端的shop虚拟表中创建product表:

create table product (
    id int primary key auto_increment,
    name varchar(255),
    price decimal(10,2)
)engine=innodb;

# 此时会同时在shop1~3都创建这个product表。

现在插入一条数据

insert into product values (null,"A",12);   # 报错:ERROR 1064 (HY000): partition table, insert must provide ColumnList

# 意思是插入时要指定所有的字段名
insert into product (`id`,`name`,`price`) values (null,"A",12);     # 报错:ERROR 1064 (HY000): columnValue:NULL Please eliminate any quote and non number within it.
# 意思时不能用null占位
insert into product (`id`,`name`,`price`) values (1,"A",12);    #插入成功

现在这条数据并非同时插入shop1~3,而是只插入了shop1;这里涉及到了mycat的分片规则,后面会详细介绍。

如果想查看到底插入了哪个库,可以

explain insert into product (`id`,`name`,`price`) values (1,"A",12);    #来查看

==============================================

Mycat表切分规则

在上面的例子中,插入的数据是插入到shop1这个库。但是随着数据量增大,数据也会插入到shop2和shop3这两个库,这要归因于在定义schema.xml的<table>标签中的rule="auto-sharding-long"这个属性。
该属性指定该product表使用auto-sharding-long(范围约定)这个分片规则来分片。

下面我们先看一下有哪些数据会写到shop1,哪些数据会写到shop2和shop3:

explain insert into product (id,name,price) values (10000000,"asdf",1000);
+-----------+-------------------------------------------------------------------------+
| DATA_NODE | SQL                                                                     |
+-----------+-------------------------------------------------------------------------+
| dn2       | INSERT INTO product (id, name, price) VALUES ('10000000', 'asdf', 1000) |
+-----------+-------------------------------------------------------------------------+

explain insert into product (id,name,price) values (15000000,"asdf",1000);
+-----------+-------------------------------------------------------------------------+
| DATA_NODE | SQL                                                                     |
+-----------+-------------------------------------------------------------------------+
| dn3       | INSERT INTO product (id, name, price) VALUES ('15000000', 'asdf', 1000) |
+-----------+-------------------------------------------------------------------------+

发现当id为500万到1000万就会插入节点2,即shop2;当id为1000万到1500万就会插入shop3;
超过1500万就会报错。

所以这里是根据id的大小范围来划分节点的,在mycat中用了range分区的技术。

这里的划分规则在schema.xml的<table>标签定义虚拟表的时候就定义好了的。

<table name="product" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" splitTableNames ="true"/>

这里的规则是rule="auto-sharding-long",即按范围约定分片(分区)。

而规则是在rule.xml定义的

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

上面的配置意思是对id字段进行分区,分区的算法是range-long
而range-long算法也可以在rule.xml找到。

<function name="rang-long"
          class="io.mycat.route.function.AutoPartitionByLong">
    <property name="mapFile">autopartition-long.txt</property>
</function>

表示这个算法是写在 AutoPartitionByLong 这个类文件中的,这个类是写在mycat的java源码中。

看不懂java源码没关系,重点看mapFile地图文件,该文件是具体的分区规则,在这里是autopartition-long.txt文件,该文件在mycat的配置目录中。

内容如下:

# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2

意思是 分区字段(id)在0~500万内就写入第一个节点,500玩~1000万写入第二个节点,后面一样的意思。

所以即使我们不会Java,我们也可以在地图文件中编写规则来简单的制定自定义规则。
mycat有多少中规则可以查看文档。
 

下一节我们将介绍Mycat中的一些基本概念和schema.xml/server.xml/rule.xml这三个配置文件的标签和属性的含义。




更多内容请关注微信公众号
zbpblog微信公众号

如果您需要转载,可以点击下方按钮可以进行复制粘贴;本站博客文章为原创,请转载时注明以下信息

张柏沛IT技术博客 > Mysql进阶之Mycat中间件(一) mycat的安装和初步使用

热门推荐
推荐新闻