go语言实现 一致性hash算法

package tool

import (
	"errors"
	"hash/crc32"
	"sort"
	"strconv"
	"sync"
)

//申明切片类型
type units []uint32

//返回切片长度
func (x units) Len() int {
	return len(x)
}

//比较两个值的大小
func (x units) Less(i, j int) bool {
	return x[i] < x[j]
}

//切片中值交换
func (x units) Swap(i, j int) {
	x[i], x[j] = x[j], x[i]
}

//当hash环没有数据时,提示错误
var emptyErr = errors.New("hash 环为空")

//创建结构体,保存一致性hash信息
type Consistent struct {
	//hash环,key为hash值,值存放的是节点信息
	circle map[uint32]string
	//已经排序的节点hash切片
	sortedHashes units
	//虚拟节点个数,用来增加hash的平衡性
	virtualNode int
	//读写锁
	sync.RWMutex
}

func NewConsistent() *Consistent {
	return &Consistent{
		//初始化变量
		circle: make(map[uint32]string),
		//设置虚拟节点个数
		virtualNode: 20,
	}
}

//自动生成key值
func (c *Consistent) generateKey(element string, index int) string {
	//副本key生成逻辑
	return element + strconv.Itoa(index)
}

//获取hash位置
func (c *Consistent) hashKey(key string) uint32 {
	if len(key) < 64 {
		var srcatch [64]byte
		copy(srcatch[:], key)

		//使用IEEE多项式返回数据的CRC-32校验和
		return crc32.ChecksumIEEE(srcatch[:len(key)])
	}

	return crc32.ChecksumIEEE([]byte(key))
}

//更新排序,方便查找
func (c *Consistent) updateSortedHashes() {
	hash := c.sortedHashes[:0]

	//判断切片容量是否过大,如果过大则重置
	if cap(c.sortedHashes)/(c.virtualNode*4) > len(c.circle) {
		hash = nil
	}

	//添加hash
	for k := range c.circle {
		hash = append(hash, k)
	}

	//排序
	sort.Sort(hash)

	c.sortedHashes = hash
}

//向hash环添加节点
func (c *Consistent) Add(element string) {
	c.Lock()
	defer c.Unlock()
	c.add(element)
}

func (c *Consistent) add(element string) {
	//生成虚拟节点
	var (
		i    int
		hash uint32
		key  string
	)

	//循环虚拟节点,设置副本
	for i = 0; i < c.virtualNode; i++ {
		key = c.generateKey(element, i)
		hash = c.hashKey(key)
		c.circle[hash] = element
	}

	//更新排序
	c.updateSortedHashes()
}

func (c *Consistent) remove(element string) {
	//生成虚拟节点
	var (
		i    int
		hash uint32
		key  string
	)

	//循环虚拟节点,设置副本
	for i = 0; i < c.virtualNode; i++ {
		key = c.generateKey(element, i)
		hash = c.hashKey(key)
		delete(c.circle, hash)
	}

	//更新排序
	c.updateSortedHashes()
}

//删除节点
func (c *Consistent) Remove(element string) {
	c.Lock()
	defer c.Unlock()
	c.remove(element)
}

//顺时针查找最近的节点
func (c *Consistent) search(key uint32) int {
	f := func(x int) bool {
		return c.sortedHashes[x] > key
	}

	i := sort.Search(len(c.sortedHashes), f)

	if i > len(c.sortedHashes) {
		i = 0
	}

	return i
}

//根据数据表示,获取对应的服务器节点信息
func (c *Consistent)Ger(name string) (string,error){
	c.Lock()
	defer c.Unlock()

	if len(c.circle) == 0 {
		return "",emptyErr
	}

	key := c.hashKey(name)
	i := c.search(key)

	return c.circle[c.sortedHashes[i]],nil
}
上一篇:Redis - 一致性哈希(Consistent Hashing Algorithm)


下一篇:【算法】一致性哈希算法(consistent hashing)