mycat详细

MyCAT的优势
基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能以及众多成熟的使用案例使得MYCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,我们能看到更远。业界优秀的开源项目和创新思路被广泛融入到MYCAT的基因中,使得MYCAT在很多方面都领先于目前其他一些同类的开源项目,甚至超越某些商业产品。
MYCAT背后有一支强大的技术团队,其参与者都是5年以上资深软件工程师、架构师、DBA等,优秀的技术团队保证了MYCAT的产品质量。
MYCAT并不依托于任何一个商业公司,因此不像某些开源项目,将一些重要的特性封闭在其商业产品中,使得开源项目成了一个摆设。


高可用方案和架构图如下:




 

 Mycat部署与使用 

MyCAT 可以视为“MySQL”集群的企业级数据库,用来替代昂贵的Oracle集群,其背后是阿里曾经开源的知名产品Cobar。MyCAT的目标是:低成本的将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。

下面就适合订单的业务场景做介绍

1 应用场景

Mycat 有很多数据分库规则,接下来几篇就相关觉得常用的规则进行试用与总结。

一般来说,按自然月份或按日期来进行数据分片的规则比较适用于商城订单查询,类似最近1周、2周、3个月内的数据。或是报表类应用。

这样的数据放在一个片区内省去了数据合并的时间。

当然按月数据量不要过大就OK。

一、部署步骤详解
(1) 用命令行工具或图形化客户端,连接MYSQL,创建DEMO所用三个分片数据库;

CREATE SCHEMA `range_db_01` DEFAULT CHARACTER SET utf8 ;
CREATE SCHEMA `range_db_02` DEFAULT CHARACTER SET utf8 ;
CREATE SCHEMA `range_db_03` DEFAULT CHARACTER SET utf8 ;
CREATE SCHEMA `range_db_04` DEFAULT CHARACTER SET utf8 ; 

(2) 修改配置my.cnf新增以下语句, 一般会放在/etc/my.cnf 或 /etc/mysql/my.cnf,设置为Mysql表名大小写不敏感,否则可能会发生表找不到的问题。

lower_case_table_names = 1 

(3) 解压Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz 到安装目录下,会生成mycat目录

(4) 安装jdk-7u79-linux-x64

(5) 修改mycat/conf/wrap.conf 修改wrapper.Java.command=java为上一步存放路径

wrapper.java.command=/usr/java/jdk1.7.0_79/ 

(6) 创建mycat 用户,改变目录权限为mycat

useradd mycat
chown -R mycat.mycat mycat 

(7) 修改用户密码

passwd mycat
输入: 

(8) 修改mycat/conf/schema.xml,URL、用户名、密码修改,其余不变

<writeHost host="hostM1" url="192.168.184.56:3306" user="root"
                       password="root"> 

二、运行步骤详解
(1) 进入 mycat/bin (默认数据端口为8066,管理端口为9066)
执行./mycat start
(2) 进入logs目录,查看日志,如果wrapper.log 报错 java.NET.BindException: Address already in use 杀掉正在执行的相关java进程

ps -ef|grep java
kill -9 xxx 

三、使用步骤详解
(1) 进入mysql bin目录mysql/bin/
(2) 登录mysql 执行以下命令
./mysql -utest -ptest -h192.168.184.56 -P8066 -DTESTDB

(mycat的用户账号和授权信息是在conf/server.xml文件中配置)
(3) 表创建测试:

mysql> create table employee (id int not null primary key,name varchar(100),sharding_id int not null);
Query OK, 0 rows affected (0.30 sec)
mysql> explain create table employee (id int not null primary key,name varchar(100),sharding_id int not null);
+-----------+------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL                                                                                            |
+-----------+------------------------------------------------------------------------------------------------+
| dn1       | create table employee (id int not null primary key,name varchar(100),sharding_id int not null) | 
| dn2       | create table employee (id int not null primary key,name varchar(100),sharding_id int not null) | 
+-----------+------------------------------------------------------------------------------------------------+
2 rows in set (0.04 sec) 

(4) 客户端软件使用:navicat
创建mycat新连接:ip:192.168.184.56,用户名:test,密码:test,端口:8066
可看到TESTDB数据库下已创建表:employee
打开db1,db2 数据库也可看到已创建表employee

(5) 插入数据测试

mysql> insert into employee(id,name,sharding_id) values(1,'leader us',10000);
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    6
Current database: TESTDB
Query OK, 1 row affected (0.03 sec)
mysql> explain insert into employee(id,name,sharding_id) values(1,'leader us',10000);
+-----------+-----------------------------------------------------------------------+
| DATA_NODE | SQL                                                                   |
+-----------+-----------------------------------------------------------------------+
| dn1       | insert into employee(id,name,sharding_id) values(1,'leader us',10000) | 
+-----------+-----------------------------------------------------------------------+
1 row in set (0.00 sec) 

(6) 根据规则auto-sharding-long(主键范围)进行分片测试

