MyCat 总结,看完这篇带你了解分库分表

水平拆分和垂直拆分

特性 垂直拆分 水平拆分
概念 按照业务将表进行分类,将数据或者说压力分担到不同的库。 按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。
优点 拆分后业务清晰,拆分规则明确;系统之间整合或扩展容易; 数据维护简单。
缺点 部分业务表无法join,只能通过接口方式解决,提高了系统复杂度;受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高;事务处理复杂。不能解决单表过于庞大的问题。
共同缺点 引入分布式事务的问题;跨节点 Join 的问题;跨节点合并排序分页问题;多数据源管理问题
垂直切分
水平拆分

MyCat

Mycat 是一个强大的数据库中间件。作用:读写分离、分库分表、容灾备份、多租户应用开发……

数据库中间件
名称 概念
逻辑库(schema) 通常对实际应用来说,并不需要知道中间件的存在,业务开发人员只需要知道数据库的概念,所以数据库中间件可以被看做是一个或多个数据库集群构成的逻辑库。
逻辑表(table) 逻辑表,可以是数据切分后,分布在一个或多个分片库中,也可以不做数据切分,不分片,只有一个表构成。
分片节点(datanNode) 数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)。
节点主机(dataHost) 数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
分片规则(rule)
全局序列号(sequence) 数据唯一性标识

逻辑库

逻辑库

逻辑表

  • 分片表
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1,dn2" rule="rule1" />
  • 非分片表
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1" />
  • ER 表
    关系型数据库是基于实体关系模型(Entity-Relationship Model)之上,通过其描述了真实世界中事物与关系,Mycat 中的 ER 表即是来源于此。

  • 全局表
    1)变动不频繁;
    2)数据量总体变化不大;
    3)数据规模不大,很少有超过数十万条记录。
    全局表的配置,不用写 rule 规则:

配置文件

配置文件 作用
MYCAT_HOME/conf/schema.xml 定义逻辑库,表、分片节点等内容;
MYCAT_HOME/conf/rule.xml 定义分片规则;
MYCAT_HOME/conf/server.xml 定义用户以及系统相关变量,如端口等。

schema.xml

schema.xml 管理 MyCat 的逻辑库、表、分片规则、DataNode 以及 DataSource。

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
    <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" ></table>
</schema>

<schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100">
    <table name="company" dataNode="dn10,dn11,dn12" rule="auto-sharding-long" ></table>
</schema>

schema 标签的相关属性

属性名 定义 / 作用
name String 用于绑定逻辑库到某个具体的 database 上。1.3版本如果配置了dataNode,则不可以配置分片表,1.4 可以配置默认分片,只需要配置需要分片的表
checkSQLschema Boolean 建议不带这个字段,防止修改sql 语句。
sqlMaxLimit Integer 减少过多的数据返回

table 标签

属性 作用
name 定义逻辑表的表名,这个名字就如同我在数据库中执行create table命令指定的名字一样
dateNode 定义逻辑表所属 DataNode,该属性的值需要和dataNode标签中name属性的值相互对应。
rule 规则名字,规则名字在 rule.xml 中定义,必须与 tableRule 标签中 name 属性属性值一 一对应。
ruleRequired 指定表是否绑定分片规则,如果配置为true,但没有配置具体rule的话,程序会报错
primaryKey 逻辑表对应真实表的主键
type 类型,分全局表(global)和普通表,
autoIncrement mysql对非自增长主键,使用last_insert_id()是不会返回结果的,只会返回0。所以,只有定义了自增长主键的表才可以用last_insert_id()返回主键值。
subTables 使用方式添加 subTables="t_order$1-2,t_order3"。目前分表 1.6 以后开始支持 并且 dataNode 在分表条件下只能配置一个,分表条件下不支持各种条件的join 语句。
needAddLimit 表是否需要自动的在每个语句后面加上 limit 限制

dataNode 属性
dn 过多可以使用如下方法减少配置

<table name="travelrecord" dataNode="multipleDn$0-99,multipleDn2$100-199" rule="auto-sharding�long" ></table>

