hash一致性算法

面试经常问到的一致hash算法


那到底hash一致算法是什么?

这里以缓存为例,它是保证部署redis集群的时候,可以在不同的机器上准确定位到自己存放的缓存机器。

在什么地方用到?

缓存 ES Handoop 分布式数据库

为什么这些场景用到?

以缓存为例,缓存可以提升数据访问性能,可以缓解数据库压力。但是集群部署的话,会导致不同机器存储的数据很难稳定寻找同一个缓存机器。所以这里就需要一致性hash算法,来确保每个服务器都可以寻找相对应的缓存机器。

hash一致性算法原理
hash一致性原理

但是这种方式有2个问题:

问题

所以下面我们需要解决这两个问题
提出虚拟节点概念,虚拟节点用其他hash算法实现,使虚拟节点均衡分布。
在这里插入图片描述
新增服务器到集群时 也是均衡分布
当加入新服务器到集群时
hash算法有以下几种
hash分布算法
存储的结构
存储结构
这里我们根据需求选择最合适的红黑树实现环存储

好的,上面的理论我们已经清楚了,那下面就用代码来实现一把。

FNV1_32_HASH
 public class FNV1_32_HASH {
	public static int getHash(String str) {
		final int p = 16777619;
		int hash = (int) 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;
	}
}

ConsistencyHash
package com.study.xuy.hash;

import com.study.mike.consistence.hash.FNV1_32_HASH;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

public class ConsistencyHash {
    //物理节点集合  用String 类型表示
    private List<String> physicalIps = new ArrayList<String>();
    //每个物理ip  对应 实现的虚拟节点数
    private Map<String, List<Integer>> physicalIp2Virtuals = new HashMap<>();
    //每个物理ip分配的虚拟节点数量  默认100
    private int virtualsNum = 100;
    //虚拟节点对应的物理节点  相当于环  用TreeMap实现红黑树存储
    private SortedMap<Integer, String> sortedMap = new TreeMap<>();


    public ConsistencyHash(int virtualsNum) {
        super();
        this.virtualsNum = virtualsNum;
    }

    public ConsistencyHash() {
        super();
    }

    /**
     * 增加物理ip  到环
     *
     * @param physicalIp
     */
    public void addServer(String physicalIp) {
        this.physicalIps.add(physicalIp);
        //加入物理ip对应的虚拟集合
        ArrayList<Integer> virtuals = new ArrayList<>();
        this.physicalIp2Virtuals.put(physicalIp, virtuals);

        int count = 0, i = 0;
        while (count < this.virtualsNum) {
            i++;
            int hash = FNV1_32_HASH.getHash(physicalIp+"&&v-"+i);
            //解决hash碰撞问题
            if (!sortedMap.containsKey(hash)) {
                virtuals.add(hash);
                this.sortedMap.put(hash, physicalIp);
                count ++;
            }
            System.out.println(count);
        }

    }

    /**
     * 获取物理ip
     * @param key
     * @return
     */
    public String getServer(String key){
        int hash = FNV1_32_HASH.getHash(key);
        //获取大于环上大于key hash的所有虚拟对应 物理ip
        SortedMap<Integer, String> integerStringSortedMap = this.sortedMap.tailMap(hash);

        if (!integerStringSortedMap.isEmpty()){
            return integerStringSortedMap.get(integerStringSortedMap.firstKey());
        }else { //没有数据时  取第一个虚拟节点上的  物理ip  顺时针取值
            return this.sortedMap.get(sortedMap.firstKey());
        }

    }

    /**
     * 移除物理ip
     * @param physicalIp
     */
    public void remoceServer(String physicalIp){
        //获得此物理ip 对应所有虚拟节点
        List<Integer> integers = this.physicalIp2Virtuals.get(physicalIp);
        if (!integers.isEmpty()) {
            for (Integer integer : integers) {
                this.sortedMap.remove(integer);
            }
        }
        this.physicalIps.remove(physicalIp);
        this.physicalIp2Virtuals.remove(physicalIp);

    }


    public static void main(String[] args) {
        ConsistencyHash consistencyHash = new ConsistencyHash();
        consistencyHash.addServer("192.168.0.10");
        consistencyHash.addServer("192.168.0.11");
        consistencyHash.addServer("192.168.0.12");

        System.out.println(1111);
        for (int i=0; i <10 ; i++){
            System.out.println("ab"+i+"服务器物理ip:"+consistencyHash.getServer("ab"+i));
        }


    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值