Mycat 数据分片--取模函数源码阅读:
package io.mycat.route.function;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.mycat.config.model.rule.RuleAlgorithm;
/**
* number column partion by Mod operator
* if count is 10 then 0 to 0,21 to 1 (21 % 10 =1)
* @author wuzhih
*
*/
public class PartitionByMod extends AbstractPartitionAlgorithm implements RuleAlgorithm {
private int count;
@Override
public void init() {
}
public void setCount(int count) {
this.count = count;
}
@Override
public Integer calculate(String columnValue) {
// columnValue = NumberParseUtil.eliminateQoute(columnValue);
try {
BigInteger bigNum = new BigInteger(columnValue).abs();
return (bigNum.mod(BigInteger.valueOf(count))).intValue();
} catch (NumberFormatException e){
throw new IllegalArgumentException(new StringBuilder().append("columnValue:").append(columnValue).append(" Please eliminate any quote and non number within it.").toString(),e);
}
}
@Override
public int getPartitionNum() {
int nPartition = this.count;
return nPartition;
}
private static void hashTest() {
PartitionByMod hash=new PartitionByMod();
//初始化机器节点的数量为11
hash.setCount(11);
hash.init();//空方法暂无实际意义
//数组用来统计每个节点存储的数据条数,数组下标从0开始编号,刚好和机器编号相同
int[] bucket=new int[hash.count];
//Map存储节点数据的片键,其中key为机器编号0-10,
// Value为分库分表对应的键值,例如以ID为主键的一系列集合
Map
int total=1000_0000;//数据量
int c=0;
for(int i=100_0000;i
c++;//计数器统计循环的次数
//核心思想 i%count 取模,取模之后的余数值范围为0-count-1,其值对应的就是机器的节点编号
//键值为0即刚好是count的整数倍
int h=hash.calculate(Integer.toString(i));
//计数器,统计落在节点h上的数据量
bucket[h]++;
//从Map中取出节点H中存储的片键集合容器List,第一次肯定为空
List
if(list==null){
list=new ArrayList<>();
hashed.put(h, list);
}
//把落在节点H中的数据扔到集合容器里面
list.add(i);
}
System.out.println(c+" "+total);
double d=0;
c=0;
int idx=0;
System.out.println("index bucket ratio");
//bucket中的值就是数据落在每个节点的数量,下标就是机器编号
for(int i:bucket){
//变量d是一个分布率求和统计,i代表落在节点的数量,total代表数据总数
d+=i/(double)total;
//统计各个节点的数据总和
c+=i;
//输出:机器节点下标 节点上数据总数 节点中数据占总数的比例
System.out.println("机器编号:"+(idx++)+",数据总数: "+i+" ,占比例: "+(i/(double)total));
}
System.out.println("分布率求和:"+d+" 各节点数据总数即路由总数: "+c);
System.out.println("****************************************************");
//取出在节点0的数据进行重新分布
rehashTest(hashed.get(0));
}
private static void rehashTest(List
PartitionByMod hash=new PartitionByMod();
//注意节点0上的数据都是11的整数倍,现在机器节点达到110,
//所以节点1上的数据重新路由会落在11,22,33,99上面
//机器编号为0---109
hash.count=110;//分片数
hash.init();
//新数组用来统计每个节点存储的数据条数,数组下标从0开始编号,刚好和机器编号相同
int[] bucket=new int[hash.count];
int total=partition.size();//数据量
int c=0;
for(int i:partition){//假设分片键从100万开始
c++;
int h=hash.calculate(Integer.toString(i));
bucket[h]++;
}
System.out.println(c+" "+total);
c=0;
int idx=0;
System.out.println("index bucket ratio");
for(int i:bucket){
c+=i;
System.out.println(idx+++" "+i+" "+(i/(double)total));
}
}
public static void main(String[] args) {
hashTest();
// PartitionByMod partitionByMod = new PartitionByMod();
// partitionByMod.count=8;
// partitionByMod.calculate("\"6\"");
// partitionByMod.calculate("\'6\'");
}
}
结果验证:
疑问:各个节点分布数据的比例总和 为什么不是100%,而是99.9999%是因为机器存储浮点数的误差导致。