曂沅仴駦 发表于 2024-8-27 21:12:20

17 | Cache:多级缓存架构在消息系统中的应用

今天,要带你了解的是一项在 IM 系统中相对比较通用的、利用比较高频的,而且对系统性能提拔非常明显的技能:缓存。
说到缓存,你应该不陌生。相对于磁盘操作,基于内存的缓存对耗时敏感的高并发应用来说,在性能方面的提拔黑白常明显的。
下面是谷歌的技能奠基人杰夫·狄恩(Jeff Dean)给出的一些盘算机相关的硬件指标,固然有些数据可能由于时间太久不够正确,但大抵的量级基本还是同等的。
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns
Mutex lock/unlock 100 ns
Main memory reference 100 ns
Compress 1K bytes with Zippy 10,000 ns
Send 2K bytes over 1 Gbps network 20,000 ns
Read 1 MB sequentially from memory 250,000 ns
Round trip within same datacenter 500,000 ns
Disk seek 10,000,000 ns
Read 1 MB sequentially from network 10,000,000 ns
Read 1 MB sequentially from disk 30,000,000 ns
Send packet CA->Netherlands->CA 150,000,000 ns
可以看到,同样是 1MB 的数据读取,从磁盘读取的耗时,比从内存读取的耗时相差近 100 倍,这也是为什么业界常说“处理高并发的三板斧是缓存、降级和限流”了。
利用缓存固然能够给我们带来诸多性能上的收益,但存在一个问题是缓存的资源成本非常高。因此,在 IM 系统中对于缓存的利用,就必要我们左右互搏地在“缓存掷中率”和“缓存利用量”两大指标间不断均衡。
在今天的课程中,会围绕 IM 系统中缓存的利用,来聊一聊在利用过程中轻易遇到的一些问题及相应的办理方案。
缓存的分布式算法

对于大规模分布式服务来说,大部分缓存的利用都是多实例分布式部署的。接下来,我们就先来了解一下缓存常见的两种分布式算法:取模求余与同等性哈希。
取模求余

取模求余的算法比较简单。比如说,用于存储消息内容的缓存,如果采用取模求余,就可以简单地利用消息 ID 对缓存实例的数量举行取模求余。
如下图所示:如果消息 ID 哈希后对缓存节点取模求余,余数是多少,就缓存到哪个节点上。
https://i-blog.csdnimg.cn/blog_migrate/b5395dc533db676bb3d63050ce021aa6.png
取模求余的分布式算法在实现上非常简单。但存在的问题是:如果某一个节点宕机或者参加新的节点,节点数量发生变化后,Hash 后取模求余的结果就可能和从前不一样了。由此导致的结果是:加减节点后,缓存掷中率降落严重。
同等性哈希

为了办理这个问题,业界常用的另一种缓存分布式算法是同等性哈希。它是 1997 年麻省理工学院提出的一种算法,现在主要应用在分布式缓存场景中。
同等性哈希的算法是:把全量的缓存空间分成 2 的 32 次方个区域,这些区域组合成一个环形的存储结构;每一个缓存的消息 ID,都可以通过哈希算法,转化为一个 32 位的二进制数,也就是对应这 2 的 32 次方个缓存区域中的某一个;缓存的节点也遵循同样的哈希算法(比如利用节点的 IP 来哈希),这些缓存节点也都能被映射到 2 的 32 次方个区域中的某一个。
那么,怎样让消息 ID 和具体的缓存节点对应起来呢?
很简单,每一个映射完的消息 ID,我们按顺时针旋转,找到离它最近的同样映射完的缓存节点,该节点就是消息 ID 对应的缓存节点。大概规则画了一个图,可以参考一下:
https://i-blog.csdnimg.cn/blog_migrate/b247dedbd655f39003d99b1e10f563dc.png
那么,为什么同等性哈希能够办理取模求余算法下,加减节点带来的掷中率突降的问题呢?
结合上图,我们一起来看一下。假设已经存在了 4 个缓存节点,现在新增加一个节点 5,那么原来相应会落到节点 1 的 mid1 和 mid9,可能会由于节点 5 的参加,有的落入到节点 5,有的还是落入到节点 1;落入到新增的节点 5 的消息会被 miss 掉,但是仍然落到节点 1 的消息还是能掷中之前的缓存的。
另外,其他的节点 2、3、4 对应的这些消息还是能保持不变的,所以整体缓存的掷中率,相比取模取余算法波动会小很多。
同样,如果某一个节点宕机的话,同等性哈希也能保证,只会有小部分消息的缓存归属节点发生变化,大部分仍然能保持不变。
数据倾斜