mysql> explain create table company(id int not null primary key,name varchar(100));
+-----------+---------------------------------------------------------------------+
| DATA_NODE | SQL                                                                 |
+-----------+---------------------------------------------------------------------+
| dn1       | create table company(id int not null primary key,name varchar(100)) | 
| dn2       | create table company(id int not null primary key,name varchar(100)) | 
| dn3       | create table company(id int not null primary key,name varchar(100)) | 
+-----------+---------------------------------------------------------------------+
3 rows in set (0.01 sec) 

(7) 三个分片上都插入了3条数据

mysql> explain insert into company(id,name) values(1,'hp');
+-----------+---------------------------------------------+
| DATA_NODE | SQL                                         |
+-----------+---------------------------------------------+
| dn1       | insert into company(id,name) values(1,'hp') | 
| dn2       | insert into company(id,name) values(1,'hp') | 
| dn3       | insert into company(id,name) values(1,'hp') | 
+-----------+---------------------------------------------+
3 rows in set (0.00 sec) 

(8) 确认是分片存储

mysql> select * from employee;
+----+-----------+-------------+
| id | name      | sharding_id |
+----+-----------+-------------+
|  2 | me        |       10010 | 
|  4 | mydog     |       10010 | 
|  1 | leader us |       10000 | 
|  3 | mycat     |       10000 | 
+----+-----------+-------------+
4 rows in set (0.01 sec)
mysql> explain select * from employee;
+-----------+----------------------------------+
| DATA_NODE | SQL                              |
+-----------+----------------------------------+
| dn1       | SELECT * FROM employee LIMIT 100 | 
| dn2       | SELECT * FROM employee LIMIT 100 | 
+-----------+----------------------------------+
2 rows in set (0.00 sec)


mycat更详细阅读
 MySQL分布式集群之MyCAT
-----------------------------------------------------------------重要的TIPs-----------------------------------------------------------------------
MyCAT的团队已经发布了1.4Alpha版本,这其中修复了不少的bug,也添加了新功能,
博主这边测试用的是1.3的版本,所以和最新版本的测试结果可能出现不一致!

-------------------------------------------------------------------背景介绍------------------------------------------------------------------

MyCAT的背景介绍直接略过,没啥用,当然,这是一个由JAVA开发的东东,这一点需要了解~。

-----------------------------------------------------------------MyCAT的前身----------------------------------------------------------------
MyCAT的前身,是阿里巴巴于2012年6月19日,正式对外开源的数据库中间件Cobar,Cobar的前身是早已经开源的Amoeba,不过其作者陈思儒离职去盛大之后,阿里巴巴内部考虑到Amoeba的稳定性、性能和功能支持,以及其他因素,重新设立了一个项目组并且更换名称为Cobar。Cobar是由 Alibaba 开源的 MySQL 分布式处理中间件,它可以在分布式的环境下看上去像传统数据库一样提供海量数据服务。

Cobar自诞生之日起, 就受到广大程序员的追捧,但是自2013年后,几乎没有后续更新。在此情况下,MyCAT应运而生,它基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能,以及众多成熟的使用案例使得MyCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,MyCAT能看到更远。

---------------------------------------------------------MyCAT的下载方式--------------------------------------------------------------------
MyCAT的SVN地址为:http://code.taobao.org/svn/openclouddb/

---------------------------------------------------------MyCAT的重要特性--------------------------------------------------------------------
支持 SQL 92标准;
支持MySQL集群,可以作为Proxy使用;
支持JDBC连接ORACLE、DB2、SQL Server,将其模拟为MySQL Server使用;
支持galera for mysql集群,percona-cluster或者mariadb cluster,提供高可用性数据分片集群;
自动故障切换,高可用性;
支持读写分离,支持MySQL双主多从,以及一主多从的模式;
支持全局表,数据自动分片到多个节点,用于高效表关联查询;
支持独有的基于E-R 关系的分片策略,实现了高效的表关联查询;
多平台支持,部署和实施简单。

------------------------------------------------------------MyCAT的体系结构----------------------------------------------------------------

总体上分成三个部分,最前端的是连接器,线程管理使用了资源池,并且默认采用了AIO的方式(这些基本信息可以再启动日志里面看到);
中间层在图中已经描述的很清楚了,SQL解析器+SQL路由,SQL Executor需要具体看源码才能了解,因为通过这段时间对MyCAT的测试,没有感觉到SQL Executor的存在,更多的感觉是一个SQL process的东西,DataNode和心跳检测算是中间层实现的两个组件,一个是和MySQL的库(注意,不是实例)相关,一个是常见的监测机制的功能模块;
最下层的存储就是是MySQL的集群了~怎么玩MySQL的集群,由我们自己决定╰(?? ▽ ??)╯。

 
--------------------------------------------------------------怎么使用MyCAT---------------------------------------------------------- 
MyCAT目前通过配置文件的方式来定义逻辑库和相关配置,主要是包括三个文件:
MYCAT_HOME/conf/schema.xml中定义逻辑库,表、分片节点等内容;
 MYCAT_HOME/conf/rule.xml中定义分片规则;
