golang编码一致性哈希算法

目录

1、原理

2、代码


1、原理

原理直接看:5分钟读懂一致性哈希算法原理

2、代码

package main

import (
	"fmt"
	"hash/crc32"
	"log"
	"sort"
	"strconv"
	"strings"
)

//HashFunc 定义生成哈希的函数
type HashFunc func(data []byte) uint32

type Map struct {
	hashFunc HashFunc       //哈希算法
	replicas int            //虚拟节点的数量
	keys     []int          //所有虚拟节点的哈希值
	hashMap  map[int]string //key->虚拟节点的哈希值,value->节点,实现虚拟节点映射到真实节点
}

//New 创建Map
func New(replicas int, fn HashFunc) *Map {
	m := &Map{
		replicas: replicas,
		hashFunc: fn,
		hashMap:  make(map[int]string),
	}
	if m.hashFunc == nil {
		m.hashFunc = crc32.ChecksumIEEE
	}
	return m
}

//Map中是否存在节点
func (m *Map) IsEmpty() bool {
	return len(m.keys) == 0
}

func (m *Map) AddNode(keys ...string) {
	for _, key := range keys {
		if key == "" {
			continue
		}

		for i := 0; i < m.replicas; i++ {
			//计算虚拟节点哈希值
			hash := int(m.hashFunc([]byte(strconv.Itoa(i) + key)))

			//存储虚拟节点哈希值
			m.keys = append(m.keys, hash)

			//存入map做映射
			m.hashMap[hash] = key
		}
	}

	//排序哈希值,下面匹配的时候要二分搜索
	sort.Ints(m.keys)
}

//支持哈希标记
func getPartitionKey(key string) string {
	beg := strings.Index(key, "{")
	if beg == -1 {
		return key
	}

	end := strings.Index(key, "}")
	if end == -1 || end == beg+1 {
		return key
	}
	return key[beg+1 : end]
}

//获取与key最接近的节点
func (m *Map) PickNode(key string) string {
	if m.IsEmpty() {
		return ""
	}

	partitionKey := getPartitionKey(key)

	//计算传入key的哈希值
	hash := int(m.hashFunc([]byte(partitionKey)))

	//sort.Search使用二分查找满足m.Keys[i]>=hash的最小哈希值
	idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash })

	//若key的hash值大于最后一个虚拟节点的hash值,则选择第一个虚拟节点
	if idx == len(m.keys) {
		idx = 0
	}

	return m.hashMap[m.keys[idx]]

}

func TestHash() {
	m := New(3, nil)
	m.AddNode("a", "b", "c", "d")
	if m.PickNode("zxc") != "a" {
		log.Println("wrong answer")
	}
	if m.PickNode("123{abc}") != "b" {
		log.Println("wrong answer")
	}
	if m.PickNode("abc") != "b" {
		log.Println("wrong answer")
	}
	for i := 0; i < 26; i++ {
		fmt.Println(string(97+i)+"zhpQQ1159968733", "在[", m.PickNode(string(97+i)), "]节点")
	}
}

func main() {
	TestHash()
}

执行结果:

[Running] go run "c:\work\1_src\999_test\7_consistent_hashing\main.go"
azhpQQ1159968733 在[ b ]节点
bzhpQQ1159968733 在[ c ]节点
czhpQQ1159968733 在[ b ]节点
dzhpQQ1159968733 在[ a ]节点
ezhpQQ1159968733 在[ b ]节点
fzhpQQ1159968733 在[ c ]节点
gzhpQQ1159968733 在[ b ]节点
hzhpQQ1159968733 在[ a ]节点
izhpQQ1159968733 在[ d ]节点
jzhpQQ1159968733 在[ a ]节点
kzhpQQ1159968733 在[ b ]节点
lzhpQQ1159968733 在[ a ]节点
mzhpQQ1159968733 在[ d ]节点
nzhpQQ1159968733 在[ c ]节点
ozhpQQ1159968733 在[ b ]节点
pzhpQQ1159968733 在[ a ]节点
qzhpQQ1159968733 在[ b ]节点
rzhpQQ1159968733 在[ c ]节点
szhpQQ1159968733 在[ b ]节点
tzhpQQ1159968733 在[ a ]节点
uzhpQQ1159968733 在[ b ]节点
vzhpQQ1159968733 在[ c ]节点
wzhpQQ1159968733 在[ b ]节点
xzhpQQ1159968733 在[ a ]节点
yzhpQQ1159968733 在[ b ]节点
zzhpQQ1159968733 在[ c ]节点

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:

https://course.0voice.com/v1/course/intro?courseId=5&agentId=0

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值