Mycat--安装启动及配置读写分离、分库分表

一、Mycat简介

Mycat是个数据库中间件,前身是阿里的cobar。利用Mycat可以对数据库集群进行管理。

可以进行1.读写分离

2.数据分片

垂直拆分(分库)

水平拆分(分表)

垂直+水平拆分(分库分表)

3.多数据源整合

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

这种方式把数据库的分布式从代码中解耦出来,程序员察觉不出来后台使用mycat还是mysql。

二、Mycat的安装启动

解压缩安装文件到linux下 /usr/local下。

conf中的三个配置文件

schema.xml  定义逻辑库,表,分片节点等内容

rule.xml 定义分片规则

server.xml 定义用户以及系统相关变量,端口等。

1.启动mycat前先修改schema.xml配置文件

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
           <!--逻辑库    name名称,   checkSQLschema         sqlMaxLimit 末尾是否要加 limit xxx-->
        <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> </schema>
            <!--逻辑库    name名称,   dataHost 引用的哪个dataHost      database:对应mysql的database-->
        <dataNode name="dn1" dataHost="localhost1" database="db1" />
        <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>
        </dataHost>
</mycat:schema>

 2.修改一下server.xml

<user name="mycat">
                <property name="password">654321</property>
                <property name="schemas">TESTDB</property>
</user>

3.验证一下通过远程方式数据库是否能连接成功。

mysql -uroot -p123456 -h 192.168.6.10 -P 3306

如本机远程访问报错,请建对应用户
grant all privileges on *.* to root@'%'  identified by '123123';    //%代表所有远程用户

4.启动mycat客户端

控制台启动 :去mycat/bin 目录下 ./mycat console,能查看实时的日志信息。

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

5.登陆

mycat有两个端口,9066为后台管理窗口,8066为数据窗口,我们一般用8066进行登陆。

mysql -umycat -p123456 -P8066 -h192.168.67.131

三、使用mycat实现读写分离

读写分离肯定要求主从机器要实现主从复制,在主从复制的基础上进行读写分离。

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="db02" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="3"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm1" url="192.168.67.1:3306" user="root"
                                   password="123123">
<!--读库(从库)的配置 -->
                       <readHost host="hosts1" url="192.168.67.131:3306" user="root"
                                   password="123123">
                       </readHost>

                </writeHost>
        </dataHost>
</mycat:schema>
 

在读写分离这里,最重要的一个配置是balance,即负载均衡的类型,取值有四种。

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

当测试读写分离的时候一定要通过mycat去测试。

mycat -p123456 -u root -h ip地址 -P 8066

三、分库

一台机器上的MySQL是有性能瓶颈的,存储的数据不应过大,所以需要需采取分库的方式,比如一个商城系统,user表和order表信息都比较大,就可以将user表分到一台mysql主机的数据库上,order表分到另一台mysql主机上。由mycat进行管理。

#客户表  rows:20万 
CREATE TABLE customer(
    id INT AUTO_INCREMENT,
    NAME VARCHAR(200),
    PRIMARY KEY(id)
);
 
 
#订单表   rows:600万
CREATE TABLE orders(
    id INT AUTO_INCREMENT,
    order_type INT,
    customer_id INT,
    amount DECIMAL(10,2),
    PRIMARY KEY(id)  
); 
 
 
#订单详细表     rows:600万
CREATE TABLE orders_detail(
    id INT AUTO_INCREMENT,
    detail VARCHAR(2000),
    order_id INT,
    PRIMARY KEY(id)
);
 

一个商城系统中,由于数据量很大,所以要进行分库操作,但分也不能随便分,比如订单表要与订单详细表进行join连接查询,这就要求这两张表必须在同一个数据库下,因为跨库join是不允许的,所以需要用户一个库,订单与订单详细信息一个库。

shcema.xml配置文件

<mycat:schema xmlns:mycat="http://io.mycat/">
 
        <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
                <table name="customer" dataNode="dn2" ></table>
        </schema>
        <dataNode name="dn1" dataHost="host1" database=db02" />
        <dataNode name="dn2" dataHost="host2" database="db03" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="2"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm1" url="192.168.67.1:3306" user="root"
                                   password="123123">
                       <readHost host="hosts1" url="192.168.67.131:3306" user="root"
                                   password="123123">
                       </readHost>
                </writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm2" url="192.168.67.1:3306" user="root"
                                   password="123123">
                </writeHost>
        </dataHost>

 
