基于代理的数据库分库分表框架 Mycat 实践 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hansonwang99
V2EX    Blogger

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

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

    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     Solana     1087 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 18:13 PVG 02:13 LAX 10:13 JFK 13:13
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86