GroupCache架构

节点管理

groupcache 是一个支持多节点部署的 K-V cache。当有多个存储节点时,内部会以 consistent hash(一致性哈希)的方式管理多个节点。通过一致性哈希,可以统一管理多个节点。如果哈希算法设计得比较好,可以把大量 K-V 数据均匀打散,存储到不同的节点上。

group(存储组)

在 groupcache 里,group 是一个相对独立的存储容器,每个 group 都有自己的名字,多个 group 之间不共享数据。然而 group 只是一个逻辑概念,一个 group 里存的 K-V 数据是可以存在多个分散的物理节点上的(分散的策略依赖于一致性哈希算法)。也就是说每个物理节点上实际上存了多个 group 的 K-V 数据,组与组之间的访问隔离全靠 groupcache 的代码逻辑来实现。

缓存系统

LRU

在缓存系统的底层,每个 K-V Entry 都是通过一条 LRU 链表来管理的。经常被访问的数据会被放置在 LRU 链表的前端,久而久之冷数据会下沉到链表尾端,甚至直接被移出链表。

并发查询优化

在 groupcache 中,如果某节点同时收到 N 个对于同一个 key 的查询请求,但是请求的 key 不在当前节点上,groupcache 会自动阻塞 N-1 个请求,只执行其中一个请求,去其他节点或者数据库中 fetch 数据。最后才恢复 N 个请求,把数据放到 N 个请求中返回。因为无论多少个对同一个 key 的查询请求并发到达,只执行一次查询,所以并发查询效率很高。

热门缓存自动镜像

每个节点都包含了两类缓存:main cache(属于本节点的数据)和 hot cache(不属于本节点但是全局热门的数据)。当节点收到了对某个 key 的查询请求,它首先会检查本地 hot cache 中有没有,如果没有就再看看该 key 是不是属于本节点的数据,如果不是就向兄弟节点请求。所谓的自动镜像,指的是从兄弟节点处返回的数据可以缓存在本节点的 hot cache 里,虽然自身没有那个数据的存储权限,但是可以存储成一份热门数据的镜像,以后再收到对该 key 的请求,无需再向兄弟节点请求,浪费网络资源。

groupcache代码模块

GroupCache 的源码结构比较简单,一共就五个文件夹外加五个单独的文件,具体目录结构如下:

01_GroupCache源码结构.png

consistenthash

consistenthash 模块实现了简单的一致性哈希算法。数据(一般是节点地址)进入一致性哈希后,会被自动冗余得到多个备份(取决于 replica 的设定值),然后插到一致性哈希环上。

groupcachepb

groupcachepb 模块里,用了第三方库 protobuf 生成了统一的 Request 和 Response 结构,供节点间网络通信使用。

lru

lru 模块实现了经典的 LRU 算法,用 container/list 里的链表实现。

singleflight

singleflight 模块非常重要。正如它名字里的 single,它是用来保证多个对同一个 key 的请求不被多次执行的。也就是上面简介所说的并发查询优化。

testpb

testpb,测试 protobuf 结构。

byteview

byteview 是一个对 byte 数组或者字符串的封装,在外部看来,groupcache 里的所有 K-V 数据最终都是落盘到 byte 上,都是对 byteview 的读写操作。

groupcache

核心代码文件,其中定义了 Group、GetterFunc、Stats 等多个关键数据结构,以及对应的方法。

http

核心代码文件,定义了 HTTPPool 以及对应的方法,包含了各种网络通信的逻辑。

peers

定义了节点的相关操作。

sinks

sinks 里定义了 Sink 接口以及多种不同的 sink。其实 sink 可以理解为一种特殊容器,当节点收到对某个 key 的查询请求,但是本地没有数据,需要到远程数据库里读取时,会把读取回来的数据下沉到 sink 容器里面,最后再把数据转成 byteview 塞到本地缓存里。