现在的面试越来越变态了,不少公司还是会考分库分表的,倒不一定会考多深,但是如果一点答不上来那就让面试官的印象很差,本文是自己搭建mycat的经验外加参考网上他人的经验写成,目的很简单应付面试的。
一 Mycat基本概念
先看schema.xml这个配置文件
<mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="RDRS_MYCAT_POC" checkSQLschema="true" sqlMaxLimit="100000"> <table name="MYCAT_SOURCETABLE" primaryKey="USERID" subTables="mycat_sourcetable_$0-7" rule="mycatrule8" dataNode="mysql_node_1,mysql_node_2" selDbColumn="USERID"></table> <table name="mycat_sourcetable_0,mycat_sourcetable_1,mycat_sourcetable_2,mycat_sourcetable_3" primaryKey="USERID" dataNode="mysql_node_1"/> <table name="mycat_sourcetable_4,mycat_sourcetable_5,mycat_sourcetable_6,mycat_sourcetable_7" primaryKey="USERID" dataNode="mysql_node_2"/> <table name="LL_SOURCE_TABLE" subTables="ll_source_table_$00-03" rule="mycatrule4" dataNode="mysql_node_1,mysql_node_2" selDbColumn="USERID"></table> <table name="ll_source_table_00,ll_source_table_01" dataNode="mysql_node_1"/> <table name="ll_source_table_02,ll_source_table_03" dataNode="mysql_node_2"/> </schema> <dataNode name="mysql_node_1" dataHost="mysql_1" database="rdrsshard_001"/> <dataNode name="mysql_node_2" dataHost="mysql_2" database="rdrsshard_002"/> <dataHost name="mysql_1" maxCon="500" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <writeHost host="mysql_1" url="10.47.147.44:3306" user="rdrsuser" password="************"/> </dataHost> <dataHost name="mysql_2" maxCon="500" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <writeHost host="mysql_2" url="10.47.147.43:3306" user="rdrsuser" password="************"/> </dataHost> </mycat:schema>
从上面的xml节点也能看的出来,mycat主要有四大节点类型
1.Schema:逻辑库,与MySQL中的Database(数据库)对应,一个逻辑库中定义了所包括的Table。
2.Table:逻辑表,分布式数据库中,对应用来说,读写数据的表就是逻辑表。逻辑表,可以是数据切分后,分布在一个或多个分片库中,也可以不做数据切分,不分片,只有一个表构成。
分片表:是指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所有分片构成了完整的数据。
3.DataNode:分片节点、数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点。
4.DataHost:节点主机,数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
5.rule:分片规则,前面讲了数据切分,一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到某个分片的规则就是分片规则,数据切分选择合适的分片规则非常重要,将极大的避免后续数据处理的难度。
二 Mycat写原理
看一组新的配置
rule.xml
<tableRule name="role1"> <rule> <!--columns分片字段,algorithm取模算法--> <columns>id</columns> <algorithm>mod-long</algorithm> </rule> </tableRule> <function name="mod-long" class="io.mycat.route.function.PartitionByMod"> <!--指定分片数量也就是几个库,不可以被更改--> <property name="count">3</property> </function>
schema.xml
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <!-- TESTDB1 是mycat的逻辑库名称,链接需要用的 --> <schema name="mycat_testdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> <table name="area_info" dataNode="dn1,dn2,dn3" rule="role1"/> </schema> <!-- database 是MySQL数据库的库名 --> <dataNode name="dn1" dataHost="localhost" database="userdb_1" /> <dataNode name="dn2" dataHost="localhost" database="userdb_2" /> <dataNode name="dn3" dataHost="localhost" database="userdb_3" /> <!-- dataNode节点中各属性说明: name:指定逻辑数据节点名称; dataHost:指定逻辑数据节点物理主机节点名称; database:指定物理主机节点上。如果一个节点上有多个库,可使用表达式db$0-99, 表示指定0-99这100个数据库; dataHost 节点中各属性说明: name:物理主机节点名称; maxCon:指定物理主机服务最大支持1000个连接; minCon:指定物理主机服务最小保持10个连接; writeType:指定写入类型; 0,只在writeHost节点写入; 1,在所有节点都写入。慎重开启,多节点写入顺序为默认写入根据配置顺序,第一个挂掉切换另一个; dbType:指定数据库类型; dbDriver:指定数据库驱动; balance:指定物理主机服务的负载模式。 0,不开启读写分离机制; 1,全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡; 2,所有的readHost与writeHost都参与select语句的负载均衡,也就是说,当系统的写操作压力不大的情况下,所有主机都可以承担负载均衡; --> <dataHost name="localhost" 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.223.141:3306" user="root" password="123456"> <!-- 可以配置多个从库 --> <readHost host="hostS2" url="192.168.223.142:3306" user="root" password="123456" /> </writeHost> </dataHost> </mycat:schema>
假如现在有记录 id 1 2 3 4 5 10
插入时的逻辑如下
1%3 取模 后1,userdb_2 2 %3取模 后2,userdb_3 3 %3取模 后0,userdb_1 4 %3取模 后1,userdb_2 5 %3取模 后2,userdb_3 10 %3取模 后1,userdb_2
第一种情况相对来说简单,是直接对某一个字段值进行分片路由的。还有第二种情况,这种情况会稍微复杂一些,先在一个文件里写明某一个字段值做映射后的值,然后再做映射。
使用场景:比如QQ注册用户上亿,我们可以按地区注册分表,这样单表的数据量就没有那么大了。
partition-hash-int.txt (名字随意,但是要和配置文件里的一致)
wuhan=0 shanghai=1 suzhou=2
<tableRule name="role2"> <rule> <!--上面columns 标识将要分片的表字段,algorithm 分片函数--> <columns>name</columns> <algorithm>hash-int</algorithm> </rule> </tableRule> <function name="hash-int" class="io.mycat.route.function.PartitionByFileMap"> <!--其中分片函数配置中,mapFile标识配置文件名称,type默认值为0,0表示Integer,非零表示String--> <property name="mapFile">partition-hash-int.txt</property> <!-- 所有的节点配置都是从0开始,及0代表节点1 defaultNode 默认节点:小于0表示不设置默认节点,大于等于0表示设置默认节点,结点为指定的值 默认节点的作用:枚举分片时,如果碰到不识别的枚举值,就让它路由到默认节点 如果不配置默认节点(defaultNode值小于0表示不配置默认节点),碰到 不识别的枚举值就会报错, like this:can't find datanode for sharding column:column_name val:ffffffff --> <property name="type">1</property> <property name="defaultNode">1</property> </function>
按照上面的配置后,数据分配就会像下面的示例那样分配
wuhan userdb_1 shanghai nanjing xian userdb_2 suzhou userdb_3
三 Mycat读原理
1 where条件是分片字段
如果where条件是分片字段,那么根据分片字段直接请求其对应的物理库进行查询,也就是说只会查询一个库
2 where条件不是分片字段
会在所有物理库中执行语句,再把结果集返回
3 limit分页查询 假设语句是 select * from area_info desc limit 0,2
向所有库查询,每个库返回两条数据,然后由mycat组装成下图数据,然后从mycat组装数据中随机抽取两条数据。
· 4 select * from area_info ORDER BY id desc limit 0,2
查询三个库,返回每个库中最大的两条,mycat组装成下图所示,最后选取组装的数据中,最大的两条数据
四 Mycat配置读写分离
Balance参数设置:
1. balance=“0”, 所有读操作都发送到当前可用的writeHost上。
2. balance=“1”,所有读操作都随机的发送到readHost。
3. balance=“2”,所有读操作都随机的在writeHost、readhost上分发
WriteType参数设置:
1. writeType=“0”, 所有写操作都发送到可用的writeHost上。
2. writeType=“1”,所有写操作都随机的发送到readHost。
3. writeType=“2”,所有写操作都随机的在writeHost、readhost分上发。