mysql 分区 mycat 分片_Mysql系列六:(Mycat分片路由原理、Mycat常用分片规则及对应源码介绍)...

一、Mycat分片路由原理我们先来看下面的一个SQL在Mycat里面是如何执行的:select * from travelrecord where id in(5000001, 10000001);有3个分片dn1,dn2,dn3, id=5000001这条数据在dn2上,id=10000001这条数据在dn3上。查询时可能有出现的问题:1)全部扫描一遍dn1 dn2 dn3,结果导致性能浪费...
摘要由CSDN通过智能技术生成

一、Mycat分片路由原理

我们先来看下面的一个SQL在Mycat里面是如何执行的:

select * from travelrecord where id in(5000001, 10000001);

有3个分片dn1,dn2,dn3, id=5000001这条数据在dn2上,id=10000001这条数据在dn3上。

查询时可能有出现的问题:

1)全部扫描一遍dn1  dn2  dn3,结果导致性能浪费。

2)只扫描某个片。漏掉数据的情况。

总结:

不能多扫——>性能不足

也不能少——>漏掉数据

那么Mycat是如何解决上面的问题的呢?

Mycat使用Druid的DruidParser作为分析器/解析器,解析的过程主要有Visitor和Statement两个阶段

4beb48a984765d62a660239857dd7907.png

说明:

1)Visitor过程,解析出如下属性:

哪一张表

字段列表

条件信息

什么样的SQL

解析出以上信息以后就可以根据schema.xml和rule.xml文件确认要去哪个分片上进行DML操作了

2)Statement过程转化:转化后知道执行的是什么样的SQL(增删改查)

3)改写SQL

通过查询条件可以知道要查询的数据都在哪些分片上

Dn2, id= 5000001

Dn3, id= 100000001

所以SQL被改写成以下的形式:

select * from travelrecord where id = 5000001;(dn2执行)select * from travelrecord where id = 10000001;(dn3执行)

4)分别在分片dn2,dn3上执行第 3)步改写的SQL,然后把从dn2,dn3上得到的结果进行拼装就是最终的结果了

备注:

多表关联查询的时候,visitor会遍历出所有的表,然后去各个分片上去获取结果,同时把结果缓存起来,最后根据关联查询计算出结果。

确定分片的过程:首先看where条件里面是否含有分片字段,有就根据分片字段的值结合schema.xml、rule.xml的值确定是哪个分片。当不能确定在哪一个分片上的时候,mycat会到所有的分片上去找

二、Mycat常用分片规则

1. 时间类:按天分片、自然月分片、单月小时分片

2. 哈希类:Hash固定分片、日期范围Hash分片、截取数字Hash求模范围分片、截取数字Hash分片、一致性Hash分片

3. 取模类:取模分片、取模范围分片、范围求模分片

4. 其他类:枚举分片、范围约定分片、应用指定分片、冷热数据分片

下面基于源码来介绍Mycat的常用分片规则,源码地址

三、Mycat常用分片规则介绍

说明:分片规则都定义在rule.xml文件里面

id

func1

1,1,2,3,1

128,128,128,128,128

1. 自动范围分片

在rule.xml里面的配置:

id

rang-long

autopartition-long.txt

说明:

有3个分片,第1个分片存储的是1-500000的数据,第2个分片存储的是500001-1000000的数据,第3个分片存储的是1000001-1500000的数据

insert into employee(id, name) value(1,Tom);在第1个分片

insert into employee(id, name) value(500002,Jack);在第2个分片

insert into employee(id, name) value(1000002,Lucy);在第3个分片

对应代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packageio.mycat.route.function;importjava.io.BufferedReader;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.util.HashSet;importjava.util.LinkedList;importjava.util.Set;importio.mycat.config.model.rule.RuleAlgorithm;/*** auto partition by Long ,can be used in auto increment primary key partition

*

*@authorwuzhi*/

