• MyCat


    此文已由作者张镐薪授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    意思就是,开头为北京的范围在A0000000~A9999999的根据后面的哈希值对5取模平均分布在0,1,2,3,4分片节点上。开头为北京的范围在B0000000以上的根据后面的哈希值对5取模平均分布在5,6,7,8,9分片节点上。开头为上海的范围在00000000~10000000的根据后面的哈希值对2取模平均分布在10,11分片节点上,剩下的开头为上海的,对6取模平均分布在10,11,12,13,14,15上。  这样,在发现某个开头的分片不够用时,可以随时改变分片规则,只要不删除之前的分片规则,就不影响以前数据的访问。在完成数据迁移后,可以删除之前的规则。 实现方法就是采用hashmap存储这些对应关系:

    /**
    * 首先实现不带范围约定的复合规则,即配置文件中为:
    * 北京=0,1,2,3,4
    * 上海=10,11
    */public class PartitionByRouteHash extends AbstractPartitionAlgorithm implements RuleAlgorithm {    protected String routeFile;    private Map<String, List<Integer>> routeNodeMap;    protected static final String DEFAULT_NODE = "DEFAULT_NODE";    protected int keyStartIndex;    protected int keyEndIndex;    protected int valueStartIndex;    protected int valueEndIndex;    public void setKeyStartIndex(int keyStartIndex) {        this.keyStartIndex = keyStartIndex;
        }    public void setKeyEndIndex(int keyEndIndex) {        this.keyEndIndex = keyEndIndex;
        }    public void setValueStartIndex(int valueStartIndex) {        this.valueStartIndex = valueStartIndex;
        }    public void setValueEndIndex(int valueEndIndex) {        this.valueEndIndex = valueEndIndex;
        }    public void setRouteFile(String routeFile) {        this.routeFile = routeFile;
        }
    
        @Override    public void init() {
            initialize();
        }
        @Override    public Integer calculate(String columnValue) {
            String key = columnValue.substring(keyStartIndex,keyEndIndex);
            String value = columnValue.substring(valueStartIndex,valueEndIndex);
            List<Integer> nodes = routeNodeMap.get(key);        if(nodes == null)
                nodes = routeNodeMap.get(DEFAULT_NODE);
            BigInteger bigNum = new BigInteger(""+value.hashCode());        return nodes.get((bigNum.mod(BigInteger.valueOf(nodes.size()))).intValue());
        }    /**
         * 读取文件,创建哈希表保存对应关系
         */
        private void initialize() {
            BufferedReader in = null;        try {            // FileInputStream fin = new FileInputStream(new File(fileMapPath));
                InputStream fin = this.getClass().getClassLoader()
                        .getResourceAsStream(routeFile);            if (fin == null) {                throw new RuntimeException("can't find class resource file "
                            + routeFile);
                }            in = new BufferedReader(new InputStreamReader(fin));
    
                routeNodeMap = new HashMap<String, List<Integer>>();            for (String line = null; (line = in.readLine()) != null;) {
                    line = line.trim();                if (line.startsWith("#") || line.startsWith("//"))                    continue;                int ind = line.indexOf('=');                if (ind < 0)                    continue;                try {
                        String key = line.substring(0, ind).trim();
                        String value = line.substring(ind+1).trim();
                        String []nodes = value.split(",");
                        List<Integer> values = new ArrayList<Integer>();                    for(int i = 0 ; i< nodes.length ; i++){
                            values.add(Integer.parseInt(nodes[i].trim()));
                        }
                        routeNodeMap.put(key,values);
                    } catch (Exception e) {
                        System.out.println("something wrong in the route hash configuration!");
                    }
                }
            } catch (Exception e) {            if (e instanceof RuntimeException) {                throw (RuntimeException) e;
                } else {                throw new RuntimeException(e);
                }
    
            } finally {            try {                in.close();
                } catch (Exception e2) {
                }
            }
        }
    }
    /**
    * 实现范围约定的复合规则
    */public class PartitionByScalableRouteHash extends PartitionByRouteHash {    private Map<String,Map<String[],List<Integer>>> routeNodeMap;
    
        @Override    public void init() {
            initialize();
        }
    
        @Override    public Integer calculate(String columnValue) {
            String key = columnValue.substring(keyStartIndex,keyEndIndex);
            String value = columnValue.substring(valueStartIndex,valueEndIndex);
            Map<String[],List<Integer>> scaleMap = routeNodeMap.get(key);        if(scaleMap==null){
                scaleMap = routeNodeMap.get(this.DEFAULT_NODE);
            }
            String []ranges = new String[1];        for(String []range:scaleMap.keySet()){            if(range[0].equals(this.DEFAULT_NODE))                continue;            if(range[0].compareTo(value)<0&&range[1].compareTo(value)>0)
                    ranges = range;
            }        if(ranges.length==1) {            for(String []range:scaleMap.keySet()){                if(range[0].equals(this.DEFAULT_NODE)){
                        ranges = range;                    break;
                    }
                }
            }
            List<Integer> nodes = scaleMap.get(ranges);
            BigInteger bigNum = new BigInteger(""+value.hashCode());        return nodes.get((bigNum.mod(BigInteger.valueOf(nodes.size()))).intValue());
        }    private void initialize(){
            BufferedReader in = null;        try {            // FileInputStream fin = new FileInputStream(new File(fileMapPath));
                InputStream fin = this.getClass().getClassLoader()
                        .getResourceAsStream(routeFile);            if (fin == null) {                throw new RuntimeException("can't find class resource file "
                            + routeFile);
                }            in = new BufferedReader(new InputStreamReader(fin));
    
                routeNodeMap = new HashMap<String, Map<String[], List<Integer>>>();            for (String line = null; (line = in.readLine()) != null;) {
                    line = line.trim();                if (line.startsWith("#") || line.startsWith("//"))                    continue;                int lb = line.indexOf('('),rb = line.indexOf(')'),mb = line.indexOf(':');                int ind = line.indexOf('=');                if((lb!=-1&&rb!=-1&&mb!=-1)&&(mb<lb||mb>rb||lb>rb||rb>ind)){                    throw new RuntimeException("Wrong format! Error use of (),:,=!");
                    }                if (ind < 0)                    continue;                try {
                        String key = line.substring(0, lb<0?ind:lb).trim();
                        Map<String[],List<Integer>> scaleMap = routeNodeMap.get(key);                    if(scaleMap == null){
                            scaleMap = new HashMap<String[],List<Integer>>();
                            routeNodeMap.put(key,scaleMap);
                        }
                        String[] valueRange = new String[2];                    if(lb!=-1&&rb!=-1&&mb!=-1) {
                            String minValue = line.substring(lb + 1, mb).trim();
                            String maxValue = line.substring(mb + 1, rb).trim();                        if (minValue.length() != maxValue.length() || minValue.compareTo(maxValue) >= 0) {                            throw new RuntimeException("Wrong value range! ");
                            }
                            valueRange[0] = minValue;
                            valueRange[1] = maxValue;
                        }                    else {
                            valueRange[0] = this.DEFAULT_NODE;
                        }
                        String value = line.substring(ind+1).trim();
                        String []nodes = value.split(",");
                        List<Integer> node = new ArrayList<Integer>();                    for(int i = 0 ; i< nodes.length ; i++){
                            node.add(Integer.parseInt(nodes[i].trim()));
                        }
                        scaleMap.put(valueRange,node);
                    } catch (Exception e) {
                        System.out.println("something wrong in the route hash configuration!");
                    }
                }
            } catch (Exception e) {            if (e instanceof RuntimeException) {                throw (RuntimeException) e;
                } else {                throw new RuntimeException(e);
                }
    
            } finally {            try {                in.close();
                } catch (Exception e2) {
                }
            }
        }
    
    }

    之后如果想用这个规则,在rule.xml中添加如下配置即可:

    <tableRule name="scalable-route-hash">
            <rule>
                <columns>order_id</columns>
                <algorithm>scalable-route-hash</algorithm>
            </rule>
        </tableRule>
        <function name="scalable-route-hash" class="org.opencloudb.route.function.PartitionByRouteHash">
            <property name="routeFile">scalable-route-hash.txt</property>
            <property name="keyStartIndex">0</property>
            <property name="keyEndIndex">5</property>
            <property name="valueStartIndex">5</property>
            <property name="valueEndIndex">11</property>
        </function>


    免费体验云安全(易盾)内容安全、验证码等服务

    更多网易技术、产品、运营经验分享请点击




    相关文章:
    【推荐】 Gradle task
    【推荐】 debian 7上源码编译MongoDB 3.4版本
    【推荐】 新手入门Sqlalchemy

  • 相关阅读:
    整型表示
    有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?
    shell排序算法实现
    一些小细节
    wordpress新注册用户或重置密码链接失效
    wordpress访问速度慢
    mysql主从复制
    mysql root密码忘记
    mysql root用户登录后无法查看数据库全部表
    Ansible
  • 原文地址:https://www.cnblogs.com/163yun/p/9888770.html
Copyright © 2020-2023  润新知