您的位置:首页 > 其它

Mycat 的分片规则设计

2016-07-02 00:00 309 查看
摘要: 分布式数据库系统中,分片规则用于定义数据与分片的路由关系,也就是insert,delete,update,select的基本sql操作中,如何将sql路由到对应的分片执行。

分片规则设计架构

分布式数据库系统中,分片规则用于定义数据与分片的路由关系,也就是insert,delete,update,select的基本sql操作中,如何将sql路由到对应的分片执行。

Mycat的总体路由图为:



如图所示分片规则是最终解析sql到那个分片执行的规则,Mycat分片的确定是根据分片字段来确定数据的分布,即根据预先配置好的分片字段(只有一个)到分片规则中解析该字段对应的值应该路由到哪个分片,然后确认sql到哪个分片执行,分片规则的类图设计为:



RouterUtil,RouteResultset,RouteResultsetNode 几张表是解析sql,解析出sql路由的节点,内部调用AbstractPartitionAlgorithm实现类解析分片字段,查找对应的分片。

AbstractPartitionAlgorithm :为路由规则的抽象类。

RuleAlgorithm :路由规则接口抽象,规定了分片规则的初始化(init),路由分片计算(calculate),及路由多值分片计算(calculateRange)。

分片规则中calculate方法是基本的分片路由计算方法,根据分片字段值,计算出分片。

分片规则中calculateRange方法是范围查询时分片计算,即如果查询类似:

select * from t_user t where t.id<100;

需要解析出指定范围的所有值对应分片。

自定义的分片规则只需要继承AbstractPartitionAlgorithm,按照自己的规则初始化配置文件,并且实现calculate或者calculateRange方法即可,路由的配置文件为:rule.xml。

route 包下面是对应的路由处理,其下面的function包,是分片规则的具体抽象与实现的代码位置。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mycat:rule SYSTEM "rule.dtd"><mycat:rule xmlns:mycat="http://org.opencloudb/"><tableRule name="rule1"><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下的columns规定了分片字段,algorithm为自定义分片类配置。

function 标签为分片规则配置:

name : 为自定义名字

class: 自定义分片规则方法。

property: 其中的参数为自定义参数配置。

分片规则自定义实现

本章节通过日期分片讲解分片规则内部实现细节:

package org.opencloudb.route.function;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import org.apache.log4j.Logger;

import org.opencloudb.config.model.rule.RuleAlgorithm;

/** * 例子按日期列分区格式 between操作解析的范例

* * @author lxy

* */

public class PartitionByDate extends AbstractPartitionAlgorithm implements RuleAlgorithm {

private static final Logger LOGGER = Logger.getLogger(PartitionByDate.class);

private String sBeginDate;

private String sPartionDay;

private String dateFormat;

private long beginDate;

private long partionTime;

private static final long oneDay = 86400000;

@Override

public void init() {

try {

beginDate = new SimpleDateFormat(dateFormat).parse(sBeginDate) .getTime();

} catch (ParseException e) {

throw new java.lang.IllegalArgumentException(e);

}

partionTime = Integer.parseInt(sPartionDay) * oneDay;

}

@Override

public Integer calculate(String columnValue) {

try {

long targetTime = new SimpleDateFormat(dateFormat).parse(columnValue).getTime();

int targetPartition = (int) ((targetTime - beginDate) / partionTime);

return targetPartition;

} catch (ParseException e) {

throw new java.lang.IllegalArgumentException(e);

}

}

@Override

public Integer[] calculateRange(String beginValue, String endValue) {

return AbstractPartitionAlgorithm.calculateSequenceRange(this, beginValue, endValue);

}

public void setsBeginDate(String sBeginDate) {

this.sBeginDate = sBeginDate;

}

public void setsPartionDay(String sPartionDay) {

this.sPartionDay = sPartionDay;

}

public void setDateFormat(String dateFormat) {

this.dateFormat = dateFormat;

}

}

在日期分片字段配置中,分片规则类PartitionByDate的配置属性与类的成员变量对应一次为

dateFormat==>private String dateFormat;

sBeginDate==>private String sBeginDate;

sPartionDay==>private String sPartionDay;

在Mycat的配置文件装载机制中,会根据property 自动设置类的成员变量,因此只要设置了Set…方法就可以赋值。

init方法:

主要处理每种规则的自定义处理,例如本规则中,解析了变量beginDate、partionTime

try {

beginDate = new SimpleDateFormat(dateFormat).parse(sBeginDate) .getTime();

} catch (ParseException e) {

throw new java.lang.IllegalArgumentException(e);

}

partionTime = Integer.parseInt(sPartionDay) * oneDay;

calculate方法:

计算路由分片的核心方法,本规则中通过处理传入的(目标日期-设置的开始日期间隔)/分片时间,计算出偏移量即是分片节点,所有的分片节点编号都是从0开始编码。

例如:每个1天一分片,开始日期是2015-01-01那么分片日期字段值假若是2015-01-10,那么通过公式:

`分片=(2015-01-10-2015-01-01)/1 =9 ,即dn9。

try {

long targetTime = new SimpleDateFormat(dateFormat).parse(columnValue).getTime();

int targetPartition = (int) ((targetTime - beginDate) / partionTime);

return targetPartition;

} catch (ParseException e) {

throw new java.lang.IllegalArgumentException(e);

}

calculateRange方法:

calculateRange 方法默认根据继承的抽象类规则,可以不实现,默认实现是获取分片字段的值连续范围内的所有分片,主要用于类似:update test where id<5; 这种语句中,通过解析条件 id<15解析出所有的id值域分片的对应关系,依次路由执行,[1->dn0,2->dn1,3->dn2,4->dn3].

Integer begin = 0, end = 0;

begin = algorithm.calculate(beginValue);

end = algorithm.calculate(endValue);

if(begin == null || end == null){

return new Integer[0];

}

if (end >= begin) {

int len = end-begin+1;

Integer [] re = new Integer[len];

for(int i =0;i<len;i++){

re[i]=begin+i;

}

return re;

}else{

return null;

}

更多内容请关注微信公众号:it_haha
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: