一个概念我觉得首先要明确到底是为了解决什么问题,github 上 readme 写的特点是 cache 命中和吞吐超过 redis 和 memcached ,如果在同基准下能做到就已经很好了,可以详细说说这个是怎么做的。
但这篇文章的一致性问题
站在大的架构概念上考虑,这已经不是一个纯粹的缓存服务了,更像是一个分布式锁,或者说都不是分布式锁,而是数据库锁的外置版本。使用它有非常重的架构成本,不是直接引入就好的,举几个例子
1. 你的逻辑会直接依赖于数据库的隔离级别,你的更新写入依赖于数据库的事务,写入的 key 按你上面说的是先 select for update 查出来的,就不提你这样可能查出一大堆的数据直接打爆应用,数据库在 rr 和 rc 的隔离级别下锁住的范围都不是一致的,这里就已经可能出现冲突了。
2. 你需要业务强依赖缓存组件,本来增加缓存是为了给数据库增加容错,缓存挂了降级到数据库也能撑一会,现在缓存一挂服务直接不可用这不可以接受
3. 如果你的缓存仅有 kv 写入,而且也没有过期的能力,业务为了这个功能引入这个组件的目的是什么
站小的细节考虑,锁有很多问题需要考虑,redis 最有名的锁应该是 redlock 吧,但它的一致性仍有非常多的讨论,可以参看
https://zhangtielei.com/posts/blog-redlock-reasoning.html我没翻源码,仅从文章上说几个点
1. 如果你想维持完美的一致性,那缓存读锁的时间是组件决定还是业务决定,太长影响 set 失败后的自然过期,太短数据库的查询又可能超时。
2. 更新后,你有一步是删除 key ,如果一个连接超时,客户端拿到的是超时的结果,你是会重试还是事务直接结束,如果结束已经更新的 key 要不要回滚,如果重试,那之前的连接发送的 delete 在组件里可能已经成功了,现在是另一个连接拿到了这个 key 的锁,之前的连接重试能不能直接删除这个 key ?
3. 集群的方案没有那么简单的,就算用 raft ,你可以解决选主的问题,那主从直接的同步是怎么做的,是写入的时候全部节点成功才算成功?异常节点重启后怎么恢复缓存,什么时候才能认为缓存已经和集群同步可以加入集群?如果集群全挂了重启怎么办?