当前位置: 首页 > news >正文

缓存解决方案

在业务系统系统中,缓存解决方案一共有三种,第一种是最为常见的集中式缓存Redis、第二种是HashMap、Guava Cache、Caffeine、EhCache等本地缓存。

第三种,则是集中式缓存Redis + 任意一种本地缓存所组成的双缓存机制。

如下图所示:

img

无论选择哪种解决方案,其核心作用无外乎两点:提升系统性能和减轻数据库访问压力。

接下来我们来详细盘点一下,这三种缓存解决方案的各自适用场景和优缺点。

集中式缓存

90%的业务场景下,无脑选择Redis作为系统缓存就对了,这是目前最为主流的解决方案,其优点有很多。

1、丰富的数据类型

我们最常用的有五种,String、Hash、List、Set、ZSet,基本上满足于系统中绝大多数业务场景。

除此之外,我们还可以通过BitMap实现用户签到、HyperLogLog实现网站UV统计、Bloom Filter实现黑白名单,等等。

2、优秀的查询性能

Redis中做了很多性能优化的策略,如下图所示:

img

除此之外,在Redis 6.0中还引入了多线程机制,旨在解决几万QPS的高并发读场景下的IO瓶颈问题,将性能至少提升一倍以上。

3、较低的内存消耗

Redis并没有按照标准的LRU算法进行实现,因为其双向链表的实现方式,对内存消耗的代价是不可接受的。

且Redis接收到每次请求,双向链表也需要进行同步操作,性能影响也不小。

因此,Redis采用了引入LRU时钟值 + 待淘汰数据池的“近似LRU”的实现方式,有效地规避了上述问题。

img

4、高可用性、扩展性

Redis Cluster支持动态扩容的数据分片机制,来保证其横向扩展能力,以及通过主从复制 + 自动故障转移机制保证高可用性。

致命缺点

但是,Redis纵然有这么多优点,也掩盖不了它的一个致命缺点,那就是高并发场景下的大Key问题。

大Key其实说的是,该Key所对应的value值比较大(如:大于1MB),存储它会占用比较大的内存空间,在进行读取的时候也会占用很大的网络带宽。

大Key本身是没什么问题的,用户每秒钟请求它一两次的不会有任何影响,最怕的就是大Key + 热Key的Buff叠满。

我们以常见的服务器千兆网卡来计算,其最大传输速度为每秒钟128MB。

这也就就意味着,Redis中的某个大Key为1MB、每秒钟有128个及以上请求打到这台服务器上,就能将服务器的网卡打满,从而影响系统可用性。

一旦Redis Cluster中存储大热Key节点的网卡被打满,就会导致集群中的资源消耗倾斜,不仅大热Key的请求被影响,就连访问该节点的其他请求也会被影响。

如下图所示:

img

也正是由于Redis这个致命缺点,才有了HashMap、Guava Cache、Caffeine、EhCache等本地缓存的“用武之地”。

本地缓存

在HashMap、Guava Cache、Caffeine、EhCache这些本地缓存中,最常用的是HashMap和Caffeine,前者优势为简单易用,后者则具有更加强悍的性能。

Caffeine性能对比图如下:

img

Caffeine的功能也比较强大,其中包括:

(1)在缓存淘汰算法上,支持结合了LRU和LFU两者优点的W-TinyLFU算法,在流量分布稳定和突发流量上都能保证最佳的命中率。

(2)在缓存淘汰策略上,支持基于容量、基于时间和基于引用三种策略,基于时间的淘汰策略上,支持写入后过期、访问后过期和自定义过期。

(3)在缓存加载策略上,支持手动加载、自动加载、手动异步加载和自动异步加载四种策略。

接下来,我们讲讲这些本地缓存的“用武之地”,也就是说,为什么它能够解决Redis的大热Key问题。

Redis的大热Key:

img

本地缓存中的大热Key:

img

