MyCAT 可以视为“MySQL”集群的企业级数据库,用来替代昂贵的Oracle集群,其背后是阿里曾经开源的知名产品Cobar。MyCAT的目标是:低成本的将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。
(2) 修改配置my.cnf新增以下语句, 一般会放在/etc/my.cnf 或 /etc/mysql/my.cnf,设置为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,这是从网上摘抄的一个示例模板
- <?xml version="1.0"?>
- <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
- <mycat:schema xmlns:mycat="http://org.opencloudb/">
- <schema name="weixin" checkSQLschema="false" sqlMaxLimit="100" dataNode="weixin" >
-
-
- <schema name="yixin" checkSQLschema="false" sqlMaxLimit="100" dataNode="yixin" />
-
-
- <dataNode name="dn1" dataHost="localhost0" database="weixin" />
- <dataNode name="dn2" dataHost="localhost0" database="yixin" />
- <dataHost name="localhost0" maxCon="450" minCon="10" balance="1"
- writeType="0" dbType="mysql" dbDriver="native">
- <heartbeat>select user()</heartbeat>
- <!-- can have multi write hosts -->
- <writeHost host="hostM1" url="localhost:3306" user="root" password="123456" />
- <readHost host="hostS1" url="localhost:3307" user="test" password="123456" />
- </dataHost>
- </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如示例
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mycat:rule SYSTEM "rule.dtd">
- <mycat:rule xmlns:mycat="http://org.opencloudb/">
- <tableRule name="rule">
- <rule>
- <columns>user_id</columns>
- <algorithm>func1</algorithm>
- </rule>
- </tableRule>
- <function name="func1" class="org.opencloudb.route.function.PartitionByLong">
- <property name="partitionCount">2</property>
- <property name="partitionLength">512</property>
- </function>
- </mycat:rule>
rule.xml里面的配置主要用于对表的水平切分,MyCAt本身提供了很多种水平切分的策略,这个示例显示的是取模分片,总共分成四片,user_id对1024取模,然后分成两片,每一片512个。
其他的切分策略以后再详细介绍
server.xml如示例
- <!DOCTYPE mycat:server SYSTEM "server.dtd">
- <mycat:server xmlns:mycat="http://org.opencloudb/">
- <system>
- <property name="sequnceHandlerType">0</property>
- </system>
- <user name="test">
- <property name="password">test</property>
- <property name="schemas">weixin,yixin</property>
- </user>
- </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文件,双引号之前的反斜杠不会消除,姑且当成不存在吧...
- <?xml version=\"1.0\"?>
- <!DOCTYPE mycat:schema SYSTEM \"schema.dtd\">
- <mycat:schema xmlns:mycat=\"http://org.opencloudb/\">
- <schema name=\"mycat\" checkSQLschema=\"false\" sqlMaxLimit=\"100\">
- <!-- auto sharding by id (long) -->
- <table name=\"students\" dataNode=\"dn1,dn2,dn3,dn4\" rule=\"rule1\" />
- <table name=\"log_test\" dataNode=\"dn1,dn2,dn3,dn4\" rule=\"rule2\" />
- <!-- global table is auto cloned to all defined data nodes ,so can join
- with any table whose sharding node is in the same data node -->
- <!--<table name=\"company\" primaryKey=\"ID\" type=\"global\" dataNode=\"dn1,dn2,dn3\" />
- <table name=\"goods\" primaryKey=\"ID\" type=\"global\" dataNode=\"dn1,dn2\" />
- -->
- <table name=\"item_test\" primaryKey=\"ID\" type=\"global\" dataNode=\"dn1,dn2,dn3,dn4\" />
- <!-- random sharding using mod sharind rule -->
- <!-- <table name=\"hotnews\" primaryKey=\"ID\" dataNode=\"dn1,dn2,dn3\"
- rule=\"mod-long\" /> -->
- <!--
- <table name=\"worker\" primaryKey=\"ID\" dataNode=\"jdbc_dn1,jdbc_dn2,jdbc_dn3\" rule=\"mod-long\" />
- -->
- <!-- <table name=\"employee\" primaryKey=\"ID\" dataNode=\"dn1,dn2\"
- rule=\"sharding-by-intfile\" />
- <table name=\"customer\" primaryKey=\"ID\" dataNode=\"dn1,dn2\"
- rule=\"sharding-by-intfile\">
- <childTable name=\"orders\" primaryKey=\"ID\" joinKey=\"customer_id\"
- parentKey=\"id\">
- <childTable name=\"order_items\" joinKey=\"order_id\"
- parentKey=\"id\" />
- <ildTable>
- <childTable name=\"customer_addr\" primaryKey=\"ID\" joinKey=\"customer_id\"
- parentKey=\"id\" /> -->
- </schema>
- <!-- <dataNode name=\"dn\" dataHost=\"localhost\" database=\"test\" /> -->
- <dataNode name=\"dn1\" dataHost=\"localhost\" database=\"test1\" />
- <dataNode name=\"dn2\" dataHost=\"localhost\" database=\"test2\" />
- <dataNode name=\"dn3\" dataHost=\"localhost\" database=\"test3\" />
- <dataNode name=\"dn4\" dataHost=\"localhost\" database=\"test4\" />
- <!--
- <dataNode name=\"jdbc_dn1\" dataHost=\"jdbchost\" database=\"db1\" />
- <dataNode name=\"jdbc_dn2\" dataHost=\"jdbchost\" database=\"db2\" />
- <dataNode name=\"jdbc_dn3\" dataHost=\"jdbchost\" database=\"db3\" />
- -->
- <dataHost name=\"localhost\" maxCon=\"100\" minCon=\"10\" balance=\"1\"
- writeType=\"1\" dbType=\"mysql\" dbDriver=\"native\">
- <heartbeat>select user()<beat>
- <!-- can have multi write hosts -->
- <writeHost host=\"localhost\" url=\"localhost:3306\" user=\"root\" password=\"wangwenan\">
- <!-- can have multi read hosts -->
- <readHost host=\"hostS1\" url=\"localhost:3307\" user=\"root\" password=\"wangwenan\"/>
- </writeHost>
- <writeHost host=\"localhost1\" url=\"localhost:3308\" user=\"root\" password=\"wangwenan\">
- <!-- can have multi read hosts -->
- <readHost host=\"hostS11\" url=\"localhost:3309\" user=\"root\" password=\"wangwenan\"/>
- </writeHost>
- </dataHost>
- <!-- <writeHost host=\"hostM2\" url=\"localhost:3316\" user=\"root\" password=\"123456\"/> -->
- <!--
- <dataHost name=\"jdbchost\" maxCon=\"1000\" minCon=\"1\" balance=\"0\" writeType=\"0\" dbType=\"mongodb\" dbDriver=\"jdbc\">
- <heartbeat>select user()<beat>
- <writeHost host=\"hostM\" url=\"mongodb://192.168.0.99/test\" user=\"admin\" password=\"123456\" ></writeHost>
- </dataHost>
- -->
- <!--
- <dataHost name=\"jdbchost\" maxCon=\"1000\" minCon=\"10\" balance=\"0\"
- dbType=\"mysql\" dbDriver=\"jdbc\">
- <heartbeat>select user()<beat>
- <writeHost host=\"hostM1\" url=\"jdbc:mysql://localhost:3306\"
- user=\"root\" password=\"123456\">
- </writeHost>
- </dataHost>
- -->
- </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示例:
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- - you may not use this file except in compliance with the License. - You
- may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - - Unless required by applicable law or agreed to in writing, software -
- distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
- License for the specific language governing permissions and - limitations
- under the License. -->
- <!DOCTYPE mycat:server SYSTEM "server.dtd">
- <mycat:server xmlns:mycat="http://org.opencloudb/">
- <system>
- <property name="processors">32</property>
- <property name="processorExecutor">256</property>
- <property name="processorBufferPool">204800000</property>
- <property name="processorBufferChunk">40960</property>
- <!--默认是65535 64K 用于sql解析时最大文本长度 -->
- <property name="maxStringLiteralLength">65535</property>
- <!--<property name="sequnceHandlerType">0</property>-->
- <!--<property name="backSocketNoDelay">1</property>-->
- <!--<property name="frontSocketNoDelay">1</property>-->
- <!--<property name="processorExecutor">16</property>-->
- <!--
- <property name="mutiNodeLimitType">1</property> 0:开启小数量级(默认) ;1:开启亿级数据排序
- <property name="mutiNodePatchSize">100</property> 亿级数量排序批量
- <property name="processors">32</property> <property name="processorExecutor">32</property>
- <property name="serverPort">8066</property> <property name="managerPort">9066</property>
- <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
- <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
- <property name="defaultSqlParser">druidparser</property>
- </system>
- <!--
- <user name="root">
- <property name="password">root</property>
- <property name="schemas">test</property>
- </user>
- <user name="root_read">
- <property name="password">root_read</property>
- <property name="schemas">test</property>
- <property name="readOnly">true</property>
- </user>
- -->
- <user name="test">
- <property name="password">test</property>
- <property name="schemas">test</property>
- </user>
- <!-- <cluster> <node name="cobar1"> <property name="host">127.0.0.1</property>
- <property name="weight">1</property> </node> </cluster> -->
- <!-- <quarantine> <host name="1.2.3.4"> <property name="user">test</property>
- </host> </quarantine> -->
- </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示例:
- #used for mycat cache service conf
- factory.encache=org.opencloudb.cache.impl.EnchachePooFactory
- #key is pool name ,value is type,max size, expire seconds
- pool.SQLRouteCache=encache,1500000,60
- pool.ER_SQL2PARENTID=encache,2000,180
- layedpool.TableID2DataNodeCache=encache,3000,18000
- 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以上的时候,就会不定时的出现性能波动,为了保证稳定运行,在基准测试时采用了较低的150WPS:由于基准测试的时候,SQL语句模板里面的参数都是
采用随机值,所以缓存的命中率是偏低的(150W的设置下,大约只有
25%的命中率),生产环境下,
这个命中率会高很多,同时QPS也会有一定程度的上升
PPS:这个routeCache和MySQL的queryCache比较像,缓存的都是具体的SQL语句,而不是框架里面的带?占位符的语句,queryCache的信息可以参考http://blog.itpub.net/29510932/viewspace-1694922/
来源:http://blog.itpub.net/29510932/