7天用Go实现分布式缓存
本文是学习自https://geektutu.com/post/geecache.html
在此基础上,加入自己的学习过程与理解。
谈谈分布式缓存
第一次请求时将一些耗时操作的结果暂存,以后遇到相同的请求,直接返回暂存的数据。通过这个例子应该比较好理解什么是缓存。
在计算机系统中,缓存无处不在。比如微博的点赞的数量,不可能每个人每次访问,都从数据库中查找所有点赞的记录再统计,数据库的操作是很耗时的,很难支持那么大的流量,所以一般点赞这类数据是缓存在 Redis 服务集群中的。
缓存中最简单的莫过于存储在内存中的键值对缓存了。说到键值对,很容易想到的是字典(dict)类型,Go 语言中是map。很容易想到,直接创建一个 map,每次有新数据就往 map 中插入,这不就是键值对缓存么?但这样做有什么问题呢?
1)内存不够了怎么办?
那肯定是想着删掉一些已存在的数据。那通过什么策略去淘汰呢?我们需要实现一个合理的淘汰策略。
2)并发写入冲突了怎么办?
对缓存的访问,一般不可能是串行的。Go中map 是没有并发保护的,应对并发的场景,修改操作(包括新增,更新和删除)需要加锁。(sync.map是支持并发安全的)
3)单机性能不够怎么办?
单台计算机的资源是有限的,计算、存储等都是有限的。随着业务量和访问量的增加,单台机器很容易遇到瓶颈。如果利用多台计算机的资源,并行处理提高性能就要缓存应用能够支持分布式,这称为水平扩展(scale horizontally)。与水平扩展相对应的是垂直扩展(scale vertically),即通过增加单个节点的计算、存储、带宽等,来提高系统的性能,硬件的成本和性能并非呈线性关系,大部分情况下,分布式系统是一个更优的选择。
4)…
如何设计
按照前面的想法,设计一个分布式缓存系统,需要考虑资源控制、淘汰策略、并发、分布式节点通信等各个方面的问题。
原教程的分布式缓存是模仿了groupcache的实现。
每个版本的讲解
cache教程1.LRU 缓存淘汰策略
cache教程 2.单机并发缓存
完整代码:https://github.com/liwook/Go-projects/tree/main/go-cache