MYCAT_HOME/conf/server.xml中定义用户以及系统相关变量,如端口等。

 不着急,这一篇简单介绍这几个配置文件的作用和一些参数的意义。
一个一个来,先看schema.xml,这是从网上摘抄的一个示例模板                

点击(此处)折叠或打开

  1. <?xml version="1.0"?>
  2. <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
  3. <mycat:schema xmlns:mycat="http://org.opencloudb/">
  4.     <schema name="weixin" checkSQLschema="false" sqlMaxLimit="100" dataNode="weixin" >
  5.         
  6.     
  7.     <schema name="yixin" checkSQLschema="false" sqlMaxLimit="100" dataNode="yixin" />
  8.         
  9.     
  10.     <dataNode name="dn1" dataHost="localhost0" database="weixin" />
  11.     <dataNode name="dn2" dataHost="localhost0" database="yixin" />
  12.     <dataHost name="localhost0" maxCon="450" minCon="10" balance="1"
  13.        writeType="0" dbType="mysql" dbDriver="native">
  14.        <heartbeat>select user()</heartbeat>
  15.        <!-- can have multi write hosts -->
  16.        <writeHost host="hostM1" url="localhost:3306" user="root" password="123456" />
  17.            <readHost host="hostS1" url="localhost:3307" user="test" password="123456" />
  18.     </dataHost>
  19. </mycat:schema>
首先是schema name = "weixin",这一项配置以后的效果就是,当MySQL客户端连接MyCAT时,通过Show DATABASE命令,能看到的数据库的,名字,
比如在这个配置文件里面,就配置了两个数据库,weixin和yixin,这两个库各自包含一张user表。
注意:MyCAT对外端显示出来的数据库,和数据库里面的表,全部在schema里面配置,没有写在这个里面的表或者库,即使后端的MySQL里面存在,也无法通过MyCAT去访问,不过MyCAT不会去定义具体表的结构。
然后是datanode,这个属性指定了schema的表,具体存放在哪个数据库,比如这个配置里面,指定了dn1的数据节点位于localhost0,这个数据库实例的名为weixin的数据库,dn2同理。
datahost列出了实际的后端MySQL集群的具体信息,writehost是负责写入数据的MySQL实例,writehost是负责读的MySQL实例,如果两个实例的具体信息写成一样,那就意味着后端使用单实例,如果配置成不同的实例,那么就在两个实例之间配置主从同步,然后通过MyCAT实现读写分离
对数据库进行垂直切分,主要由schema.xml来完成,这个以后再详细介绍。

rule.xml如示例

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mycat:rule SYSTEM "rule.dtd">
  3. <mycat:rule xmlns:mycat="http://org.opencloudb/"> 
  4.  <tableRule name="rule">
  5.     <rule>
  6.       <columns>user_id</columns>
  7.       <algorithm>func1</algorithm>
  8.     </rule>
  9.  </tableRule>
  10.  <function name="func1" class="org.opencloudb.route.function.PartitionByLong">
  11.     <property name="partitionCount">2</property>
  12.     <property name="partitionLength">512</property>
  13.  </function>
  14. </mycat:rule>
                
rule.xml里面的配置主要用于对表的水平切分,MyCAt本身提供了很多种水平切分的策略,这个示例显示的是取模分片,总共分成四片,user_id对1024取模,然后分成两片,每一片512个。
其他的切分策略以后再详细介绍

server.xml如示例

点击(此处)折叠或打开

  1. <!DOCTYPE mycat:server SYSTEM "server.dtd">
  2. <mycat:server xmlns:mycat="http://org.opencloudb/">
  3.     <system>
  4.         <property name="sequnceHandlerType">0</property> 
  5.     </system>
  6.     <user name="test">
  7.        <property name="password">test</property>
  8.        <property name="schemas">weixin,yixin</property>
  9.     </user>
  10. </mycat:server>

server.xml里面配置MyCAT的逻辑库参数,如示例,配置的就是逻辑库weixin和yixin的登录用户名和密码
这个XML里面其实还有一些有关于MyCAT性能调整的参数,不过略去了,东西太多,以后再详细介绍

----------------------------------------------------------------------华丽的分割线-------------------------------------------------------------

简单的MyCAT搭建大致上就包括这些内容,现在讲讲使用一段时间以后,对MyCAT的一些总结;
1.MyCAT的性能表现还是不错的,这几天一直对MyCAT的各方面进行测试,发现MyCAT作为一个代理,虽然是在JAVA虚拟机上面运行,但是面对接近9K的QPS的峰值的时候,本身并没有出现无响应或者丢失连接的问题;
2.MyCAT对前端显示的所有的库,表,全部由schema来配置,但是本身不定义表结构,这使得后端的表结构如果出现不一致,MyCAT前端是察觉不到的,不太方便吧;
3.第二点的不方便,也反映了一点,没有配置到schema的表,完全无法通过MyCAT去操作,这也算是安全性良好的一个表现吧;
4.之前说SQL Executor没感觉到,也是因为在一些测试中,发现MyCAT更像一个提供转发和结果合并功能的代理,只是对SQL和结果进行了process,不过这个需要去看源代码才知晓细节了。