同等性哈希既然办理了加减节点带来的掷中率降落的问题,那么是不是这种算法,就是缓存分布式算法的完美方案呢?
这里我们会发现,同等性哈希算法中,如果节点比较少,会轻易出现节点间数据不均衡的情况,发生数据倾斜;如果节点很多,相应的消息就能在多个节点上分布得更匀称。
但在实际的线上业务中,部署的缓存机器节点是很有限的。
所以,为了办理物理节点少导致节点间数据倾斜的问题,我们还可以引入虚拟节点,来人为地创造更多缓存节点,以此让数据分布更加匀称。
虚拟节点的大概实现过程,可以参考下图:
https://i-blog.csdnimg.cn/blog_migrate/118653578c4661d740e4e0a77f156e91.png
我们为每一个物理节点分配多个虚拟节点,比如在上图这里,给节点 1 虚拟出 4 个节点。当消息举行缓存哈希定位时,如果落到了这个物理节点上的恣意一个虚拟节点,那么就表现,真正的缓存存储位置在这个物理节点上,然后服务端就可以从这个物理节点上举行数据的读写了。
如上面这个例子,原来都落在节点 3 的 4 条消息 mid4、mid5、mid6、mid7,在参加节点 1 的虚拟节点后,mid4 和 mid5 落到了虚拟节点 1-2 上,如许 mid4 和 mid5 就被分配到物理节点 1 上了。可见,通过这种方式,能更好地打散数据的分布,办理节点间数据不平衡的问题。
缓存热点问题

通过同等性哈希共同虚拟节点,我们办理了节点快速扩容和宕机,导致掷中率降落的问题及节点间数据倾斜的问题。但在 IM 的一些场景里,还可能会出现单一资源热点的问题。
比如,一个超级大 V 给他的粉丝群发了一篇经心编写的长文章,可能一刹时服务端会有上万的文章阅读请求涌入。由于这些长文章都是作为富文本举行存储的,所以存储的数据较大,有的文章都超过 1MB,而且用户还必要随时能够修改文章,也欠好通过 CDN 来举行分发。
那么,我们怎样去办理这种缓存热点问题呢?
多级缓存架构 - 主从模式

以上面的“长文章流量热点”的例子来阐明一下。为了防止文章下载阅读出现热点时,造成后端存储服务的压力太大,我们一般会通过缓存来举行下载时的加速。比如说,我们可以通过文章的唯一 ID 来举行哈希,而且通过缓存的一主多从模式来举行部署,主从模式的部署大概如下图:
https://i-blog.csdnimg.cn/blog_migrate/0af84aeefb7d5e23677a5315306fae9c.png
一般来说,主从模式下,主库只用于数据写入和更新,从库只用于数据读取。当然,这个也不是肯定的。
比如,在写多读少的场景下,也可以让主库承担一部分的数据读取工作。当缓存的数据读取 QPS 比较大的情况下,可以通过增加从库的方式来提拔整体缓存层的抗读取能力。
主从模式是最常见的、利用最多的缓存应用模式。但是主从模式在某些突发流量的场景下会存在一些问题,就比如刚刚提到的“长文章流量热点”问题。
我们对某篇长文章的唯一 ID 来举行哈希,在主从模式下,一篇文章只会映射到一个从库节点上。固然能够通过增加从库副本数来提拔服务端对一篇文章的读取能力,但由于文章大小比较大,即使是多从库副本,对于千兆网卡的从库实例机器来说,带宽层面也很难抗住这个热点。举个例子,单台机器 120MB 带宽,对于 1MB 大小的文章来说,如果 QPS 到 1000 的话,至少必要 8 个实例才可以抗住。
另外,多从库副本是对主库数据的完备拷贝,从成本上思量也黑白常不划算的。除了带宽问题,对于某些 QPS 很高的资源请求来说,如果采用的是单主单从结构,一旦从库宕机,刹时会有大量请求直接穿透到 DB 存储层,可能直接会导致资源不可用。
多级缓存架构 -L1+ 主从模式

为了办理主从模式下,单点峰值过高导致单机带宽和热点数据在从库宕机后,造成后端资源瞬时压力的问题,我们可以参考 CPU 和主存的结构,在主从缓存结构前面再增加一层 L1 缓存层。
L1 缓存,顾名思义一般它的容量会比较小,用于缓存极热的数据。那么,为什么 L1 缓存可以办理主从模式下的带宽问题和穿透问题呢?
我们来看一下,L1+ 主从模式的部署和访问情势:
https://i-blog.csdnimg.cn/blog_migrate/70773b48de79ee8418d8a64d47305e3e.png
L1 缓存作为最前端的缓存层,在用户请求的时候,会先从 L1 缓存举行查询。如果 L1 缓存中没有,再从主从缓存里查询,查询到的结果也会回种一份到 L1 缓存中。
与主从缓存模式不一样的地方是:L1 缓存有分组的概念,一组 L1 可以有多个节点,每一组 L1 缓存都是一份全量的热数据,一个系统可以提供多组 L1 缓存,同一个数据的请求会轮番落到每一组 L1 内里。
比如同一个文章 ID,第一次请求会落到第一组 L1 缓存,第二次请求可能就落到第二组 L1 缓存。通过穿透后的回种,最后每一组 L1 缓存,都会缓存到同一篇文章。通过这种方式,同一篇文章就有多个 L1 缓存节点来抗读取的请求量了。
而且,L1 缓存一般采用 LRU(Least Recently Used)方式举行淘汰,如许既能淘汰 L1 缓存的内存利用量,也能保证热点数据不会被淘汰掉。而且,采用 L1+ 主从的双层模式,即使有某一层节点出现宕机的情况,也不会导致请求都穿透到后端存储上,导致资源出现问题。
多级缓存架构 - 本地缓存 +L1+ 主从的多层模式

