V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hansonwang99
V2EX  ›  Blogger

基于代理的数据库分库分表框架 Mycat 实践

  •  
  •   hansonwang99 · 2018-12-20 07:39:13 +08:00 · 1422 次点击
    这是一个创建于 1954 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Profile

    文章共 1796 字,阅读大约需要 4 分钟 !


    概 述

    在如今海量数据充斥的互联网环境下,分库分表的意义我想在此处就不用赘述了。而分库分表目前流行的方案最起码有两种:

    • 方案一:基于应用层的分片,即应用层代码直接完成分片逻辑
    • 方案二:基于代理层的分片,即在应用代码和底层数据库中间添加一层代理层,而分片的路由规则则由代理层来进行处理

    而本文即将要实验的 MyCAT 框架就属于第二种方案的代表作品。


    环境规划

    在本文中,我拿出了三台 Linux 主机投入试验,各节点的角色分配如下表所示:

    节点 | 部署组件 | 角色 | :---: | :---: | :---: | 192.168.199.75 | MySQL、MyCAT | master 192.168.199.74 | MySQL | slave 192.168.199.76 | MySQL | standby master

    如果说上面这张表不足以说明实验模型,那接下来再给一张图好了,如下所示:

    实验模型

    我想这样看来的话,各个节点布了哪些组件,节点间的角色关系应该一目了然了吧

    实验环境规划好了以后,接下来进行具体的部署与实验过程,首先当然是 MyCAT 代理的部署


    MyCAT 部署

    关于该部分,网上教程实在太多了,但最好还是参考官方文档来吧,下面也简述一下部署过程

    • 下载 MyCAT 并解压安装

    这里安装的是 MyCAT 1.5

    wget https://raw.githubusercontent.com/MyCATApache/Mycat-download/master/1.5-RELEASE/Mycat-server-1.5.1-RELEASE-20161130213509-linux.tar.gz
    tar -zxvf Mycat-server-1.5.1-RELEASE-20161130213509-linux.tar.gz
    mv mycat /usr/local/
    
    • 启动 MyCAT
    ./mycat start
    

    MyCAT 启动日志

    • MyCAT 连接测试
    mysql -utest -ptest -h127.0.0.1 -P8066 -DTESTDB
    

    MyCAT 连接成功


    MyCAT 配置

    官网上对于这一部分的描述是非常详细的,MyCAT 配置主要涉及三个 XML 配置文件:

    • server.xml:MyCAT 框架的系统参数 /用户参数配置文件
    • schema.xml:MyCAT 框架的逻辑库表与分片的配置文件
    • rule.xml :MyCAT 框架的逻辑库表分片规则的配置文件

    用如下图形可以形象地表示出这三个 XML 配置文件的配置内容和相互关系:

    三个与 MyCAT 相关的 xml 配置

    下面来进入具体的实验环节 ,这也是围绕 MyCAT 提供的几大主要功能展开的,主要涉及三个方面

    • 分库分表
    • 读写分离
    • 主备切换

    实验之前,我们先给出公共的 server.xml文件的配置,这部分后续实验过程中并不修改,其也就是定义了系统参数和用户参数:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mycat:server SYSTEM "server.dtd">
    <mycat:server xmlns:mycat="http://org.opencloudb/">
    	<system>
    	<property name="defaultSqlParser">druidparser</property>
          <!--  <property /> 这块诸多的 property 配置在此就不配置了,参照官网按需配置 -->
    	</system>
    	<user name="test">
    		<property name="password">test</property>
    		<property name="schemas">TESTDB</property>
    	</user>
    
    	<user name="user">
    		<property name="password">user</property>
    		<property name="schemas">TESTDB</property>
    		<property name="readOnly">true</property>
    	</user>
    
    </mycat:server>
    

    分库分表实验

    预期实验效果:通过 MyCAT 代理往一张逻辑表中插入的多条数据,在后端自动地分配在不同的物理数据库表上

    我们按照本文 **第二节 [环境规划] **中给出的实验模型图来给出如下的 MyCAT 逻辑库配置文件 schema.xml 和 分库分表规则配置文件 rule.xml

    • 准备配置文件

    schema.xml

    <?xml version="1.0"?>
    <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
    <mycat:schema xmlns:mycat="http://org.opencloudb/" >
    
    	<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
    		<table name="travelrecord" dataNode="dn1,dn2" rule="sharding-by-month" />
    	</schema>
    	
    	<dataNode name="dn1" dataHost="testhost" database="db1" />
    	<dataNode name="dn2" dataHost="testhost" database="db2" />
    	
    	<dataHost name="testhost" maxCon="1000" minCon="10" balance="0"
    		writeType="0" dbType="mysql" dbDriver="native" switchType="-1"  slaveThreshold="100">
    		<heartbeat>select user()</heartbeat>
    		<writeHost host="hostM1" url="localhost:3306" user="root" password="xxxxxx">
                    <readHost host="hostS1" url="192.168.199.74:3306" user="root" password="xxxxxx" />
    		</writeHost>
    		<writeHost host="hostM2" url="192.168.199.76:3306" user="root" password="xxxxxx">
    		</writeHost>
    	</dataHost>
    
    </mycat:schema>
    

    其中定义了实验用到的 hostM1、hostS1 和 hostM2

    rule.xml

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

    这里配置了 sharding-by-month的分库分表规则,即按照表中的 create_date字段进行分割,从 2018-11-01日期开始,月份不同的数据落到不同的物理数据库表中

    • 在三个物理节点数据库上分别创建两个库 db1 和 db2
    create database db1;
    create database db2;
    
    • 连接 MyCAT
    mysql -utest -ptest -h127.0.0.1 -P8066 -DTESTDB
    
    • 通过 MyCAT 来创建数据库 travelrecord
    create table travelrecord (id bigint not null primary key,city varchar(100),create_date DATE);
    
    • 通过 MyCAT 来往travelrecord表中插入两条数据
    insert into travelrecord(id,city,create_date)  values(1,'NanJing','2018-11-3');
    insert into travelrecord(id,city,create_date)  values(2,'BeiJing','2018-12-3');
    

    通过 MyCAT 往逻辑库中插入数据

    由于插入的这两条记录的 create_date分别是 2018-11-32018-12-3,而我们配的分库分表的规则即是根据 2018-11-01这个日期为起始来进行递增的,按照前面我们配的分片规则,理论上这两条记录按照 create_date日期字段的不同,应该分别插入到 hostM1 的 db1 和 db2 两个不同的数据库中。

    • 验证一下数据分片的效果

    数据分片的效果

    由于 hostM1hostS1组成了 主-从库 关系,因此刚插入的两条数据也应该相应自动同步到 hostS1db1db2两个数据库中,不妨也来验证一下:

    主从数据库同步也是 OK 的


    读写分离实验

    **预期实验效果:**开启了 MyCAT 的读写分离机制后,读写数据操作各行其道,互不干扰

    此节实验用到的配置文件 schema.xmlrule.xml基本和上面的 [分库分表] 实验没什么不同,只是我们需要关注一下 schema.xml配置文件中 <dataHost />标签里的 balance字段,它是与读写分离息息相关的配置:

    因此我们就需要弄清楚 <datahost> 标签中 balance 参数的含义:</datahost>

    • balance="0":不开启读写分离机制,即读请求仅分发到 writeHost 上
    • balance="1":读请求随机分发到当前 writeHost 对应的 readHost 和 standby writeHost 上
    • balance="2":读请求随机分发到当前 dataHost 内所有的 writeHost / readHost 上
    • balance="3":读请求随机分发到当前 writeHost 对应的 readHost 上

    我们验证一下 balance="1"的情况,即开启读写分离机制,且读请求随机分发到当前 writeHost 对应的 readHost 和 standby writeHost 上,而对于本文来讲,也即:hostS1 和 hostM2 上

    我们来做两次数据表的 SELECT读操作:

    mysql> select * from travelrecord limit 6;
    +----+----------+-------------+
    | id | city     | create_date |
    +----+----------+-------------+
    |  3 | TianJing | 2018-11-04  |
    |  5 | ShenYang | 2018-11-05  |
    |  4 | Wuhan    | 2018-12-04  |
    |  6 | Harbin   | 2018-12-05  |
    +----+----------+-------------+
    4 rows in set (0.08 sec)
    
    mysql> select * from travelrecord limit 6;
    +----+---------+-------------+
    | id | city    | create_date |
    +----+---------+-------------+
    |  2 | BeiJing | 2018-12-03  |
    |  8 | WuXi    | 2018-12-06  |
    |  1 | NanJing | 2018-11-03  |
    |  7 | SuZhou  | 2018-11-06  |
    +----+---------+-------------+
    4 rows in set (0.01 sec)
    

    然后我们取出 mycat.log日志查看一下具体详情,我们发现第一次 select读操作分发到了 hostM2上:

    第一次 select 读操作分发到了 hostM2 上

    而第二次 select读操作分发到了 hostS1上:

    第二次 select 读操作分发到了 hostS1 上


    主备切换实验

    **预期实验效果:**开启 MyCAT 的主备机制后,当主库宕机时,自动切换到备用机进行操作

    关于主备切换,则需要弄清楚 <dataHost /> 标签中 switchType参数的含义:

    • switchType="-1":不自动切换主备数据库
    • switchType="1":自动切换主备数据库
    • switchType="2":基于 MySQL 主从复制的状态来决定是否切换,需修改 heartbeat 语句:show slave status
    • switchType="3":基于 Galera (集群多节点复制)的切换机制,需修改 heartbeat 语句:show status like 'wsrep%'

    此处验证一下 Mycat 的主备自动切换效果。为此首先我们将 switchType="-1" 设置为 switchType="1",并重启 MyCat 服务:

    <dataHost name="testhost" maxCon="1000" minCon="10" balance="0"
            writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
    

    在本实验环境中,在 hostM1hostM2均正常时,默认写数据时是写到 hostM1

    • 接下来手动停止 hostM1 上的 MySQL 数据库来模拟 hostM1 宕机:
    systemctl stop mysqld.service
    

    接下来再通过 MyCat 插入如下两条数据:

    insert into travelrecord(id,city,create_date)  values(3,'TianJing','2018-11-4');
    insert into travelrecord(id,city,create_date)  values(4,'Wuhan','2018-12-4');
    

    效果如下:

    hostM1 宕机后,备用 hostM2 升级为主写节点

    • 此时,我们恢复 hostM1,但接下来的数据写入依然进入 hostM2
    insert into travelrecord(id,city,create_date)  values(5,'ShenYang','2018-11-5');
    insert into travelrecord(id,city,create_date)  values(6,'Harbin','2018-12-5');
    

    虽然 hostM1 恢复,但依然不是主写节点

    • 接下来手动让 hostM2宕机,看 hostM1 是否能升级为主写节点

    再插入两条数据:

    insert into travelrecord(id,city,create_date)  values(7,'SuZhou','2018-11-6');
    insert into travelrecord(id,city,create_date)  values(8,'WuXi','2018-12-6');
    

    hostM2 宕机后,hostM1 再次升级为主写节点

    很明显,答案是肯定的


    后 记

    由于能力有限,若有错误或者不当之处,还请大家批评指正,一起学习交流!



    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4515 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 10:03 · PVG 18:03 · LAX 03:03 · JFK 06:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.