这次只打算写这么多,关于MyCAT的一些细节介绍,留给下一章~
 
 在第一部分,有简单的介绍MyCAT的搭建和配置文件的基本情况,这一篇详细介绍schema的一些具体参数,以及实际作用
        首先贴上自己测试用的schema文件,双引号之前的反斜杠不会消除,姑且当成不存在吧...

点击(此处)折叠或打开

  1. <?xml version=\"1.0\"?>
  2. <!DOCTYPE mycat:schema SYSTEM \"schema.dtd\">
  3. <mycat:schema xmlns:mycat=\"http://org.opencloudb/\">
  4.     <schema name=\"mycat\" checkSQLschema=\"false\" sqlMaxLimit=\"100\">
  5.         <!-- auto sharding by id (long) -->
  6.         <table name=\"students\" dataNode=\"dn1,dn2,dn3,dn4\" rule=\"rule1\" />
  7.         <table name=\"log_test\" dataNode=\"dn1,dn2,dn3,dn4\" rule=\"rule2\" />
  8.         <!-- global table is auto cloned to all defined data nodes ,so can join 
  9.             with any table whose sharding node is in the same data node -->
  10.         <!--<table name=\"company\" primaryKey=\"ID\" type=\"global\" dataNode=\"dn1,dn2,dn3\" />
  11.         <table name=\"goods\" primaryKey=\"ID\" type=\"global\" dataNode=\"dn1,dn2\" />
  12.             -->
  13.         <table name=\"item_test\" primaryKey=\"ID\" type=\"global\" dataNode=\"dn1,dn2,dn3,dn4\" />
  14.         <!-- random sharding using mod sharind rule -->
  15.         <!-- <table name=\"hotnews\" primaryKey=\"ID\" dataNode=\"dn1,dn2,dn3\"
  16.             rule=\"mod-long\" /> -->
  17.             <!-- 
  18.         <table name=\"worker\" primaryKey=\"ID\" dataNode=\"jdbc_dn1,jdbc_dn2,jdbc_dn3\" rule=\"mod-long\" />
  19.  -->
  20.         <!-- <table name=\"employee\" primaryKey=\"ID\" dataNode=\"dn1,dn2\"
  21.             rule=\"sharding-by-intfile\" />
  22.         <table name=\"customer\" primaryKey=\"ID\" dataNode=\"dn1,dn2\"
  23.             rule=\"sharding-by-intfile\">
  24.             <childTable name=\"orders\" primaryKey=\"ID\" joinKey=\"customer_id\"
  25.                 parentKey=\"id\">
  26.                 <childTable name=\"order_items\" joinKey=\"order_id\"
  27.                     parentKey=\"id\" />
  28.             <ildTable>
  29.             <childTable name=\"customer_addr\" primaryKey=\"ID\" joinKey=\"customer_id\"
  30.                 parentKey=\"id\" /> -->
  31.     </schema>
  32.     <!-- <dataNode name=\"dn\" dataHost=\"localhost\" database=\"test\" /> -->
  33.     <dataNode name=\"dn1\" dataHost=\"localhost\" database=\"test1\" />
  34.     <dataNode name=\"dn2\" dataHost=\"localhost\" database=\"test2\" />
  35.     <dataNode name=\"dn3\" dataHost=\"localhost\" database=\"test3\" />
  36.     <dataNode name=\"dn4\" dataHost=\"localhost\" database=\"test4\" />
  37.     <!-- 
  38.     <dataNode name=\"jdbc_dn1\" dataHost=\"jdbchost\" database=\"db1\" />
  39.     <dataNode name=\"jdbc_dn2\" dataHost=\"jdbchost\" database=\"db2\" />
  40.     <dataNode name=\"jdbc_dn3\" dataHost=\"jdbchost\" database=\"db3\" />
  41.  -->
  42.     <dataHost name=\"localhost\" maxCon=\"100\" minCon=\"10\" balance=\"1\"
  43.         writeType=\"1\" dbType=\"mysql\" dbDriver=\"native\">
  44.         <heartbeat>select user()<beat>
  45.         <!-- can have multi write hosts -->
  46.         <writeHost host=\"localhost\" url=\"localhost:3306\" user=\"root\" password=\"wangwenan\">
  47.             <!-- can have multi read hosts -->
  48.             <readHost host=\"hostS1\" url=\"localhost:3307\" user=\"root\" password=\"wangwenan\"/>
  49.         </writeHost>
  50.         <writeHost host=\"localhost1\" url=\"localhost:3308\" user=\"root\" password=\"wangwenan\">
  51.             <!-- can have multi read hosts -->
  52.             <readHost host=\"hostS11\" url=\"localhost:3309\" user=\"root\" password=\"wangwenan\"/>
  53.         </writeHost>
  54.     </dataHost>
  55.         <!-- <writeHost host=\"hostM2\" url=\"localhost:3316\" user=\"root\" password=\"123456\"/> -->
  56.     <!-- 
  57.         <dataHost name=\"jdbchost\" maxCon=\"1000\" minCon=\"1\" balance=\"0\" writeType=\"0\" dbType=\"mongodb\" dbDriver=\"jdbc\">
  58.         <heartbeat>select user()<beat>
  59.         <writeHost host=\"hostM\" url=\"mongodb://192.168.0.99/test\" user=\"admin\" password=\"123456\" ></writeHost>
  60.     </dataHost>    
  61.     -->
  62.      <!-- 
  63.     <dataHost name=\"jdbchost\" maxCon=\"1000\" minCon=\"10\" balance=\"0\"
  64.         dbType=\"mysql\" dbDriver=\"jdbc\">
  65.         <heartbeat>select user()<beat>
  66.         <writeHost host=\"hostM1\" url=\"jdbc:mysql://localhost:3306\"
  67.             user=\"root\" password=\"123456\">
  68.         </writeHost>
  69.     </dataHost>
  70.      -->
  71. </mycat:schema>
        第一行参数<schema name="mycat" checkSQLschema="false" sqlMaxLimit="100"/>
                在这一行参数里面,schema name定义了可以在MyCAT前端显示的逻辑数据库的名字,
                checkSQLschema这个参数为False的时候,表明MyCAT会自动忽略掉表名前的数据库名,比如说mydatabase1.test1,会被当做test1;
                sqlMaxLimit指定了SQL语句返回的行数限制;
                     
                       
                如截图,这个limit会让MyCAT在分发SQL语句的时候,自动加上一个limit,限制从分库获得的结果的行数,另外,截图右上角可以看到,MyCAT本身也是有缓存的;
                那么,如果我们执行的语句要返回较多的数据行,在不修改这个limit的情况下,MyCAT会怎么做?
                      
                可以从截图看到,MyCAT完全就没搭理前端的实际需求,老老实实返回100条数据,所以如果实际应用里面需要返回大量数据,可能就得手动改逻辑了
                MyCAT的1.4版本里面,用户的Limit参数会覆盖掉默认的MyCAT设置 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                <table name="students" dataNode="dn1,dn2,dn3,dn4" rule="rule1" />
                这一行代表在MyCAT前端会显示哪些表名,类似几行都代表一样的意思,这里强调的是表,而MyCAT并不会在配置文件里面定义表结构
                    如果在前端使用show create table ,MyCAT会显示正常的表结构信息,观察Debug日志,
                      
                可以看到,MyCAT把命令分发给了dn1代表的数据库,然后把dn1的查询结果返回给了前端
                可以判断,类似的数据库级别的一些查询指令,有可能是单独分发给某个节点,然后再把某个节点的信息返回给前端;
               
                dataNode的意义很简单,这个逻辑表的数据存储在后端的哪几个数据库里面                
                rule代表的是这个逻辑表students的具体切分策略,目前MyCAT只支持按照某一个特殊列,遵循一些特殊的规则来切分,如取模,枚举等,具体的留给之后细说 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                
                <table name="item_test" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3,dn4" />
                这一行代表的是全局表,这意味着,item_test这张表会在四个dataNode里面都保存有完整的数据副本,那么查询的时候还会分发到所有的数据库么?
                      
                结果如截图,MyCAT依然是规规矩矩的返回了100条数据(╮(╯_╰)╭),而针对全局表的查询,只会分发到某一个节点上
                配置的primaryKey没发现作用在哪里,姑且忽略吧,以后发现了再补上

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                childtable我在测试中并没有实际用起来不过在MyCAT的设计文档里面有提到,childtable是一种依赖于父表的结构,
                这意味着,childtable的joinkey会按照父表的parentKey的策略一起切分,当父表与子表进行连接,且连接条件是childtable.joinKey=parenttable.parentKey时,不会进行跨库的连接.
                PS:具体测试以后再补

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                dataNode的参数在之前的篇章介绍过,这里直接跳过~

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                dataHost配置的是实际的后端数据库集群,大部分参数简单易懂,这里就不一个个介绍了,只介绍比较重要的两个参数,writeType和balance.
                writeType和balance是用来控制后端集群的读写分离的关键参数,这里我用了双主双从的集群配置
                这里的测试过程比较麻烦,所以直接贴结论:
                        1.balance=0时,读操作都在localhost上(localhost失败时,后端直接失败)
                        2.balance=1时,读操作会随机分散在localhost1和两个readhost上面(localhost失败时,写操作会在localhost1,如果localhost1再失败,则无法进行写操作)
                        3.balance=2时,写操作会在localhost上,读操作会随机分散在localhost1,localhost1和两个readhost上面(同上)
                        4.writeType=0时,写操作会在localhost上,如果localhost失败,会自动切换到localhost1,localhost恢复以后并不会切换回localhost进行写操作
                        5.writeType=1时,写操作会随机分布在localhost和localhost1上,单点失败并不会影响集群的写操作,但是后端的从库会无法从挂掉的主库获取更新,会在读数据的时候出现数据不一致
                                举例:localhost失败了,写操作会在localhost1上面进行,localhost1的主从正常运行,但是localhost的从库无法从localhost获取更新,localhost的从库于其他库出现数据不一致

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                实际上,MyCAT本身的读写分离是基于后端集群的同步来实现的,而MyCAT本身则提供语句的分发功能,当然,那个sqlLimit的限制也使得MyCAT会对前端应用层的逻辑造成一些影响
                由schema到table的配置,则显示出MyCAT本身的逻辑结构里面,就包含了分库分表的这种特性(可以指定不同的表存在于不同的数据库中,而不必分到全部数据库)
                下一章将会介绍server和rule的一些细节
 
