一致性hash算法总结

       一致性hash算法一般在分布式系统中运用比较广泛,例如多节点的数据存储,dubbo框架中也实现了一致性hash算法来选择服务提供者。还有在mysql集群,分库分表时,一致性hash也是比较常用的用来划分数据区域的算法。

       举个例子,电商公司的订单表,一般都会用数据库集群或者分库分表,用多个数据库实例在承载订单信息,这么大数据量的信息,在查询的时候,首先必须要保证幂等性,就是多次调用hash算法得出的hash值都必须一样,这样才能保证在去查询订单信息的时候,都会到对应的数据库实例中去查询,否则就可能会查不到订单信息,之前经历的就是将订单表拆分为了512张表,按照订单时间来经行hash一致性算法

一致性hash的数据结构:

    090559_z9nZ_3426682.png

蓝色表示机器节点,橘黄色表示数据节点

真实节点:A B C D

虚拟节点:A1 A2 B1 B2 C1 C2 D1 D2

数据存放规则:计算出各个虚拟节点的hash值(不一定非要hash算法,可以是符合自己业务逻辑的算法,只要保证有效的数据通过hash算法能够在hash环内都有落点并且具有幂等性),例如:K1的hash值∈(A1,C2),则得出K1应该存放在C2节点

本章用java实现了两种hash一致性算法;

1.没有虚拟节点的hash环(逻辑环)

2.带虚拟节点的hash环(逻辑环)

备注:我这里为了方便测试,直接给对应的真是节点的hash值写死了

实现一:

package com.dubbo.algorithm;

import java.util.SortedMap;
import java.util.TreeMap;

public class ShardHash {
	
	//真实机器节点 <hash值,节点信息>
	private TreeMap<Long,String> realNodes = new TreeMap<Long,String>();
	
	public ShardHash(){
		init();
	}
	
	public void init(){
		// A B C D 4个真实节点
		realNodes.put(1L, "A");
		realNodes.put(6L, "B");
		realNodes.put(14L, "C");
		realNodes.put(25L, "D");
		/*
		realNodes.put(hash("A"), "A");
		realNodes.put(hash("B"), "B");
		realNodes.put(hash("C"), "C");
		realNodes.put(hash("D"), "D");
		*/
	}
	
	public String getNode(String key){
		//方便测试
		Long keyHash = Long.valueOf(key);
//		Long keyHash = hash(key);
		//根据key的hash值,找到hash环上面比此hash值大的节点
		SortedMap<Long,String> sorted = realNodes.tailMap(keyHash);
		if(sorted.isEmpty()){
			//没有比key的hash大的节点,则该key存放在第一个节点上面
			String node = realNodes.get(realNodes.firstKey());
			return node;
		}
		String node = sorted.get(sorted.firstKey());
		return node;
	}
	
	/** 
	 * 网上copy的一个hash算法,可以选择适合自己场景的hash算法
     */  
    private Long hash(String str) {  
        final int p = 16777619;  
        Long hash =  2166136261L;  
        for (int i = 0; i < str.length(); i++)  
            hash = (hash ^ str.charAt(i)) * p;  
        hash += hash << 13;  
        hash ^= hash >> 7;  
        hash += hash << 3;  
        hash ^= hash >> 17;  
        hash += hash << 5;  
  
        // 如果算出来的值为负数则取其绝对值  
        if (hash < 0)  
            hash = Math.abs(hash);  
        return hash; 
    }  
    public static void main(String[] args) {
    	ShardHash s = new ShardHash();
    	String node = s.getNode("33");
    	System.out.println("数据存放节点为:"+node);
	}
}

实现二:

package com.dubbo.algorithm;

import java.util.LinkedList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

public class ShardHashV {
	//真实节点,4个真实节点
	private List<String> realNodes = new LinkedList<String>();
	//虚拟节点
	private TreeMap<Long,String> vNode = new TreeMap<Long,String>();
	//每个真实节点对应多少个虚拟节点
	private int VNODE_NUM = 4;
	//区间大小
	private static Long count = 0L;
	
	public ShardHashV(){
		init();
	}
	
	//0--5--10--15....
	public void init(){
		realNodes.add("A1");
		realNodes.add("B1");
		realNodes.add("C1");
		realNodes.add("D1");
		for(int i=0;i<realNodes.size();i++){
			for(int j=0;j<VNODE_NUM;j++){
				vNode.put(hash(), "A"+(j+1));
				vNode.put(hash(), "B"+(j+1)); 
				vNode.put(hash(), "C"+(j+1)); 
				vNode.put(hash(), "D"+(j+1)); 
			}
		}
	}
	
	public String getNodes(String key){
		//找到所有比key大的节点
		SortedMap<Long,String> sm = vNode.tailMap(Long.valueOf(key));
		if(sm.isEmpty()){
			String node =vNode.get(vNode.firstKey()) ;
			return node;
		}
		String node =vNode.get(sm.firstKey()) ;
		return node;
	}
	
	public void remove(String key){
		vNode.remove(Long.valueOf(key));
	}
	
    public static void main(String[] args) {
    	ShardHashV sv = new ShardHashV();
    	System.out.println(sv.getNodes("0"));
    	System.out.println(sv.getNodes("7"));
    	System.out.println(sv.getNodes("11"));
    	System.out.println(sv.getNodes("16"));
    	System.out.println(sv.getNodes("54"));
    	//删除B1节点
    	sv.remove("10");
    	System.out.println(sv.getNodes("7"));
    	sv.remove("5");
    	System.out.println(sv.getNodes("3"));
	}
	/** 
	 * 网上copy的一个hash算法,可以选择适合自己场景的hash算法
     */  
    private Long hash() {  
    	Long key = this.count+5L;
    	count=count+5L;
        return key; 
    }  

}

 

转载于:https://my.oschina.net/u/3426682/blog/1549997

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值