多级缓存架构在消息系统中的应用

下面是谷歌的技术奠基人杰夫·狄恩(Jeff Dean)给出的一些计算机相关的硬件指标,虽然有些数据可能由于时间太久不够准确,但大致的量级基本还是一致的。

  1. L1 cache reference 0.5 ns
  2. Branch mispredict 5 ns
  3. L2 cache reference 7 ns
  4. Mutex lock/unlock 100 ns
  5. Main memory reference 100 ns
  6. Compress 1K bytes with Zippy 10,000 ns
  7. Send 2K bytes over 1 Gbps network 20,000 ns
  8. Read 1 MB sequentially from memory 250,000 ns
  9. Round trip within same datacenter 500,000 ns
  10. Disk seek 10,000,000 ns
  11. Read 1 MB sequentially from network 10,000,000 ns
  12. Read 1 MB sequentially from disk 30,000,000 ns
  13. Send packet CA->Netherlands->CA 150,000,000 ns

使用缓存虽然能够给我们带来诸多性能上的收益,但存在一个问题是缓存的资源成本非常高。因此,在 IM 系统中对于缓存的使用,就需要我们左右互搏地在“缓存命中率”和“缓存使用量”两大指标间不断均衡。

 

缓存的分布式算法

取模求余

如下图所示:如果消息 ID 哈希后对缓存节点取模求余,余数是多少,就缓存到哪个节点上。

多级缓存架构在消息系统中的应用

 

取模求余的分布式算法在实现上非常简单。但存在的问题是:如果某一个节点宕机或者加入新的节点,节点数量发生变化后,Hash 后取模求余的结果就可能和以前不一样了。由此导致的后果是:加减节点后,缓存命中率下降严重。

一致性哈希

多级缓存架构在消息系统中的应用

 

数据倾斜

为了解决物理节点少导致节点间数据倾斜的问题,我们还可以引入虚拟节点,来人为地创造更多缓存节点,以此让数据分布更加均匀。

多级缓存架构在消息系统中的应用

 

我们为每一个物理节点分配多个虚拟节点,比如在上图这里,给节点 1 虚拟出 4 个节点。当消息进行缓存哈希定位时,如果落到了这个物理节点上的任意一个虚拟节点,那么就表示,真正的缓存存储位置在这个物理节点上,然后服务端就可以从这个物理节点上进行数据的读写了。

缓存热点问题

多级缓存架构 - 主从模式

为了防止文章下载阅读出现热点时,造成后端存储服务的压力太大,我们一般会通过缓存来进行下载时的加速。比如说,我们可以通过文章的唯一 ID 来进行哈希,并且通过缓存的一主多从模式来进行部署,主从模式的部署大概如下图:

 

多级缓存架构在消息系统中的应用

 

多级缓存架构 -L1+ 主从模式

我们来看一下,L1+ 主从模式的部署和访问形式:

 

多级缓存架构在消息系统中的应用

 

L1 缓存作为最前端的缓存层,在用户请求的时候,会先从 L1 缓存进行查询。如果 L1 缓存中没有,再从主从缓存里查询,查询到的结果也会回种一份到 L1 缓存中。

与主从缓存模式不一样的地方是:L1 缓存有分组的概念,一组 L1 可以有多个节点,每一组 L1 缓存都是一份全量的热数据,一个系统可以提供多组 L1 缓存,同一个数据的请求会轮流落到每一组 L1 里面。

多级缓存架构 - 本地缓存 +L1+ 主从的多层模式

对于大部分请求量较大的应用来说,应用层机器的部署一般不会太少。如果我们的应用服务器本身也能够承担一部分数据缓存的工作,就能充分利用应用层机器的带宽和极少的内存,来低成本地解决带宽问题了

 

多级缓存架构在消息系统中的应用