7days-golang分布式缓存GeeCache:如何模仿groupcache在7天实现一个分布式缓存系统
【免费下载链接】7days-golang7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列项目地址: https://gitcode.com/gh_mirrors/7d/7days-golang
在7days-golang项目中,作者模仿 Google 开源库 groupcache 的设计,用「7 天、每天约 100 行 Go 代码」的搭积木方式,带你从零动手实现一个完整的GeeCache 分布式缓存系统:从 LRU 淘汰策略、并发安全,到一致性哈希多节点、singleflight 防击穿、Protobuf 通信,每一天的代码都能独立运行和测试。🧱
一、为什么值得自己动手写分布式缓存
「缓存为王」是架构圈的共识:微博点赞数不可能每次访问都查库统计,网页静态资源要靠浏览器和 CDN 缓存加速。但一个真正的缓存系统远不止「往 map 里塞数据」这么简单,至少要回答四个问题 🤔:
- 内存不够了淘汰谁?需要合理的淘汰策略(FIFO / LFU / LRU);
- 并发读写冲突了怎么办?内存缓存必须有并发保护;
- 单机扛不住了怎么扩?需要多节点水平扩展,即分布式;
- 热点 key 被同时击穿怎么办?需要限流合并同类请求。
GeeCache把 groupcache(约 3000 行)裁剪到 500 行左右,却保留了分布式缓存最核心的骨架,是学习 Go 并发与分布式系统的绝佳素材。
二、7天路线图:每天一块「积木」
整个实现分布在 gee-cache/ 目录下,每个day*目录都是一个可独立编译运行的模块。
Day 1|LRU 缓存淘汰策略
对比了先进先出(FIFO)、最少使用(LFU)、最近最少使用(LRU)三种算法后,选择相对平衡的LRU:用「哈希字典 + 双向链表」实现,查找、访问、淘汰都是O(1)。核心代码见 lru.go。
Day 2|单机并发缓存
用sync.Mutex互斥锁给 LRU 加并发保护,并抽出 GeeCache 的核心结构Group:它像一个缓存命名空间,缓存未命中时会调用用户提供的回调函数Getter从数据源取数。流程是:
接收 key → 命中缓存?→ 直接返回;未命中 → 调回调取源数据 → 写入缓存 → 返回
关键文件:并发封装 cache.go、主体结构与回调 geecache.go。
Day 3|HTTP 服务端
借助 Go 标准库net/http,每个缓存节点对外暴露http://host:port/<group>/<key>这样的 HTTP 接口,其他节点就能像调用服务一样读取本机缓存,为多节点通信铺路。代码约 60 行,见 http.go。
Day 4|一致性哈希:数据该放哪个节点?
节点变多后,「key 该找谁」就成了难题。简单取余hash(key) % N在节点增减时会让几乎所有 key 重新分布,瞬间引发缓存雪崩;而一致性哈希把节点和 key 映射到一个环上,增删节点只影响环上邻近的一小段 key。再引入虚拟节点解决节点少导致的数据倾斜问题。实现仅约 60 行:consistenthash.go。
Day 5|分布式节点:真正「联」起来
抽象出PeerPicker(按 key 选节点)与PeerGetter(向节点取值)两个接口,HTTPPool借助一致性哈希选出目标节点,再用 HTTP 客户端去拉取数据;选到的是自己则回退本地处理。这是 GeeCache 从单机走向分布式的临门一脚:peers.go、http.go。
Day 6|singleflight:防止缓存击穿
并发请求同一个未命中 key 时,会瞬间向数据源发起 N 次重复取数——这就是缓存击穿。GeeCache 实现了一个约 70 行的 singleflight.go:同一时刻相同 key 只放行一个「领航」请求,其余请求等待并共享其结果。
Day 7|Protobuf 通信:给节点间通信提速
节点间改用 Google 的 Protobuf 编码报文:二进制体积小、跨语言、字段可扩展。只需一个 geecachepb.proto 定义Request/Response并用protoc生成 Go 代码即可,约 50 行改动完成升级。
三、3分钟跑起来 🚀
最终版(day7)自带演示:启动 3 个缓存节点(8001/8002/8003)加 1 个 API 前端(9999),并发 3 个相同请求,可以直观看到「一致性哈希选中同一节点 + singleflight 只回源一次」的效果:
- 演示入口:main.go
- 一键运行脚本:run.sh(执行
bash gee-cache/day7-proto-buf/run.sh即可)
如果想亲手体验从零到一的完整过程,可以按day1-lru→day7-proto-buf的顺序,每天go test验证一遍,感受每一块「积木」如何咬合。
四、文件导读
| 内容 | 路径 |
|---|---|
| 系列总览(含特性与目录) | geecache.md |
| 7天逐日教程文档 | geecache-day1.md ~ geecache-day7.md |
| LRU 淘汰策略源码 | lru.go |
| Group 核心结构 | geecache.go |
| 一致性哈希实现 | consistenthash.go |
| 节点注册与 HTTP 客户端 | peers.go |
| singleflight 防击穿 | singleflight.go |
| Protobuf 报文定义 | geecachepb.proto |
7days-golang 是一个「7 天从零实现」系列,除 GeeCache 外还有 Web 框架 gee-web/、ORM 框架 gee-orm/、RPC 框架 gee-rpc/ 等,每个都按同样的节奏逐日拆解,非常适合 Go 新手系统性进阶。✨
五、小结
GeeCache 证明了:分布式缓存没有想象中神秘。LRU 解决淘汰、互斥锁解决并发、HTTP 解决跨进程、一致性哈希解决分片、singleflight 解决击穿、Protobuf 解决传输效率——每天解决一个问题,七天拼出一个完整系统。跟着这份 500 行的极简实现读下来,你对缓存与分布式系统的理解,会胜过读十篇概念文章。
【免费下载链接】7days-golang7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列项目地址: https://gitcode.com/gh_mirrors/7d/7days-golang
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考