首先写在最前面,MyCAT1.4的alpha版本已经发布了,这里面修复了不少的bug,也完善了一细节,之前两篇博客已经做了一些修改

---------------------------------------------------------------------------------这才是本体~----------------------------------------------------------------------------------
            之前已经介绍过了schema的作用了,这一篇会把rule和server一起介绍~
            首先是rule,在这个文件里面会详细的制定多种分片的规则,这次只抽出一些使用率比较高的方法,先上配置文件的内容
         
            可以简单看一下,在截图的上半部分描述的是rule的定义,在下半部分,是rule对应的实际切分规则,这里总工介绍下面四种切分方式~murmur已坑~
-------------------------------------------------------------------------------------------Hash-int---------------------------------------------------------------------------------
            先看hash-int,在这一条切分规则的下面,有一个mapfile,这代表着,这个切分规则是根据partition-hash-int的内容来决定的,那么看一下这个文本文件
         
            很简单的内容,这代表着切分使用的基准列里面,值为10000的时候,放在第一个DN里面(dn1),值为10010的时候,放在第二个DN里面(dn2)
            可以看一下实际效果
         
         
            看一下MyCAT的Debug日志,这两条语句被分配到了dn1和dn2上面,数据库里面也插入了相对应的数据
         
            那么~问题来了(挖掘机滚粗~),如果插入的数据中,基准列的取值不是这个文件里面写明的值,会是什么效果?
         
            直截了当的报错了~

            好了,hash-int的这种切分规则,大体上可以理解为枚举分区,会比较适合于取值固定的场合,比如说性别(0,1),省份(固定值,短时间不会收复日本省吧~),渠道商 or 各种平台的ID
            而且,用逗号分隔可以把多个值放在一个分区里面,所以可以根据实际的数据量/流量/访问量来综合制定切分策略;
            缺点:毕竟不是全能战士╮(╯_╰)╭