<dataNode name="multipleDn$0-99" dataHost="localhost1" database="db$0-99" ></dataNode><dataNode name="multipleDn2$100-199" dataHost="localhost1" database=" db$100-199" ></dataNode>

childTable 标签

用于定义 E-R 分片的子表。通过标签上的属性与父表进行关联。

属性 定义/ 作用
name String 定义子表的表名
joinKey String 插入子表的时候会使用这个列的值查找父表存储的数据节点
parentKey String 属性指定的值一般为与父表建立关联关系的列名
primaryKey String 同 table 标签所描述的
needAddLimit boolean 同 table 标签所描述的
<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" /></childTable>
    <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" parentKey="id" />
</table>

dataNode 标签

定义MyCat中的数据节点,即数据分片。

<dataNode name="dn1" dataHost="localhost1" database="db1" />

相关属性

属性名 定义 / 作用
name String 数据节点的名字,这个名字需要是唯一的。
dataHost String 定义该分片属于哪个数据库实例的,属性值是引用dataHost标签上定义的name属性。
database String 定义该分片属于哪个具体数据库实例上的具体库

dataHost 标签

定义了具体的数据库实例、读写分离配置和心跳语句。

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
    <heartbeat>select user()</heartbeat>
    <!-- can have multi write hosts -->
    <writeHost host="hostM1" url="localhost:3306" user="root" password="123456">
        <!-- can have multi read hosts -->
        <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />
    </writeHost>
    <writeHost host="hostS1" url="localhost:3316" user="root" password="123456" />
    <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
属性名 定义 / 作用
name String 唯一标识dataHost 标签
maxCon Integer 指定每个读写实例连接池的最大连接,也就是说,标签内嵌套的writeHost、readHost 标签都会使用这个属性的值来实例化出连接池的最大连接数
minCon Integer 指定每个读写实例连接池的最小连接,初始化连接池的大小。
balance Integer 负载均衡类型:
1. 指定每个读写实例连接池的最小连接,初始化连接池的大小。
2. balance="1",全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。
3. balance="2",所有读操作都随机的在writeHost、readhost 上分发。
4. balance="3",所有读请求随机的分发到wiriterHost 对应的readhost 执行,writerHost 不负担读压力,注意balance=3只在1.4及其以后版本有,1.3没有。
writeType Integer
dbType String 指定后端连接的数据库类型,目前支持二进制的mysql协议,还有其他使用JDBC连接的数据库。例如:mongodb、oracle、spark 等。
dbDriver String 指定连接后端数据库使用的Driver,目前可选的值有native和JDBC。使用native的话,因为这个值执行的是二进制的mysql协议,所以可以使用mysql和maridb。其他类型的数据库则需要使用JDBC驱动来支持。

heartbeat 标签

这个标签内指明用于和后端数据库进行心跳检查的语句。例如,MYSQL可以使用select user(),Oracle可以使用select 1 from dual 等。
1.4 主从切换的语句必须是:show slave status。

writeHost标签、readHost标签

这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。唯一不同的是,writeHost 指定写实例、readHost 指定读实例,组着这些读写实例来满足系统的要求。

在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost 上去。

属性名 定义 / 作用
host String 用于标识不同实例,一般writeHost我们使用M1,readHost我们用S1。
url String 后端实例连接地址,例如 jdbc:mysql://localhost:3306/
user String 数据库用户名
password String 数据库密码
weight String 权重
usingDecrypt String 是否对密码加密默认0 否如需要开启配置1