</mycat:schema>

四、分表

shcema.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="customer" dataNode="dn2" ></table>
                <table name="orders" dataNode="dn1,dn2"  rule="mod_rule" ></table>
        </schema>
        <dataNode name="dn1" dataHost="host1" database="db01" />
        <dataNode name="dn2" dataHost="host2" database="db02" />
        <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.67.1:3306" user="root"
                                   password="123123">


                </writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostm2" url="192.168.67.1:3306" user="root"
                                   password="123123">
                </writeHost>
        </dataHost>

将orders表的数据分到dn1和dn2这两个节点对应的库,rule指分表的规则,mod_rule为我们指定的rule.xml文件的规则。

rule.xml

 
<tableRule name="mod_rule">
             <rule>

//按customer_id这个字段的值做哈希运算去分组
                        <columns>customer_id</columns>
                        <algorithm>mod-long</algorithm>
               </rule>
       </tableRule>
 
 //mycat提供了一种默认的分组方法,按哈希去分。我们要分到两个库中,所以count为2
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- how many data nodes -->
                <property name="count">2</property>
        </function>

跨库join由两种形式:1.ER表,为了相关联的表的行尽量分在一个库下。

schema.xml

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
                <table name="customer" dataNode="dn2" ></table>
                <table name="orders" dataNode="dn1,dn2"  rule="mod_rule" >
                    <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
                </table>
                <table name="dict_status" dataNode="dn1,dn2" type="global" ></table>
        </schema>

2.全局表,设定为全局的表,会直接复制给每个数据库一份,所有写操作也会同步给多个库。所以全局表一般不能是大数据表或者更新频繁的表,一般是字典表或者系统表为宜。

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
                <table name="customer" dataNode="dn2" ></table>
                <table name="orders" dataNode="dn1,dn2"  rule="mod_rule" ></table>
                 <table name="dict_order_type" dataNode="dn1,dn2" type="global" ></table>
        </schema>

五、全局序列

如果做了分库分表,那么主键如果是自增长,如何控制主键的唯一性?

1.本地文件,不安全,不推荐

2.数据库方式(推荐):

利用数据库一个表 来进行计数累加。
 
但是并不是每次生成序列都读写数据库,这样效率太低
mycat会预加载一部分号段到mycat的内存中,这样大部分读写序列都是在内存中完成的。
如果内存中的号段用完了 mycat会再向数据库要一次。
 
问:那如果mycat崩溃了 ,那内存中的序列岂不是都没了?
是的。如果是这样,那么mycat启动后会向数据库申请新的号段,原有号段会弃用。
也就是说如果mycat重启,那么损失是当前的号段没用完的号码,但是不会因此出现主键重复。

脚本函数

CREATE TABLE MYCAT_SEQUENCE (NAME VARCHAR(50) NOT NULL,current_value INT NOT
NULL,increment INT NOT NULL DEFAULT 100, PRIMARY KEY(NAME)) ENGINE=INNODB;
 
 
 
 
DELIMITER $$
 
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS VARCHAR(64)
DETERMINISTIC  
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT CONCAT(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval FROM
MYCAT_SEQUENCE WHERE NAME = seq_name;
RETURN retval;
END $$
DELIMITER;
 
DELIMITER $$
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = VALUE
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER ;
 
DELIMITER $$
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) 
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER;
 
 
SELECT * FROM MYCAT_SEQUENCE
 
TRUNCATE TABLE MYCAT_SEQUENCE
 
##增加要用的序列
INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDERS', 400000,
100);
 

配置sequence_db_conf.properties

表明全局序列在dn1这个主机上。

配置server.xml

重启mycat

插入语句时,在自增主键列调用我们的脚本函数即可

insert into `orders`(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);

3.时间戳方式:18位,太长

4.自主生成:可利用redis的单线程原子性incr来生成序列。

发布了227 篇原创文章 · 获赞 77 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/m2606707610/article/details/103752257
今日推荐