水平拆分和垂直拆分
特性 | 垂直拆分 | 水平拆分 |
---|---|---|
概念 | 按照业务将表进行分类,将数据或者说压力分担到不同的库。 | 按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。 |
优点 | 拆分后业务清晰,拆分规则明确;系统之间整合或扩展容易; 数据维护简单。 | |
缺点 | 部分业务表无法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>
- dbDriver 一定为 jdbc,dbType 代表数据库类型,可以为 mysql,oracle,mongodb
- url 地址是 jdbc 连接的地址,和一般开发 java web 的 jdbc.url 地址一致,user,password 是用户名和密码
- 是心跳包的查询语句
- 是连接 oracle 的初始化语句,初始化本次会话的日期显示格式
- 需要 ojdbc14-x.jar 包(其它版本也支持)
MyCat 分页查询解决
mycat 对多数据库分页语法的支持主要分为 2 种方式:
一是 limit 语法自动转换成原生分页语法;
二是直接支持对原生分页语句。目前支持的数据库分页的类型有 oracle、db2、sqlserver、PostgreSQL 等。
DruidMycatRouteStrategy 路由策略入口
MycatStatementParser 扩展语句解析
MycatSelectParser 扩展查询语句解析
MycatExprParser 扩展支持聚合函数
MycatLexer 扩展支持关键词
DruidParserFactory 解析工厂类
DruidSelectOracleParser oracle 分页解析
DruidSelectDb2Parser db2 分页解析
DruidSelectSqlServerParser sqlserver 分页解析
DruidSelectPostgresqlParser PostgreSQL 分页支持
RouteResultset 路由结果类
MyBatis PageHelper
https://blog.csdn.net/itcats_cn/article/details/81586724
Mybatis的插件运行原理
Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。