schema.xml 完整展示

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
        <!-- auto sharding by id (long) -->
        <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />

        <!-- 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" />
        <!-- random sharding using mod sharind rule -->
        <table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
               rule="mod-long" />
        <!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global"
            needAddLimit="false"/> <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" />
            </childTable>
            <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id"
                        parentKey="id" />
        </table>
        <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
            /> -->
    </schema>
    <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
        /> -->
    <dataNode name="dn1" dataHost="localhost1" database="db1" />
    <dataNode name="dn2" dataHost="localhost1" database="db2" />
    <dataNode name="dn3" dataHost="localhost1" database="db3" />
    <!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
     <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="localhost1" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <!-- can have multi write hosts -->
        <writeHost host="hostM1" url="localhost:3306" user="root"
                   password="123456">
            <!-- can have multi read hosts -->
            <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />
        </writeHost>
        <writeHost host="hostS1" url="localhost:3316" user="root"
                   password="123456" />
        <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
    </dataHost>
    <!--
        <dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc">
        <heartbeat>         </heartbeat>
         <writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng"  password="jifeng"></writeHost>
         </dataHost>

      <dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0"   dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat>
        <connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
        <writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base"   password="123456" > </writeHost> </dataHost>

        <dataHost name="jdbchost" maxCon="1000"     minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc">
        <heartbeat>select   user()</heartbeat>
        <writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost>

        <dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc">
        <heartbeat> </heartbeat>
         <writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng"     password="jifeng"></writeHost> </dataHost> -->

    <!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql"
        dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1"
        url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost>
        </dataHost> -->
</mycat:schema>

server.xml

<user name="root" defaultAccount="true">
        <property name="password">123456</property>
        <property name="schemas">TESTDB</property>
        <!-- 表级 DML 权限设置 -->    
        <privileges check="false">
            <schema name="TESTDB" dml="0110" >
                <table name="tb01" dml="0000"></table>
                <table name="tb02" dml="1111"></table>
            </schema>
        </privileges>           
    </user>

全局表一致性检查分布式事务开关都在 server.xml 配置。

rule.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:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <tableRule name="rule1">
        <rule>
            <columns>id</columns>
            <algorithm>func1</algorithm>
        </rule>
    </tableRule>

    <tableRule name="rule2">
        <rule>
            <columns>user_id</columns>
            <algorithm>func1</algorithm>
        </rule>
    </tableRule>

    <tableRule name="sharding-by-intfile">
        <rule>
            <columns>sharding_id</columns>
            <algorithm>hash-int</algorithm>
        </rule>
    </tableRule>
    <tableRule name="auto-sharding-long">
        <rule>
            <columns>id</columns>
            <algorithm>rang-long</algorithm>
        </rule>
    </tableRule>
    <tableRule name="mod-long">
        <rule>
            <columns>id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
    <tableRule name="sharding-by-murmur">
        <rule>
            <columns>id</columns>
            <algorithm>murmur</algorithm>
        </rule>
    </tableRule>
    <tableRule name="crc32slot">
        <rule>
            <columns>id</columns>
            <algorithm>crc32slot</algorithm>
        </rule>
    </tableRule>
    <tableRule name="sharding-by-month">
        <rule>
            <columns>create_time</columns>
            <algorithm>partbymonth</algorithm>
        </rule>
    </tableRule>
    <tableRule name="latest-month-calldate">
        <rule>
            <columns>calldate</columns>
            <algorithm>latestMonth</algorithm>
        </rule>
    </tableRule>
    
    <tableRule name="auto-sharding-rang-mod">
        <rule>
            <columns>id</columns>
            <algorithm>rang-mod</algorithm>
        </rule>
    </tableRule>
    
    <tableRule name="jch">
        <rule>
            <columns>id</columns>
            <algorithm>jump-consistent-hash</algorithm>
        </rule>
    </tableRule>

    <function name="murmur"
        class="io.mycat.route.function.PartitionByMurmurHash">
        <property name="seed">0</property><!-- 默认是0 -->
        <property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
        <property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
        <!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
        <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property> 
            用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
    </function>

    <function name="crc32slot"
              class="io.mycat.route.function.PartitionByCRC32PreSlot">
    </function>
    <function name="hash-int"
        class="io.mycat.route.function.PartitionByFileMap">
        <property name="mapFile">partition-hash-int.txt</property>
    </function>
    <function name="rang-long"
        class="io.mycat.route.function.AutoPartitionByLong">
        <property name="mapFile">autopartition-long.txt</property>
    </function>
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">3</property>
    </function>

    <function name="func1" class="io.mycat.route.function.PartitionByLong">
        <property name="partitionCount">8</property>
        <property name="partitionLength">128</property>
    </function>
    <function name="latestMonth"
        class="io.mycat.route.function.LatestMonthPartion">
        <property name="splitOneDay">24</property>
    </function>
    <function name="partbymonth"
        class="io.mycat.route.function.PartitionByMonth">
        <property name="dateFormat">yyyy-MM-dd</property>
        <property name="sBeginDate">2015-01-01</property>
    </function>
    
    <function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
            <property name="mapFile">partition-range-mod.txt</property>
    </function>
    
    <function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
        <property name="totalBuckets">3</property>
    </function>
