vRp.CD2g_test/toolkit/loadbalancer/consistent_hash.go

81 lines
1.8 KiB
Go

package loadbalancer
import (
"github.com/kercylan98/minotaur/utils/super"
"hash/fnv"
"sort"
"sync"
)
func NewConsistentHash(replicas int) *ConsistentHash {
return &ConsistentHash{
replicas: replicas,
keys: []int{},
hashMap: make(map[int]string),
mutex: sync.RWMutex{},
}
}
type ConsistentHash struct {
replicas int // 虚拟节点倍数
keys []int // 哈希环上的所有节点的哈希值
hashMap map[int]string // 哈希值到真实节点的映射
mutex sync.RWMutex // 用于保护数据结构
}
// Add 添加一个节点到哈希环
func (c *ConsistentHash) Add(node string) {
c.mutex.Lock()
defer c.mutex.Unlock()
for i := 0; i < c.replicas; i++ {
hash := c.hash(node + super.IntToString(i))
c.keys = append(c.keys, hash)
c.hashMap[hash] = node
}
sort.Ints(c.keys)
}
// Remove 从哈希环中移除一个节点
func (c *ConsistentHash) Remove(node string) {
c.mutex.Lock()
defer c.mutex.Unlock()
for i := 0; i < c.replicas; i++ {
hash := c.hash(node + super.IntToString(i))
delete(c.hashMap, hash)
// 从 keys 中移除节点的哈希值
for j, k := range c.keys {
if k == hash {
c.keys = append(c.keys[:j], c.keys[j+1:]...)
break
}
}
}
}
// Get 返回给定 key 所在的节点
func (c *ConsistentHash) Get(key string) string {
c.mutex.RLock()
defer c.mutex.RUnlock()
if len(c.keys) == 0 {
return ""
}
hash := c.hash(key)
// 顺时针找到第一个比 key 大的哈希值,即对应的节点
idx := sort.Search(len(c.keys), func(i int) bool { return c.keys[i] >= hash })
if idx == len(c.keys) {
idx = 0 // 如果 key 大于所有哈希值,则返回第一个节点
}
return c.hashMap[c.keys[idx]]
}
// hash 计算字符串的哈希值
func (c *ConsistentHash) hash(key string) int {
h := fnv.New32a()
_, _ = h.Write([]byte(key))
return int(h.Sum32())
}