设计艺术~缓存结构设计
背景
面对高QPS场景的业务,不得不考虑对一些数据做缓存设计,常见的缓存设计有这些:DB Proxy缓存、分布式缓存、Localcache缓存。
在考虑加缓存的背景下不考虑数据的一致性,都是瞎扯,所以我们再定义一下数据的一致性场景:强制一致性、最终一致性。本质上只要加了缓存就会破坏数据的一致性,最起码破坏了数据的强一致性。但在不同的缓存选择下,最终一致性的延迟效果是完全不同的。
DB Proxy缓存
DB proxy 缓存是比较简单的一种缓存,它的拓展性和策略手段也偏少,基本上只能做某 key 某 SQL 超过一定 QPS 之后,做一些结果缓存。缓存时间可以设置个1秒、2秒、3秒,按照你的业务需求去做决定。但本质上它的策略手段因为太单一,你也没有办法去做一些强制的删除或强制的更新。所以优势就在于简单,纯配置就可以。劣势就在于策略手段太过单一,维护热 key 缓存的 key 的手段太过单一。而且 DB proxy 缓存一般也不能承担太多的缓存任务,只有一些非常非常高的 key 比如说一些 key 的 QPS 超过了20K 30K 才会考虑对着一个 k 去开启。而且是得手动针对某一个 key 去开启,最好不要全局去开启,避免一些不必要的问题。
分布式缓存
分布式缓存应该是最常用的,最熟悉的应该就是 Redis 它可以把 DB 的一些查询结果做一些缓存。效果策略手段也是最好的。我们可以做一些策略化的过期时间,可以针对某一个 key 或者批量针对某一批 key 去做缓存,由业务代码去设定,灵活性更好。缺点的话就在于它对于超高的 QPS 的 key 这个超高怎么定义呢?就从 Redis 的单 key 的承载能力去做定义。一个 key 如果超过了5000QPS 也就是5K 多流量,可以认为是热 key 那超过10K 也就是1万的 QPS 那基本上就靠 Redis 去缓存,也是不可靠的,会引起单分片的 CPU 问题。靠分布式缓存就不太好解决了。
Localcache缓存
对于前面提到的,如果某一个 key 超过了10K 的 QPS 就需要考虑去做 local cache 本地缓存。本地缓存优势就在于它可以本地区直接返回结果,对吞吐量、响应的效率、速度都有非常好的支持。但它的缺陷就在于维护成本太高。因为它会消耗机器的实际内存,我们内存资源是非常宝贵的,所以一般 local CACHE 会有一个内存上限,也会有很多的淘汰算法。再一个就是使用分布式缓存的话,因为它是分布式的,你可以去做一些强制更新,缓存更新。我们常见的延迟双删这些技术点,都是为了保证一致性。但 local CACHE 的话,它就不太好去做这些事情了。也就是说,local CACHE 缓存的 key 它没有办法去全量的删除,在它过期时间之前。这也是它的一个缺点。
选型
所以选型的话,如果一个数据是超高 QPS 超过了10K 甚至以上,并且你认为它的一致性还好,就比如是一些点赞的数值啊。直播间人数啊这些完全可以考虑去通过 local cache 去做承载,但要设置好缓存这个 key 的条件和过期时间以及淘汰策略。避免因为 local CACHE 导致整个机器的内存使用消耗太高。最常用的,最实用的应该就是分布式缓存。它可以做一些像延迟双删这样的一些技术手段,去保证一致性,也可以使用一些很多的算法去策略手段去做缓存,比如把时间打散,比如说某一个 key 去设置5秒还是3秒过期,由业务代码去决定,灵活性是最好的。DB proxy 缓存的话就比较的简单,可以为了在发现某一个 key 对机器产生影响了之后,主动的为这个 key 开启缓存来,算是一个运维能力去保护 DB也就是说,得你主动的去发现某 key 特别超高。然后去开启。