</mycat:rule>

tableRule 标签

这个标签定义表规则。定义的表规则,在 schema.xml:

<tableRule name="sharding-by-intfile">
    <rule>
        <columns>sharding_id</columns>
        <algorithm>hash-int</algorithm>
    </rule>
</tableRule>

name 属性指定唯一的名字,用于标识不同的表规则。
内嵌的 rule 标签则指定对物理表中的哪一列进行拆分和使用什么路由算法。
columns 内指定要拆分的列名字。
algorithm 使用 function 标签中的 name 属性。连接表规则和具体路由算法。当然,多个表规则可以连接到
同一个路由算法上。table 标签内使用。让逻辑表使用这个规则进行分片。

function 标签

<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
    <property name="mapFile">partition-hash-int.txt</property>
</function>

name 指定算法的名字。
class 制定路由算法具体的类名字。
property 为具体算法需要用到的一些属性。

Mycat 的分片 join

INNER JOIN

内连接,也叫等值连接,inner join 产生同时符合A表和B表的一组数据。

内连接

LEFT JOIN

左连接从A表(左)产生一套完整的记录,与匹配的 B 表记录(右表) ,如果没有匹配,右侧将包含 null。

左连接

right join 与之相反。 full join:全连接产生的所有记录(双方匹配记录)在表A和表B。如果没有匹配,则对面将包含 null。

性能建议

尽量避免使用 Left join 或 Right join,而用 Inner join;
在使用 左右连接时,ON 会优先执行,where 条件在最后执行,所以在使用过程中,条件尽可能的在 ON 语句中判断,减少 where 的执行;
少用子查询,而用 join。

全局表

字典表特性:

  • 变动不频繁,可以根据主键 ID 进行缓存
  • 数据量总体变化不大
  • 数据规模不大,很少有超过数十万条记录。

鉴于此,MyCAT 定义了一种特殊的表,称之为“全局表”,全局表具有以下特性:

  • 全局表的插入、更新操作会实时在所有节点上执行,保持各个分片的数据一致性
  • 全局表的查询操作,只从一个节点获取
  • 全局表可以跟任何一个表进行 JOIN 操作

通过全局表+基于 E-R 关系的分片策略,MyCAT 可以满足 80%以上的企业应用开发,全局表配置简单,不用写 rule 规则。

<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />

ER join

基于 E-R 关系的数据分片策略。配置如下:

<table name="customer" dataNode="dn1,dn2" rule="sharding-by-intfile">
    <childTable name="orders" joinKey="customer_id" parentKey="id"/>
</table>

share join

目前支持 2 个表的 join,原理就是解析 SQL 语句,拆分成单表的 SQL 语句执行,然后把各个节点的数据汇集。

<!-- A,B 的 dataNode 相同-->
<table name="A" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<table name="B" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />

<!-- A,B 的 dataNode 不同-->
<table name="A" dataNode="dn1,dn2 " rule="auto-sharding-long" />
<table name="B" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />

<!-- 或者-->
<table name="A" dataNode="dn1 " rule="auto-sharding-long" />
<table name="B" dataNode=" dn2,dn3" rule="auto-sharding-long" />
/*!mycat:catlet=io.mycat.catlets.ShareJoin*/select * from employee a, employee_detail b where a.id = b.id;

人工智能

p 104

MyCat 常用的分片规则

分片枚举