如图中所示,这个大热Key的流量只会打在Redis集群中的一个节点上,但本地缓存可以用集群中的多个应用服务器均摊流量,这样服务器的网卡就不再成为瓶颈了。

本地缓存还有一个比较经典的应用场景,那就是在Eureka、Nacos这些配置中心和服务注册中心上,底层实现会在客户端本地缓存一份数据。

这样做可以提升数据查询性能,减轻对Server端的访问压力,并且也降低了对Server端的强依赖,就算Server端挂了功能也能正常运行。

相比较而言,本地缓存既然不如集中式缓存Redis主流,原因在于前者存在一些令人无法忍受的缺点,我们就来盘点一下。

1、数据一致性问题

本地缓存的最大缺点在于,缓存更新的场景下,需要将集群中多个应用服务器的缓存数据全部更新。

无论是通过API全部调用的方式,还是通过消息队列的发布订阅模式,都很难保证绝对意义上的数据一致性问题,这可能会给业务系统埋下很大的坑。

因此,本地缓存只适合所缓存的数据不变更、或是很少变更的业务场景。

2、需数据预热

应用服务器重启或功能发布上线的时候,本地缓存中的数据会全部丢失,此时需要有个将数据全部吃进缓存的数据预热步骤,增加了系统实现的复杂性。

另外,若在本地缓存中缓存数据过多,数据预热时间也会很久。

3、导致GC频繁

本地缓存的数据在强引用状态下不会进行GC,若缓存数据过多会导致GC频繁。

双缓存机制

双缓存机制适用于QPS极高的业务场景,一般将本地缓存用于缓存访问频率极高的热点数据,如:新闻网站上的头条爆点新闻,电商平台中的大促秒杀商品。而Redis则用于缓存访问频率一般的数据,如:新闻网站上的普通新闻、电商平台中正常售卖的商品。

img

在双缓存机制更有利于系统容灾,无论本地缓存还是Redis出现问题,都有另一个进行兜底。其不足之处在于,数据一致性的问题更难以解决了,仍然只适合所缓存的数据不变更、或是很少变更的业务场景。

http://www.dtcms.com/a/267430.html

相关文章:

  • vuedraggable在iframe中无法使用问题
  • MySQL基础和 表的‘CRUD’(基础版)
  • 基础数据结构第04天:单向链表(概念篇)
  • ubuntu手动编译VTK9.3 Generating qmltypes file 失败
  • 解决URL编码兼容性问题:空格转义与HTML实体解码实战
  • 基于企业私有数据实现智能问答
  • 动手学深度学习-学习笔记(总)
  • Kali Linux Wifi 伪造热点
  • 基于Java+SpringBoot的三国之家网站
  • 嵌入式系统内核镜像相关(十二)
  • Flink-Source算子点位提交问题(Earliest)
  • 力扣 hot100 Day35
  • STM32中实现shell控制台(命令解析实现)
  • MySQL回表查询深度解析:原理、影响与优化实战
  • 从UI设计到数字孪生实战部署:构建智慧城市的智慧照明系统
  • 【项目笔记】高并发内存池项目剖析(三)
  • NX二次开发——NX二次开发-检查点是否在面上或者体上
  • MPLS 多协议标签交换
  • Python实例题:基于 Python 的简单聊天机器人
  • springsecurity5配置之后启动项目报错:authenticationManager cannot be null
  • LangChain4j 框架模仿豆包实现智能对话系统:架构与功能详解
  • windows 安装 wsl
  • 基于matlab卡尔曼滤波器消除噪声
  • 点击方块挑战小游戏流量主微信小程序开源
  • Java+Vue开发的进销存ERP系统,集采购、销售、库存管理,助力企业数字化运营
  • 浏览器与服务器的交互
  • 深度学习图像分类数据集—百种鸟类识别分类
  • STM32中实现shell控制台(shell窗口输入实现)
  • 结构型智能科技的关键可行性——信息型智能向结构型智能的转变(修改提纲)
  • rk3128 emmc显示剩余容量为0