public class AutoPartitionByLong extends AbstractPartitionAlgorithm implementsRuleAlgorithm{privateString mapFile;privateLongRange[] longRongs;private int defaultNode = -1;

@Overridepublic voidinit() {

initialize();

}public voidsetMapFile(String mapFile) {this.mapFile =mapFile;

}

@OverridepublicInteger calculate(String columnValue) {//columnValue = NumberParseUtil.eliminateQoute(columnValue);

try{long value =Long.parseLong(columnValue);

Integer rst= null;for (LongRange longRang : this.longRongs) {if (value <= longRang.valueEnd && value >=longRang.valueStart) {returnlongRang.nodeIndx;

}

}//数据超过范围,暂时使用配置的默认节点

if (rst == null && defaultNode >= 0) {returndefaultNode;

}returnrst;

}catch(NumberFormatException e){throw new IllegalArgumentException(new StringBuilder().append("columnValue:").append(columnValue).append(" Please eliminate any quote and non number within it.").toString(),e);

}

}

@OverridepublicInteger[] calculateRange(String beginValue, String endValue) {return AbstractPartitionAlgorithm.calculateSequenceRange(this, beginValue, endValue);

}

@Overridepublic intgetPartitionNum() {//int nPartition = longRongs.length;

/** fix #1284 这里的统计应该统计Range的nodeIndex的distinct总数*/Set distNodeIdxSet = new HashSet();for(LongRange range : longRongs) {

distNodeIdxSet.add(range.nodeIndx);

}int nPartition =distNodeIdxSet.size();returnnPartition;

}private voidinitialize() {

BufferedReader in= null;try{//FileInputStream fin = new FileInputStream(new File(fileMapPath));

InputStream fin = this.getClass().getClassLoader()

.getResourceAsStream(mapFile);if (fin == null) {throw new RuntimeException("can't find class resource file "

+mapFile);

}

in= new BufferedReader(newInputStreamReader(fin));

LinkedList longRangeList = new LinkedList();for (String line = null; (line = in.readLine()) != null;) {

line=line.trim();if (line.startsWith("#") || line.startsWith("//")) {continue;

}int ind = line.indexOf('=');if (ind < 0) {

System.out.println(" warn: bad line int " + mapFile + " :"

+line);continue;

}

String pairs[]= line.substring(0, ind).trim().split("-");long longStart = NumberParseUtil.parseLong(pairs[0].trim());long longEnd = NumberParseUtil.parseLong(pairs[1].trim());int nodeId = Integer.parseInt(line.substring(ind + 1)

.trim());

longRangeList

.add(newLongRange(nodeId, longStart, longEnd));

}

longRongs= longRangeList.toArray(newLongRange[longRangeList

.size()]);

}catch(Exception e) {if (e instanceofRuntimeException) {throw(RuntimeException) e;

}else{throw newRuntimeException(e);

}

}finally{try{

in.close();

}catch(Exception e2) {

}

}

}public intgetDefaultNode() {returndefaultNode;

}public void setDefaultNode(intdefaultNode) {this.defaultNode =defaultNode;

}static classLongRange {public final intnodeIndx;public final longvalueStart;public final longvalueEnd;public LongRange(int nodeIndx, long valueStart, longvalueEnd) {super();this.nodeIndx =nodeIndx;this.valueStart =valueStart;this.valueEnd =valueEnd;

}

}

}

View Code

2. 枚举分片

把数据分类存储

在rule.xml里面的配置:

sharding_id

hash-int

partition-hash-int.txt

0

说明:找不到分片时设置容错规则,把数据插入到默认分片0里面

对应代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packageio.mycat.route.function;importjava.io.BufferedReader;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.util.HashMap;importjava.util.HashSet;importjava.util.Map;importjava.util.Set;importio.mycat.config.model.rule.RuleAlgorithm;/***

*@authormycat*/

public class PartitionByFileMap extends AbstractPartitionAlgorithm implementsRuleAlgorithm {privateString mapFile;private Mapapp2Partition;/*** Map app2Partition中key值的类型:默认值为0,0表示Integer,非零表示String*/

private inttype;/*** 默认节点在map中的key*/

private static final String DEFAULT_NODE = "DEFAULT_NODE";/*** 默认节点:小于0表示不设置默认节点,大于等于0表示设置默认节点

*

* 默认节点的作用:枚举分片时,如果碰到不识别的枚举值,就让它路由到默认节点

* 如果不配置默认节点(defaultNode值小于0表示不配置默认节点),碰到

* 不识别的枚举值就会报错,

* like this:can't find datanode for sharding column:column_name val:ffffffff*/

private int defaultNode = -1;

@Overridepublic voidinit() {

initi

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值