通过在配置文件中配置可能的枚举 id,自己配置分片,本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县固定的,这类业务使用本条规则,配置如下:

<tableRule name="sharding-by-intfile">
    <rule>
      <columns>user_id</columns>
      <algorithm>hash-int</algorithm>
    </rule>
</tableRule>

<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
    <property name="mapFile">partition-hash-int.txt</property>
    <property name="type">0</property>
    <property name="defaultNode">0</property>
</function>

partition-hash-int.txt 配置:

10000=0
10010=1
DEFAULT_NODE=1

固定分片 hash 算法

此算法的优点在于如果按照 10 进制取模运算,在连续插入 1-10 时候,1-10 会被分到 1-10 个分片,增大了插入的事务控制难度,而此算法根据二进制则可能会分到连续的分片,减少插入的事务控制难度。

<tableRule name="rule1">
    <rule>
      <columns>user_id</columns>
      <algorithm>func1</algorithm>
    </rule>
</tableRule>

<function name="func1" class="io.mycat.route.function.PartitionByLong">
    <property name="partitionCount">2,1</property>
    <property name="partitionLength">256,512</property>
</function>

配置说明:
上面 columns 标识将要分片的表字段,algorithm 分片函数,
partitionCount 分片个数列表,partitionLength 分片范围列表
分区长度:默认为最大 2^n=1024 ,即最大支持 1024 分区
**约 束 : **
count,length 两个数组的长度必须是一致的。

范围约定

适用提前规划好分片字段某个范围属于哪个分片

<tableRule name="auto-sharding-long">
    <rule>
      <columns>user_id</columns>
      <algorithm>rang-long</algorithm>
    </rule>
</tableRule>

<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
    <property name="mapFile">autopartition-long.txt</property>
    <property name="defaultNode">0</property>
</function>

配置说明:
上面 columns 标识将要分片的表字段,algorithm 分片函数,
rang-long 函数中 mapFile 代表配置文件路径
defaultNode 超过范围后的默认节点。

autopartition-long.txt:

# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2

取模

<tableRule name="mod-long">
    <rule><columns>user_id</columns>
    <algorithm>mod-long</algorithm></rule>
</tableRule>

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    <!--how manydatanodes-->
    <property name="count">3</property>
</function>

配置说明:
上面columns 标识将要分片的表字段,algorithm 分片函数,rang-long 函数中mapFile 代表配置文件路径defaultNode 超过范围后的默认节点。所有的节点配置都是从0开始,及0代表节点1,此配置非常简单,即预先制定可能的id范围到某个分片

按日期(天)分片

非重点

取模范围约束

此种规则是取模运算与范围约束的结合,主要为了后续数据迁移做准备,即可以自主决定取模后数据的节点分布。

<tableRule name="sharding-by-pattern">      
    <rule>
        <columns>user_id</columns>        
        <algorithm>sharding-by-pattern</algorithm>
    </rule>
</tableRule>

<function name="sharding-by-pattern" class="io.mycat.route.function.PartitionByPattern">
    <property name="patternValue">256</property>
    <property name="defaultNode">2</property>
    <property name="mapFile">partition-pattern.txt</property>
</function>

partition-pattern.txt

# id partition range start-end ,data node index
###### first host configuration 
1-32=0
33-64=1
65-96=2
97-128=3

######## second host configuration 
129-160=4
161-192=5
193-224=6
225-256=7
0-0=7

配置说明:
上面columns 标识将要分片的表字段,algorithm 分片函数,patternValue 即求模基数,defaoultNode 默认节点,如果配置了默认,则不会按照求模运算

mapFile 配置文件路径
配置文件中,1-32即代表id%256后分布的范围,如果在1-32则在分区1,其他类推,如果id非数据,则会分配在defaoultNode默认节点
String idVal = “0”;
Assert.assertEquals(true, 7 == autoPartition.calculate(idVal));
idVal = “45a”;
Assert.assertEquals(true, 2 == autoPartition.calculate(idVal));

截取数字做hash 求模范围约束

后续补

应用指定

后续补

