Skip to content

Commit

Permalink
解读一致性hash算法
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] committed May 25, 2020
1 parent 750c018 commit b6462a5
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 3 deletions.
Binary file added 2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions ReadMe_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

### 功能介绍
groupcache是go语言开发的缓存库。用于替换memcache的。
#### 系统框架
![](./2.png)


#### 代码框架
![](./1.png)



### 使用入门
```shell
cd example
Expand All @@ -19,13 +25,31 @@ curl localhost:8080/color?name=red

```

### 源码目录
```shell script
.
├── byteview.go
├── byteview_test.go
├── consistenthash // 实现一致性hash功能
├── groupcache.go // grpc生成的代码,用于远程调用
├── groupcachepb // grpc生成的代码,用于远程调用
├── http.go // http相关的代码
├── lru // 实现缓存的置换算法(最近最少使用)
├── peers.go // 单个节点的一些接口实现
├── singleflight // 实现多个同请求的合并,保证“同时”多个同参数的get请求只执行一次操作功能
├── sinks.go
└── testpb

```

### 分析目的
+ consistenthash(提供一致性哈希算法的支持),
+ lru(提供了LRU方式清楚缓存的算法),
+ singleflight(保证了多次相同请求只去获取值一次,减少了资源消耗),
https://segmentfault.com/a/1190000018464029

### 参考资料
+ [《groupcache 设计原理剖析 》](https://www.dazhuanlan.com/2019/12/11/5df07fcb62cae/?__cf_chl_jschl_tk__=e5a47b230d1b9d89eb3887cab036b09f2e3ea621-1590370196-0-AYcPFk14NmbUvag0bCwvLEwPGpXssbJuZhDvEpan7iZiKQi123FXqUvH-LsRSQaov7ybpQtzh-615A-1ZEDC54TuWv_6ZTwsr3zoEwubtJbUbw2J8PTOnzfviGoQB4UWA9Y1ZVzP5QLQ2BCSNlSYxDlegJsosJAV1xJQf06FNkbXPBEAh0SCE29OAzUhpZx1qOKfiUjkI1NNltnexAUoGKVMymm9ocKiWwcq4y_CnUX3xNGz6wyOTmUjQ0RrS1qcQDN8Z-0Jrzn9z1VbzCbEc8R-bdwdkzo7hqaHZ3goA0AQMpxVWxzRjbsy4YIf7vHWEg)
+ [《GROUPCACHE EXAMPLE》](https://sconedocs.github.io/groupcacheUseCase/)
+ [Playing with groupcache](https://capotej.com/blog/2013/07/28/playing-with-groupcache/)

Expand Down
23 changes: 20 additions & 3 deletions consistenthash/consistenthash.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ import (
"strconv"
)

// Hash函数
type Hash func(data []byte) uint32

type Map struct {
hash Hash
replicas int
keys []int // Sorted
hashMap map[int]string
replicas int // 每个key的副本数量
keys []int // Sorted,key为哈希环上面的一个点(节点哈希值)
// hashMap表的key是一个表示cache服务器或者副本的hash值,value为一个具体的cache服务器,
// 这样就完成了Cache A、Cache A1、Cache A2等副本全部映射到Cache A的功能。
hashMap map[int]string // 哈希环上面的一个点到服务器名的映射
}

func New(replicas int, fn Hash) *Map {
Expand All @@ -39,6 +42,7 @@ func New(replicas int, fn Hash) *Map {
hashMap: make(map[int]string),
}
if m.hash == nil {
// 默认的hash函数
m.hash = crc32.ChecksumIEEE
}
return m
Expand All @@ -50,32 +54,45 @@ func (m *Map) IsEmpty() bool {
}

// Add adds some keys to the hash.
// 将缓存服务器加到Map中,比如Cache A、Cache B作为keys,
// 如果副本数指定的是2,那么Map中存的数据是Cache A#1、Cache A#2、Cache B#1、Cache B#2的hash结果
// keys类似"host1","host2"等,表示cache服务器
func (m *Map) Add(keys ...string) {
for _, key := range keys {
// 内循环实现副本数量要求
for i := 0; i < m.replicas; i++ {
// key和数字编号一起计算哈希
hash := int(m.hash([]byte(strconv.Itoa(i) + key)))
// 哈希值存入切片
m.keys = append(m.keys, hash)
// 哈希值和服务器名字的对应关系
m.hashMap[hash] = key
}
}

// 从小到大排序
sort.Ints(m.keys)
}

// Get gets the closest item in the hash to the provided key.
// 如果有一个key要保存到某个cache服务器,Get函数返回对应的cache服务器。
func (m *Map) Get(key string) string {
if m.IsEmpty() {
return ""
}

// 计算哈希值
hash := int(m.hash([]byte(key)))

// Binary search for appropriate replica.
// 查找m.keys[i] >= hash成立的最小值i,i前面的元素都不满足>hash
idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash })

// Means we have cycled back to the first replica.
if idx == len(m.keys) {
idx = 0
}

// 返回对应的服务器信息
return m.hashMap[m.keys[idx]]
}

0 comments on commit b6462a5

Please sign in to comment.