通过 L1 缓存 + 主从缓存的双层架构,我们用较少的资源办理了热点峰值的带宽问题和单点穿透问题。
但有的时候,面对一些极热的热点峰值,我们可能必要增加多组 L1 才能抗住带宽的必要。不过内存毕竟是比较昂贵的成本,所以有没有更好的平衡极热峰值和缓存成本的方法呢?
对于大部分请求量较大的应用来说,应用层机器的部署一般不会太少。如果我们的应用服务器本身也能够承担一部分数据缓存的工作,就能充分利用应用层机器的带宽和极少的内存,来低成本地办理带宽问题了。那么,这种方式是否可以实现呢?
答案是可以的,这种本地缓存 +L1 缓存 + 主从缓存的多级缓存模式,也是业界比较成熟的方案了。多级缓存模式的整体流程大概如下图:
https://i-blog.csdnimg.cn/blog_migrate/0094ef8416628c6bb4a214e9ed9a81d4.png
本地缓存一般位于应用服务器的部署机器上,利用应用服务器本身的少量内存。它是应用层获取数据的第一道缓存,应用层获取数据时先访问本地缓存,如果未掷中,再通过长途从 L1 缓存层获取,终极获取到的数据再回种到本地缓存中。
通过增加本地缓存,依托应用服务器的多部署节点,基本就能完全办理热点数据带宽的问题。而且,相比较从长途 L1 缓存获取数据,本地缓存离应用和用户设备更近,性能上也会更好一些。
但是利用本地缓存有一个必要思量的问题,那就是数据的同等性问题。
还是以“长文章”为例。我们的服务端可能会随时接收到用户必要修改文章内容的请求,这个时候,对于本地缓存来说,由于应用服务器的部署机器随着扩缩容的改变,其数量不肯定是固定的,所以修改后的数据怎样同步到本地缓存中,就是一个比较复杂和麻烦的事情了。
要办理本地缓存同等性问题,业界比较折中的方式是:对本地缓存采用“短过期时间”的方式,来平衡本地缓存掷中率和数据更新同等性的问题。比如说,针对“长文章”的本地缓存,我们可以采用 5 秒过期的策略,淘汰后再从中央缓存获取新的数据。这种方式对于大部分业务场景来说,在产品层面上也是都能担当的。
小结

好了,下面简单回顾一下今天课程的内容。
起首,先容了缓存在高并发应用中的紧张性,以及在 IM 系统中利用的部分场景。然后再带你了解了缓存分布式的两种算法:取模求余和同等性哈希。
取模求余算法在实现上非常简单,但存在的问题是,取模求余算法在节点扩容和宕机后会出现震荡,缓存掷中率会严重低落。
同等性哈希算法办理了节点增删时震荡的问题,并通过虚拟节点的引入,缓解了“数据倾斜”的情况。
最后,偏重先容了业界通用的三种分布式缓存的常见架构。
一种是主从模式。简单的主从模式最常见,但是在面对峰值热点流量时,轻易出现带宽问题,也存在缓存节点宕机后穿透到存储层的问题。
第二种是 L1+ 主从模式。通过增加 L1 缓存层,以并行的多组小容量的 L1 缓存,办理了单一热点的带宽问题,也避免了单一节点宕机后轻易穿透到 DB 存储层的情况。
最后一种是本地缓存 +L1+ 主从的多层模式。作为低成本的办理方案,我们在 L1+ 主从模式的底子上,引入了本地缓存。本地缓存依托应用服务器的本机少量内存,既提拔了资源的有效利用,也彻底办理了带宽的问题。同时在性能方面,也比长途缓存获取更加精良。对于本地缓存的数据同等性问题,我们可以通过“短过期时间”来平衡缓存掷中率和数据同等性。
面对高并发业务带来的流量压力,我们不能否认的是,缓存的利用是现在为止最有效的提拔系统整体性能的手段。作为系统优化的一把利器,怎样用好这个强大的工具,是你必要去不断思考和学习的。希望今天先容的这几种缓存利用的姿势,能够让你有所收获,并能在本身的业务中去尝试实践。
最后留一道思考题:
L1+ 主从模式下,如果热点数据都被 L1 缓存层拦截掷中,会导致主从缓存层相应的这个热点数据,由于长时间得不到读取而被 LRU 淘汰掉。如许,如果下线 L1 缓存,还是会有不少的请求直接穿透到 DB 存储层。那么有没有办法,能够让主从缓存在有 L1 缓存层的情况下,依旧能保持数据热度?

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 17 | Cache:多级缓存架构在消息系统中的应用