-------------------------------------------------------------------------------------------range-long---------------------------------------------------------------------------------
            第二种切分方式,range-long,仔细一看的话,和hash-int是比较像的,也是由特定的文件来决定切分策略,所以还是去看一下文件的内容
         
            从文件内容可以看出,这是一种范围切分的方式,制定基准列的取值范围,然后把这一范围的所有数据都放到一个DN上面,这种方式和hash-int基本一致,就不截图了(懒癌晚期,时间不够了!)
            这种切分策略,个人感觉在业务数据库里面的使用场景会少一些,因为这种切分方式需要预定好整体的数量,这就决定了那种无限增长的数据不能用这个,毕竟要改动这个切分策略会很麻烦
            真要用起来,感觉也就对自增主键用,然后按照一定的数量来均匀切分,比如那种一天固定X条数据的业务(温度采集?数据采集?之类的情况),然后提前建好多个DN(库)。
            当然,也存在一种潜在的问题,如果在短时间发生海量的顺序插入操作,而每一个DN(分库)设定的数量比较高(比如说一个DN设定的放1000W条数据),那么在这个时候,会出现某一个DN(分库)IO压力非常高,而其他几个DN(分库)完全没有IO操作,就会出现类似于DB中常见的热块/热盘的现象,而MySQL经常用自增主键,所以使得MySQL的表出现大量“顺序”插入的机会会多很多。
--------------------------------------------------------------------------------------------mod-long-----------------------------------------------------------------------------------
            mod-long,从mod来看这应该是一种取余数的方法,来看一下具体配置的信息
         
            count=4,这是代表着总共把数据切分成四份,一般是和具体的DN数量对应,从而达到把数据均匀的分布在四个DN上(当然,count<dn数量也没什么问题)
             看一下实际的效果
         
            看一下MyCAT的Debug日志,看看MyCAT是如何处理的
         
            采用这种取余数的方式时,这四条数据分别插入了四个DN(库),而且可以看到,顺序插入时,数据是被均匀的分散在多个DN(库)上面
            相比较于上面的range的方法,这种切分策略会更好的分散数据库写的压力,但是问题也很明显,一旦出现了范围查询,就需要MyCAT去合并结果,当数据量偏高的时候,这种跨库查询+合并结果消耗的时间有可能会增加很多,尤其是还出现了order by的时候。
            所以这种切分策略会比较适合于单点查询的情景,比如说.....我也不知道......真的不知道,也许在银行,查询个人账户信息的时候,一些和用户信息的表可以做好冗余,然后利用这种方式来提供更为高效的查询(毕竟银行的用户数量多,恩恩~)

