查看原文
其他

Mycat 的分片规则设计

2016-07-02 IT哈哈

分片规则设计架构


分布式数据库系统中,分片规则用于定义数据与分片的路由关系,也就是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;

        }


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存