Skip to content

Commit

Permalink
✨ feat: Day4 一致性哈希
Browse files Browse the repository at this point in the history
  • Loading branch information
p3ddd committed Apr 6, 2022
1 parent ba5ce58 commit 49d5fc2
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
39 changes: 37 additions & 2 deletions consistenthash/consistenthash.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package consistenthash

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

type Hash func(data []byte) uint32

// Map constains all hashed keys
type Map struct {
hash Hash
replicas int //虚拟节点倍数
replicas int // 虚拟节点倍数
keys []int // 哈希环
hashMap map[int]string // 虚拟节点与真实节点的映射表,键是哈希值,值是真实节点的名称
}
Expand All @@ -22,3 +28,32 @@ func New(replicas int, fn Hash) *Map {
}
return m
}

// Add adds some keys to the hash.
// 传入真实节点名称
func (m *Map) Add(keys ...string) {
for _, key := range keys {
for i := 0; i < m.replicas; i++ {
hash := int(m.hash([]byte(strconv.Itoa(i) + key)))
fmt.Printf("key: %v, i: %v, hash: %v\n", key, i, hash)
m.keys = append(m.keys, hash)
m.hashMap[hash] = key
}
}
sort.Ints(m.keys)
}

func(m *Map) Get(key string) string {
if len(m.keys) == 0 {
return ""
}

// 计算 key 的哈希值
hash := int(m.hash([]byte(key)))
// 顺时针找到第一个匹配的虚拟节点的下标 idx,从 m.keys 中获取对应的哈希值
idx := sort.Search(len(m.keys), func(i int) bool {
return m.keys[i] >= hash
})
// 得到真实节点
return m.hashMap[m.keys[idx%len(m.keys)]]
}
53 changes: 53 additions & 0 deletions consistenthash/consistenthash_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package consistenthash

import (
"strconv"
"testing"
)

func TestHashing(t *testing.T) {
hash := New(3, func(key []byte) uint32 {
i, _ := strconv.Atoi(string(key))
return uint32(i)
})

// 哈希值: 2, 4, 6, 12, 14, 16, 22, 24, 26
hash.Add("6", "4", "2")
// fmt.Printf("%+v\n", hash)
// &{hash:0x77f740 replicas:3
// keys:[2 4 6 12 14 16 22 24 26]
// hashMap:map[2:2 4:4 6:6 12:2 14:4 16:6 22:2 24:4 26:6]}

testCases := map[string]string{
"2": "2",
"11": "2",
"23": "4",
"27": "2",
}

for k, v := range testCases {
if hash.Get(k) != v {
t.Errorf("Asking for %s, should have yielded %s", k, v)
}
}

hash.Add("8")
// fmt.Printf("%+v\n", hash)
// &{hash:0x5af740 replicas:3
// keys:[2 4 6 8 12 14 16 18 22 24 26 28]
// hashMap:map[2:2 4:4 6:6 8:8 12:2 14:4 16:6 18:8 22:2 24:4 26:6 28:8]}

testCases["27"] = "8"

for k, v := range testCases {
if hash.Get(k) != v {
t.Errorf("Asking for %s, should have yielded %s", k, v)
}
}

// hash.Add("9", "10", "11", "12", "233")
// fmt.Printf("%+v\n", hash)
// &{hash:0xf1f740 replicas:3
// keys:[2 4 6 8 9 10 11 12 12 14 16 18 19 22 24 26 28 29 110 111 112 210 211 212]
// hashMap:map[2:2 4:4 6:6 8:8 9:9 10:10 11:11 12:12 14:4 16:6 18:8 19:9 22:2 24:4 26:6 28:8 29:9 110:10 111:11 112:12 210:10 211:11 212:12]}
}

0 comments on commit 49d5fc2

Please sign in to comment.