diff --git a/2.png b/2.png new file mode 100644 index 0000000..fa4ec03 Binary files /dev/null and b/2.png differ diff --git a/ReadMe_CN.md b/ReadMe_CN.md index 1902405..ff3ff41 100644 --- a/ReadMe_CN.md +++ b/ReadMe_CN.md @@ -2,9 +2,15 @@ ### 功能介绍 groupcache是go语言开发的缓存库。用于替换memcache的。 +#### 系统框架 +![](./2.png) + + #### 代码框架 ![](./1.png) + + ### 使用入门 ```shell cd example @@ -19,6 +25,23 @@ 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方式清楚缓存的算法), @@ -26,6 +49,7 @@ curl localhost:8080/color?name=red 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/) diff --git a/consistenthash/consistenthash.go b/consistenthash/consistenthash.go index da13909..728bddb 100644 --- a/consistenthash/consistenthash.go +++ b/consistenthash/consistenthash.go @@ -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 { @@ -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 @@ -50,26 +54,38 @@ 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. @@ -77,5 +93,6 @@ func (m *Map) Get(key string) string { idx = 0 } + // 返回对应的服务器信息 return m.hashMap[m.keys[idx]] }