截取数字hash 解析

后续补

一致性hash(重点)

一致性hash 预算有效解决了分布式数据的扩容问题。

<tableRule name="sharding-by-murmur">  
    <rule>
      <columns>user_id</columns>        
      <algorithm>murmur</algorithm>
    </rule>
</tableRule>

<function name="murmur" class="io.mycat.route.function.PartitionByMurmurHash">
    <property name="seed">0</property><!--默认是0-->
    <property name="count">2</property><!--要分片的数据库节点数量,必须指定,否则没法分片-->
    <property name="virtualBucketTimes">160</property><!--一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍-->
    <!--<property name="weightMapFile">weightMapFile</property>节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替-->
    <!--<property name="bucketMapPath">/etc/mycat/bucketMapPath</property>用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西-->
</function>

范围求模分片(重点)

先进行范围分片计算出分片组,组内再求模优点可以避免扩容时的数据迁移,又可以一定程度上避免范围分片的热点问题综合了范围分片和求模分片的优点,分片组内使用求模可以保证组内数据比较均匀,分片组之间是范围分片可以兼顾范围查询。
最好事先规划好分片的数量,数据扩容时按分片组扩容,则原有分片组的数据不需要迁移。由于分片组内数据比较均匀,所以分片组内可以避免热点数据问题。

<tableRule name="auto-sharding-rang-mod">
    <rule>
      <columns>id</columns>
      <algorithm>rang-mod</algorithm>
    </rule>
</tableRule>

<function name="rang-mod"class="io.mycat.route.function.PartitionByRangeMod">
    <property name="mapFile">partition-range-mod.txt</property>
    <property name="defaultNode">21</property>
</function>

配置说明:
上面columns 标识将要分片的表字段,algorithm 分片函数,rang-mod 函数中mapFile 代表配置文件路径defaultNode 超过范围后的默认节点顺序号,节点从0 开始。
partition-range-mod.txt
range start-end ,data node group size
以下配置一个范围代表一个分片组,=号后面的数字代表该分片组所拥有的分片的数量。
partition-range-mod.txt

# range start-end ,data node group size
0-200M=5
200M1-400M=1
400M1-600M=4
600M1-800M=4
800M1-1000M=6

还有几种不常用,就不介绍了。

配置支持 Oracle

<dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle"
dbDriver="jdbc">
    <heartbeat>select 1 from dual</heartbeat>
    <connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
    <writeHost host="hostM1" url="jdbc:oracle:thin:@192.168.0.95:1521:orcl" user="test" password="test" ></writeHost>
</dataHost>
  1. dbDriver 一定为 jdbc,dbType 代表数据库类型,可以为 mysql,oracle,mongodb
  2. url 地址是 jdbc 连接的地址,和一般开发 java web 的 jdbc.url 地址一致,user,password 是用户名和密码
  3. 是心跳包的查询语句
  4. 是连接 oracle 的初始化语句,初始化本次会话的日期显示格式
  5. 需要 ojdbc14-x.jar 包(其它版本也支持)

MyCat 分页查询解决

mycat 对多数据库分页语法的支持主要分为 2 种方式:
一是 limit 语法自动转换成原生分页语法;
二是直接支持对原生分页语句。目前支持的数据库分页的类型有 oracle、db2、sqlserver、PostgreSQL 等。

  1. DruidMycatRouteStrategy 路由策略入口

  2. MycatStatementParser 扩展语句解析

  3. MycatSelectParser 扩展查询语句解析

  4. MycatExprParser 扩展支持聚合函数

  5. MycatLexer 扩展支持关键词

  6. DruidParserFactory 解析工厂类

  7. DruidSelectOracleParser oracle 分页解析

  8. DruidSelectDb2Parser db2 分页解析

  9. DruidSelectSqlServerParser sqlserver 分页解析

  10. DruidSelectPostgresqlParser PostgreSQL 分页支持

  11. RouteResultset 路由结果类

MyBatis PageHelper

https://blog.csdn.net/itcats_cn/article/details/81586724

Mybatis的插件运行原理

Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容