--------------------------------------------------------------------------------partition-by-long----------------------------------------------------------------------------------
            partition-by-long,处于range-long和mod-long之间的一个略微折中的划分策略,具体切分形势依照如下描述:
            以1024为一个单位,每个DN存放partitionLength数量的数据,且,partitionCount x partitionLength=1024
            看起来有点难以理解,形象点描述的话,以partitionCount(4) x partitionLength(256)为例,sid%1024=0-255的放在DN1,256-511的放在DN2,以此类推
            试着以128为偏移值插入了八条数据,直接看MyCAT的日志
         
            可以看到,八条数据均匀的分布在这四个DN里面~
            值得一提的是,这种切分策略也支持非均匀分布~实在是测不动了,盗图两张~
          
          
            这两张图基本上也说明白了这种非均匀分布的划分策略,重点还是在2x256+1x512=1024上面~
            这种划分策略在range-long和mod-long之间取了一个折中点,同时,也还算是比较灵活,可以根据不同的情况进行非均匀划分,实际上能应用的场景会稍微多一点吧,或者说,不少场景都能用一用,相对减少了跨DN的情形,又把数据比较均匀的切分开来了,单点查询也不会太慢。

-----------------------------------------------------------------------------------写在最后-------------------------------------------------------------------------------------
            其实MyCAT支持的切分方式还有不少,比如说按照时间的切分策略,可以按月,按天切分等,在这里也没办法把所有的策略都放上来,见谅了o( ̄ヘ ̄o#)
            实际上从个人的观点来看,时间的切分依照数据库本身的分区策略来分也没什么问题,半年度,季度的数据也还是会需要查询的....PS:   _(:з」∠)_真不是懒...
            可以说,MyCAT的分库分表的重点,基本全部在这个rule里面体现了,表要不要分,表的数据怎么切分,都是需要根据实际业务来决定,充分根据业务的特点去决定最合适的划分策略~
 
背景:接本应接在基准测试之后就整理,不过有别的事情耽搁了

环境:与基准测试时保持一致,4核32G,MyCAT-1.4-RC,6月17号发布的版本,目前最新发布的版本应该是在7.29,七月底的样子。

相关配置文件:server.xml与cacheservice.properties

文件简介:
server.xml:保存了有关MyCAT的配置信息,包括MyCAT对外暴露的schema(包含这个schema对应的账户名和密码),MyCAT server的连接池等参数配置
cacheservice.properties:缓存区的配置

server.xml示例:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- - - Licensed under the Apache License, Version 2.0 (the "License"); 
  3.         - you may not use this file except in compliance with the License. - You 
  4.         may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 
  5.         - - Unless required by applicable law or agreed to in writing, software - 
  6.         distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT 
  7.         WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the 
  8.         License for the specific language governing permissions and - limitations 
  9.         under the License. -->
  10. <!DOCTYPE mycat:server SYSTEM "server.dtd">
  11. <mycat:server xmlns:mycat="http://org.opencloudb/">
  12.         <system> 
  13.         <property name="processors">32</property> 
  14.         <property name="processorExecutor">256</property> 
  15.         <property name="processorBufferPool">204800000</property>
  16.         <property name="processorBufferChunk">40960</property>
  17.                 <!--默认是65535 64K 用于sql解析时最大文本长度 -->
  18.         <property name="maxStringLiteralLength">65535</property>
  19.                 <!--<property name="sequnceHandlerType">0</property>-->
  20.                 <!--<property name="backSocketNoDelay">1</property>-->
  21.                 <!--<property name="frontSocketNoDelay">1</property>-->
  22.                 <!--<property name="processorExecutor">16</property>-->
  23.                 <!-- 
  24.                         <property name="mutiNodeLimitType">1</property> 0:开启小数量级(默认) ;1:开启亿级数据排序
  25.                         <property name="mutiNodePatchSize">100</property> 亿级数量排序批量
  26.                         <property name="processors">32</property> <property name="processorExecutor">32</property> 
  27.                         <property name="serverPort">8066</property> <property name="managerPort">9066</property> 
  28.                         <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property> 
  29.                         <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
  30.         <property name="defaultSqlParser">druidparser</property>
  31.         </system>
  32.         <!--
  33.         <user name="root">
  34.                 <property name="password">root</property>
  35.                 <property name="schemas">test</property>
  36.         </user>
  37.         <user name="root_read">
  38.                 <property name="password">root_read</property>
  39.                 <property name="schemas">test</property>
  40.                 <property name="readOnly">true</property>
  41.         </user>
  42.         -->
  43.         <user name="test">
  44.                 <property name="password">test</property>
  45.                 <property name="schemas">test</property>
  46.         </user>
  47.         <!-- <cluster> <node name="cobar1"> <property name="host">127.0.0.1</property> 
  48.                 <property name="weight">1</property> </node> </cluster> -->
  49.         <!-- <quarantine> <host name="1.2.3.4"> <property name="user">test</property> 
  50.                 </host> </quarantine> -->
  51. </mycat:server>
PS:MyCAT对外暴露的schema,是可以使用readonly模式的,如上面配置文件中的加红部分;

processors:用于指定可用线程数,实际上由于现在的多核CPU和超线程技术,这个值可以酌情调高,这里调到了虚拟机核数的八倍,感觉稍稍有点高了,实际上四倍or五倍就差不多了

processorExecutor:类似于线程池大小的参数,酌情修改即可,在1.4之后,这个线程池是用来做异步处理逻辑的时候用的,对并发能力的影响相对较小了

processorBufferPool:BufferPool的大小,原则上来说,调高一些会比较好

processorBufferChunk:每一个Buffer块的大小,processorBufferPool/processorBufferChun可以得到buffer块的数量

server调整总结:
processors+processorExecutor会影响到MyCAT可用的线程数,虽然调高点会比较好,但是调的太高会导致频繁的上下文切换和软中断,在实际调整中,用top观察sys和si的百分比,如果服务器/虚拟机并没有什么不干净的后台程序和其他的服务在运行,sys在10%-15%之内,si在5%之内是比较理想的状态

processorBufferPool+processorBufferChunk影响的server缓存,保持processorBufferChunk大小合理的情况下,增加buffer块的数量才是关键


cacheservice.properties示例:

点击(此处)折叠或打开

  1. #used for mycat cache service conf
  2. factory.encache=org.opencloudb.cache.impl.EnchachePooFactory
  3. #key is pool name ,value is type,max size, expire seconds
  4. pool.SQLRouteCache=encache,1500000,60
  5. pool.ER_SQL2PARENTID=encache,2000,180
  6. layedpool.TableID2DataNodeCache=encache,3000,18000
  7. layedpool.TableID2DataNodeCache.TESTDB_ORDERS=10000,18000
cacheservice是SQL的缓存服务,

SQLRouteCache:sql路由缓存,通过缓存SQL语句的路由信息,下次查询,不用再路由了,直接从缓存中获取路由信息,然后发到各个节点执行;
TableID2DataNodeCache :表主键ID的路由缓存,为每一个表建一个缓存池,命名为TableID2DataNodeCache.TESTDB_表名,缓存的key是id的值,value是节点名;
ER_SQL2PARENTID : ER关系的缓存目前只是在Insert语句中才会使用缓存,子表插入数据的时候,根据joinKey的值,判断父表所在分片,从而定位子表分片,分片信息put缓存,以便下次直接获取

由于在测试的时候并没有对测试表是简单的区域划分,所以在测试中对后两个缓存是没有利用到的,具体对缓存大小的调整可以参考SQLRouteCache;

首先贴出结论:SQLRouteCache的大小对具体的QPS有比较大的影响(废话......._(:з」∠)_),在实际的测试过程中,保持线程并发不变的情况下,从100W-300W都有调整过,大概每增加50W,有约15%的增加,直观来看的话,从100W-300W的增加过程中,128线程,5张表x5000W行/表的情况下,QPS范围从1W5-2W5,然而有一个问题很重要,当这个值增加到比较高后,会频繁出现极高的sys占用率,同时vmstat命令下,proc列会有非常高的r和b,直接后果就是MyCAT server本身会出现剧烈的性能波动,在基准测试中,QPS的低谷会降到3000-4000;但是free查看内存使用的时候,并没有出现内存不足的情况,推断为MyCAT本身的缓存设计中存在不完善的地方;

具体的设置值,在不断的测试中,以之前的虚拟机的配置(4核,32G)为参考,当SQLRouteCache的值设置到180W以上的时候,就会不定时的出现性能波动,为了保证稳定运行,在基准测试时采用了较低的150W

PS:由于基准测试的时候,SQL语句模板里面的参数都是采用随机值,所以缓存的命中率是偏低的(150W的设置下,大约只有25%的命中率),生产环境下,这个命中率会高很多,同时QPS也会有一定程度的上升
PPS:这个routeCache和MySQL的queryCache比较像,缓存的都是具体的SQL语句,而不是框架里面的带?占位符的语句,queryCache的信息可以参考http://blog.itpub.net/29510932/viewspace-1694922/
 
 
来源:http://blog.itpub.net/29510932/
posted @ 2017-09-16 06:54  疯狂110  阅读(563)  评论(0编辑  收藏  举报