Redis学习笔记

知识全景图

![图片alt](/media/article/image/2020-12-14/1607932818322.png ‘‘图片title’’)

  • 高性能主线:线程模型、数据结构、持久化、网络框架;
  • 高可靠主线:主从复制、哨兵极致;
  • 高可扩展主线:数据分片、负载均衡。

问题画像

![图片alt](/media/article/image/2020-12-14/1607933106053.png ‘‘图片title’’)

Redis演变

![图片alt](/media/article/image/2021-01-05/1609828867535.png ‘‘图片title’’)

![图片alt](/media/article/image/2021-01-05/1609841595780.png ‘‘图片title’’)

  • Redis通过网络框架进行访问,不再是动态库了,使得Redis成为一个基础的网络服务,扩大应用范围。
  • Redis的value类型丰富。
  • Redis的持久化支持日志AOF和快照RDB
  • simpleKV是单机键值数据库,而Redis支持高可靠集群和高扩展集群。

bigkey

  • value很大的,才叫bigkey。
  • 字符串类型,比如超过10kb,非字符串类型元素个数很多。

value的类型及数据结构

  • value的类型有五种:
    String(字符串)、List(列表)、 Hash(哈希)、Set(集合)和 Sorted Set(有序集合)

![图片alt](/media/article/image/2021-01-05/1609829286318.png ‘‘图片title’’)

![图片alt](/media/article/image/2021-01-05/1609830968780.png ‘‘图片title’’)

String字符串

  • string需要额外的空间记录数据长度,空间使用等信息。使用简单动态字符串结构体(Simple Dynamic String,SDS)保存。
  • 内存存储,有SDS开销、RedisObject开销、dictEntry结构开销。可以使用压缩列表。
  • 内存分配库jemalloc,分配内存时会找一个比申请的字节数大一些,但是接近2的幂次数的字节,比如申请6字节会分配8字节,申请24字节分配32字节。
  • 最大可以存储512Mb

![图片alt](/media/article/image/2021-01-06/1609901728450.png ‘‘图片title’’)

hash哈希

  • Redis的所有键值采用hash表来保存。
  • 一个哈希表就是一个数组,数组的每个元素称为一个哈希桶。所以一个哈希表由多个哈希桶组成,每个哈希桶中保存键值对数据。哈希桶中保存的并不是值,而是值的指针。
  • 哈希表的好处是在,查询时通过计算键的哈希值找到对应哈希桶的位置,时间复杂度是O(1)。如果发现查询变慢了,那就是hash表发生冲突或者rehash可能带来的操作阻塞。
  • Redis解决哈希冲突是链式哈希,同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接。这样效率低,Redis会采用渐进式rehash操作。
  • 不支持范围查询

set集合

  • 元素不允许重复

sorted有序集合

  • 有两个值:member值和score值,member复制存储数据,不允许重复,score负责存储顺序

压缩列表

  • 压缩列表类似于数组,在表头多了,zlbytes列表长度、zltail列表尾部偏移量、zllen列表中entry个数。表尾还有个zlend表示列表结束。

  • 好处是查找第一个和最后一个元素是O(1),其他元素是O(n)

  • 使用场景:队列

  • 整数数组和压缩列表都是非常紧凑的数据结构,它比链表占用的内存要更少。

跳表

  • 在链表的基础上,增加了多级索引,通过索引位置的几个跳转,快速定位。

GEO数据类型存储经纬度

速度快的原因

Redis的线程

  • Redis的网络IO和键值对读写是一个线程完成的,持久化,异步删除,集群数据同步是额外的线程执行的。

多线程的开销

  • 多线程确实可以增加系统吞吐率,增加系统扩展性。
  • 但是,多线程面临共享资源的并发访问控制问题。大部分线程都在等待获取共享资源的互斥锁,并行变成串行,增加线程也没用。

速度快的原因

  • Redis是内存数据库,大部分操作在内存中执行,再加上采用了高效的数据结构,例如:哈希和跳表
  • 采用多路复用机制,可以在网络IO操作中并发处理大量数据请求,实现高吞吐率。

处理请求过程

  • 需要先监听客户端请求listen/bind,和客户端建立连接accept,从socket中读取请求recv,解析客户端的请求parse,根据请求类型读取键值对数据get,最后返回给客户端,即向socket中写回数据send。
  • 潜在问题是accept()和send()是可能发生网络IO阻塞的,可以使用socket网络模型本身的非阻塞模式。

![图片alt](/media/article/image/2021-01-05/1609832161818.png ‘‘图片title’’)

基于多路复用的高性能I/O模型

  • Linux的多路复用指:一个线程处理多个IO流,就是select/epoll机制。在Redis只运行单进程时,该机制允许内核中,同时存在多个监听套接字和已连接套接字。

Redis高可靠性

  • 数据尽量少丢失:使用AOF和RDB
  • 服务尽量少中断:主从库模式

AOF日志

  • Redis使用后写日志,先执行,执行成功再写日志。这样不会记录错误数据,不会阻塞当前的写操作。

三种写回策略

  • Always:同步写回,每个写操作执行完,立马把日志写回到磁盘。
  • Everysec:每秒写回,每个写操作执行完,先把日志写到内存缓存区,每隔一秒再把日志写回到磁盘上。
  • No:操作系统控制写回,每个写操作执行完,先把日志写到内存缓存区,由操作系统决定什么时候写回磁盘。

![图片alt](/media/article/image/2021-01-05/1609834074717.png ‘‘图片title’’)

日志文件太大怎么办

  • AOF重写机制,同一个key只记录最新的value值。

AOF重写阻塞问题

  • AOF重写是由额外的进程bgrewriteaof完成的,避免阻塞主进程。
  • 一处拷贝:每次执行重写时,主进程会fork一个bgrewriteaof子进程,fork会把主进程的内存拷贝给它,这样子进程就可以单独完成aof重写。
  • 两处日志:此时主进程未阻塞,当有新的写操作时,第一处日志就是当前使用的AOF日志;第二处日志指新的AOF重写日志。

RDB快照

命令

  • save:在主进程执行,会阻塞主进程,
  • bgsave:创建一个子进程,在子进程中执行,不会阻塞主进程,

AOF和RDB选择问题

  • 数据不能丢失:AOF和RDB混合使用
  • 允许分钟级别丢失:使用RDB
  • 允许秒级丢失:使用AOF的everysec配置

实际问题示例

  • 我曾碰到过这么一个场景:我们使用一个 2 核 CPU、4GB 内存、500GB 磁盘的云主机运行 Redis,Redis 数据库的数据量大小差不多是 2GB,我们使用了 RDB 做持久化保证。当时 Redis 的运行负载以修改操作为主,写读比例差不多在 8:2 左右,也就是说,如果有 100 个请求,80 个请求执行的是修改操作。你觉得,在这个场景下,用 RDB 做持久化有什么风险吗?你能帮着一起分析分析吗?

  • 2核CPU、4GB内存、500G磁盘,Redis实例占用2GB,写读比例为8:2,此时做RDB持久化,产生的风险主要在于 CPU资源 和 内存资源 这2方面:

  • a、内存资源风险:Redis fork子进程做RDB持久化,由于写的比例为80%,那么在持久化过程中,“写实复制”会重新分配整个实例80%的内存副本,大约需要重新分配1.6GB内存空间,这样整个系统的内存使用接近饱和,如果此时父进程又有大量新key写入,很快机器内存就会被吃光,如果机器开启了Swap机制,那么Redis会有一部分数据被换到磁盘上,当Redis访问这部分在磁盘上的数据时,性能会急剧下降,已经达不到高性能的标准(可以理解为武功被废)。如果机器没有开启Swap,会直接触发OOM,父子进程会面临被系统kill掉的风险。

  • b、CPU资源风险:虽然子进程在做RDB持久化,但生成RDB快照过程会消耗大量的CPU资源,虽然Redis处理处理请求是单线程的,但Redis Server还有其他线程在后台工作,例如AOF每秒刷盘、异步关闭文件描述符这些操作。由于机器只有2核CPU,这也就意味着父进程占用了超过一半的CPU资源,此时子进程做RDB持久化,可能会产生CPU竞争,导致的结果就是父进程处理请求延迟增大,子进程生成RDB快照的时间也会变长,整个Redis Server性能下降。

  • c、另外,可以再延伸一下,老师的问题没有提到Redis进程是否绑定了CPU,如果绑定了CPU,那么子进程会继承父进程的CPU亲和性属性,子进程必然会与父进程争夺同一个CPU资源,整个Redis Server的性能必然会受到影响!所以如果Redis需要开启定时RDB和AOF重写,进程一定不要绑定CPU。

主从库模式

  • 读操作:主库和从库
  • 写操作:主库负责写,主库将写操作同步给从库

![图片alt](/media/article/image/2021-01-05/1609836948833.png ‘‘图片title’’)

  • 主从库通过replicaof(Redis5.0之前使用的是slaveof)命令完成同步。
replicaof 主库ip 端口号

![图片alt](/media/article/image/2021-01-05/1609837402845.png ‘‘图片title’’)

主从库间网络中断怎么办

  • Redis在2.8之前只能重新使用全量复制的方式同步,2.8之后可以进行增量复制的方式同步。
  • 主从库断联时,会把命令写入到缓冲区repl_backlog_buffer。这是环形缓冲区,主库记录自己写入的位置,从库记录自己读到的位置。

![图片alt](/media/article/image/2021-01-05/1609838087490.png ‘‘图片title’’)

![图片alt](/media/article/image/2021-01-05/1609838031053.png ‘‘图片title’’)![图片alt](/media/article/image/2021-01-05/1609838050015.png ‘‘图片title’’)

Redis实例不要太大,几个G就行

(哨兵模式)主库挂了怎么办

哨兵模式基本流程

  • 哨兵是运行在特殊模式下的Redis进程,主要负责:
  1. 监控
    哨兵进程会周期性的发送ping命令给主从库,进行监控主从库是否下线,若主库下线则启动自动切换主库流程

  2. 选择主库
    按照一定规则,从从库中选择一个作为主库。

  3. 通知
    把新的主库连接,通知给其他从库,通知给客户端,让它们把请求发送到新主库上。

![图片alt](/media/article/image/2021-01-05/1609838933373.png ‘‘图片title’’)

防止哨兵误判主库下线

  • 采用哨兵集群,多个哨兵一起判断
    ![图片alt](/media/article/image/2021-01-05/1609839051998.png ‘‘图片title’’)

如何选定新主库

  • 先按照一定条件进行筛选,再按照规则对剩下的从库进行打分,选择分数最高的从库作为主库
  • 第一轮优先级高的从库得分高
  • 第二轮与旧主库同步程度最近的从库得分高
  • 第三轮ID号小的从库得分高

![图片alt](/media/article/image/2021-01-05/1609839172614.png ‘‘图片title’’)

哨兵集群

  • 一个哨兵挂了,其他哨兵还可以工作
  • 哨兵集群中,彼此是不需要配置其他哨兵的IP的
  • 哨兵之间可以相互发现,通过Redis的pub/sub 发布/订阅机制实现

![图片alt](/media/article/image/2021-01-05/1609839808104.png ‘‘图片title’’)

  • 基于INFO命令的从库列表,可以帮助哨兵和从库建立连接
    ![图片alt](/media/article/image/2021-01-05/1609839833199.png ‘‘图片title’’)

  • 基于pub/sub机制,实现客户端事件的通知

![图片alt](/media/article/image/2021-01-05/1609839948896.png ‘‘图片title’’)

  • 哨兵配置命令
sentinel monitor <master-name> <ip> <redis-port> <quorum> 

要保证哨兵集群中所有哨兵的配置一致

  • 尤其是主观下线的判断值down-after-milliseconds

切/分片集群

![图片alt](/media/article/image/2021-01-05/1609840366901.png ‘‘图片title’’)

如何保持更多的数据

纵向扩展 scale up

  • 升级单个Redis实例配置,加内存、CPU、磁盘。

横向扩展 scale out

  • 使用多个Redis实例

![图片alt](/media/article/image/2021-01-05/1609840640765.png ‘‘图片title’’)

Redis Cluster方案

  • 采用哈希槽Hash Slot,处理数据和实例之间的关系,手动分配哈希槽时,需要把16384个槽都分配完,Redis集群才能正常工作。
  • 对可以使用CRC16算法,计算一个16bit值,产生16384个模,每个模对应一个哈希槽。Redis会自动把这些槽平均分配给N个实例,也可以通过cluster meet 手动分配。

![图片alt](/media/article/image/2021-01-05/1609840953639.png ‘‘图片title’’)

  • 集群中,增删实例会重新分配哈希槽;为了负载均衡,也会重新分配哈希槽。

数据统计

  • 新增用户数或留存用户数:聚合统计
  • 最新评论列表:排序统计
  • 用户签到数:二值状态统计
  • 网页独立访客量:基数统计

![图片alt](/media/article/image/2021-01-06/1609903637186.png ‘‘图片title’’)

Redis保存时间序列数据

时间序列数据特点

  • 快速写入
  • 查询有点查询、范围查询、聚合计算三种。

方案一:

  • 同时保存在hash和sorted set

优点

  • 使用hash进行单键查询,使用sorted set进行范围查询

缺点

  • 聚合计算时,需要把数据传输到客户端再聚合,数据传输开销大
  • 所有数据都要存两次,内存开销大

适用场景

  • Redis实例网络带宽高,内存容量大

方案二

  • 使用RedisTimeSeries模块。

优点

  • 在Redis中直接进行聚合计算,避免大量传输到客户端

缺点

  • 范围查询的时间复杂度高O(n)
  • 点查询只能返回最新的数据,不能查任意时间点数据

适用场景

  • Redis实例网络带宽,内存容量有限,数据量大,聚合计算频繁。

消息队列

  • 在分布式系统中,两个组件要基于消息队列进行通信时,一个组件把要处理的数据以消息的形式传递到消息队列中,然后这个组件可以继续做其他工作,另一个组件从消息队列中把消息读出来,再在本地处理。

![图片alt](/media/article/image/2021-01-06/1609913151221.png ‘‘图片title’’)

![图片alt](/media/article/image/2021-01-06/1609913734330.png ‘‘图片title’’)

需求1:消息保序

  • 消费者是异步处理消息的,但是消费者仍然需要按照生产者产生消息的顺序进行执行。

需求2:重复消息处理

  • 由于网络阻塞会出现消息重复传输,消息队列要能够处理重复消息,消费者要能够避免重复处理

需求3:消息可靠性保证

  • 消费者在处理消息过程中,发生故障或宕机,消息队列要能够提供可靠性,保证消费者可以重新读取消息继续处理。

基于list消息队列方案

![图片alt](/media/article/image/2021-01-06/1609914155265.png ‘‘图片title’’)

基于stream消息队列方案

![图片alt](/media/article/image/2021-01-06/1609914232870.png ‘‘图片title’’)

关于Redis是否适合做消息队列

  • Redis是轻量级消息队列,kafka和RabbitMQ是重量级的。

Redis性能的影响因素

  • Redis内部阻塞式操作
  • CPU核和NUMA架构影响
  • Redis关键系统配置
  • Redis内存碎片
  • Redis缓冲区

Redis阻塞操作

  • 客户端:网络IO,键值对增删改查,数据库操作

  • 磁盘:生成RDB快照,记录AOF日志,AOF日志重写

  • 主从节点:主库生成,传输RDB文件,从库接受RDB文件、清空数据库、加载RDB文件。

  • 切片:向其他实例发送哈希槽,数据迁移

  • ![图片alt](/media/article/image/2021-01-06/1609914689762.png ‘‘图片title’’)

Redis变慢的原因

  • 响应延迟
  • 基线性能
  1. 使用复杂度过高的命令或一次查询全量数据;
  2. 操作 bigkey;
  3. 大量 key 集中过期;
  4. 内存达到 maxmemory;
  5. 客户端使用短连接和 Redis 相连;
  6. 当 Redis 实例的数据量大时,无论是生成 RDB,还是 AOF 重写,都会导致 fork 耗时 严重;
  7. AOF 的写回策略为 always,导致每个操作都要同步刷回磁盘;
  8. Redis 实例运行机器的内存不足,导致 swap 发生,Redis 需要到 swap 分区读取数 据;
  9. 进程绑定 CPU 不合理;
  10. Redis 实例运行机器上开启了透明内存大页机制;
  11. 网卡压力过大。

解决方案

  • 获取当前Redis实例的当前环境下的基线性能
# 打印120秒内的最大延迟,实例运行延时大于这个的两倍就说明变慢了
redis-cli --intrinsic-latency 120
  • 是否用了慢命令,若有可改成其他命令,例:把聚合命令放到客户端
showlog get 1 # 查看最近一条慢查询的日志

# 使用latency monitor命令监控慢查询
config set latency-monitor-threshold 1000 # 设置慢查询的时间阈值为1000微秒
latency monitor # 开启监控
  • 是否对过期key设置了相同的过期时间,若有则在每个key的过期时间加上一个随机数,避免同时删除
  • 是否存在bigkey,bigkey的删除可以用异步删除,bigkey的集合查询和聚合操作,可以用SCAN命令在客户端完成
./redis-cli --bigkeys
  • Redis的AOF是什么级别,若允许少量数据丢失,可以采用everysec模式;将配置项no-appendfsync-on-rewrite改为yes,避免aof重写与fsync竞争磁盘IO资源。
  • Redis内存使用是否过大?发生swap了吗,若是则需要增加内存或者使用集群
  • Redis运行环境是否启用了透明大页机制,若有则需要关闭。
  • 是否运行了Redis主从集群,主库控制在2-4G,避免加载过大的RDB而阻塞
  • 是否使用多核CPU?若有,则可以给Redis实例绑定物理核
  • CPU是否是NUMA架构,若是,则把Redis实例和网络中断处理程序运行在一个CPU socket上

内存碎片

形成原因

  • 内因:操作系统内存分配机制
  • 外因:Redis负载特征,键值对大小不一样和删改操作

查看内存碎片

INFO memory
  • 其中mem_fragmentation_ratio = (used_memory_rss/used_memory)就是内存碎片率
  • 其中mem_fragmentation_ratio 在1-1.5之间是正常的,如果大于1.5说明内存占用率超过了50%,需要采取措施降低。
  • 如果其中mem_fragmentation_ratio小于1,可能是发生swap了。

清理内存碎片

  • 重启Redis
  • 设置Redis自动清理config set activedefrag yes

内存碎片自动清理参数

  • active-defrag-ignore-bytes 100mb:表示内存碎片的字节数达到 100MB 时,开始清理;
  • active-defrag-threshold-lower 10:表示内存碎片空间占操作系统分配给 Redis 的 总空间比例达到 10% 时,开始清理。
  • active-defrag-cycle-min 25: 表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展;
  • active-defrag-cycle-max 75:表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致 响应延迟升高。

缓冲区

客户端和服务器的缓冲区

  • 输入缓存区,缓存客户端输入的命令
  • 输出缓存区,缓存服务端输出的结果

![图片alt](/media/article/image/2021-01-06/1609923579803.png ‘‘图片title’’)

如何应对输入缓冲区溢出

原因

  • 写入了bigkey,写入多个百万级别的集合类型数据
  • 服务端处理请求过慢

查看缓冲区命令

CLIENT LIST

解决

  • 把缓冲区调大
  • 数据命令的发送和处理速度调优

如何应对输出缓冲区溢出

原因

  • 服务端返回bigkey的大量结果
  • 执行了MONITOR命令(这个是监测Redis行为的,不要在生成环境使用)
  • 缓冲区大小设置不合适

解决

  • 设置缓冲区大小,normal代表普通客户端,第一个0是缓冲区大小,第二个0是缓冲区持续写入量限制,第三个0是缓冲区持续写入时间限制。
client-output-buffer-limit  normal  0  0  0
例如:client-output-buffer-limit  pubsub  8mb  2mb  60

主从集群的缓冲区

  • 全量复制
  • 增量复制

复制缓冲区的溢出问题

  • 在全量复制时,主节点在发送RDB文件给从节点时,会把接受的新的写命令保存到复制缓冲区中,等RDB传输完成时,再把缓冲区的命令发送给从节点。如果在主节点在发送RDB文件给从节点时,接收到大量写命令时,可能会发送缓冲区溢出问题。

![图片alt](/media/article/image/2021-01-06/1609925226910.png ‘‘图片title’’)

缓存

缓存的特征

  • 一个系统不同层的之间的访问速度不同,所以才要缓存。
  • 一个快速的子系统要连接一个慢速的子系统,为了避免每次都要去连接慢速的子系统,自身会存储部分数据。 快速的子系统缓存系统的容量总是小于慢速子系统的。

![图片alt](/media/article/image/2021-01-07/1609987314696.png ‘‘图片title’’)

处理缓存的两种情况

  • 命中缓存
  • 缓存缺失,缓存中没有数据,需要重新读取数据,还有额外存储到缓存中。
    ![图片alt](/media/article/image/2021-01-07/1609987919052.png ‘‘图片title’’)

只读缓存

  • 应用在进行读请求,会调用Redis的GET接口,查询Redis中的数据。
  • 应用在进行写请求,会直接访问数据库,在数据库进行增删改操作。对于删改的数据,如果Redis中有这些数据的话,则会直接删除,下次应用再读取这些数据时,会发生缓存缺失,应用会先读取数据库的数据然后,再写入到Redis。
    ![图片alt](/media/article/image/2021-01-07/1609989035194.png ‘‘图片title’’)

特点

  • 应用的写操作会直接到数据库,数据没有丢失的风险。

应用场景

  • 读多写少

读写缓存

  • 和只读缓存不同的是,应用在进行写操作时,会先写入Redis。
  • 写回有两种策略:同步写回(Redis和数据库一起写都完成才返回),异步写回()

特点

  • 性能高,但是Redis出现故障或宕机时会丢失数据。

应用场景

  • 写入比较多

缓存容量

  • 一般建议缓存容量设置为总数据的15%—30%,兼顾访问性能和内存空间开销。
    set memory 4gb

缓存淘汰机制

  • 缓存被写满是无法避免的,此时面临两个问题,淘汰哪些数据?如何淘汰?

  • 7种淘汰机制
    ![图片alt](/media/article/image/2021-01-07/1609992184595.png ‘‘图片title’’)

缓存淘汰方案

方案一

  • allkeys-lru策略,重复利用LRU算法优势,把最近最常访问的数据留在缓存中,提升性能

适用场景

  • 业务数据有明显冷热数据区分。

方案二

  • allkeys-random策略,随机选择淘汰数据进行删除。

使用场景

  • 业务数据访问频率相差不大

方案三

  • volatile-lru策略,可以给置顶的数据不设置过期时间

适用场景

  • 适合有置顶需求的业务

Redis缓存注意

  • 在Redis中,对应淘汰的数据,无论是否是脏数据,都会被删除。因此当数据被设置为脏数据时也需要在数据库中把数据修改回来。

缓存异常

缓存数据跟数据库数据不一致问题

  • 缓存中有数据,缓存中的数据跟数据库数据不一致。
  • 缓存中没有数据,数据库的值不是最新的。

![图片alt](/media/article/image/2021-01-07/1610005118439.png ‘‘图片title’’)

通常使用只读缓存

  • 建议是先更新数据库在删除缓存。

原因

  • 先删除缓存值在更新数据库,会导致请求因为缓存缺失而访问数据库,造成数据库压力。
  • 而且业务应用读取数据库数据,跟删除缓存值的时间不好估算,延迟双删中等待时间不好设置。

缓存雪崩

定义

  • 大量应用请求无法在Redis缓存中进行处理,导致大量请求发送到数据库层,导致数据库层压力激增。

原因一

  • 缓存中有大量数据同时过期,导致大量请求无法处理。

解决办法一

  • 数据设置过期时间时,加上一个小的随机数。(expire命令,随机增加1-3命令)

解决办法二

  • 服务降级,针对不同的数据采取不同的策略
  • 业务应用访问非核心数据时(如商品属性):暂停从缓存中读取,而是直接返回预定义信息、空值、错误信息。
  • 业务应用访问核心数据时(如商品库存):仍然从缓存中读取,如果缓存缺失,则读取数据库。

原因二

  • Redis宕机

解决办法一(事后处理)

  • 在业务系统中实现服务熔断或者请求限流机制。
  • 服务熔断,暂停业务应用访问Redis实例和数据库。
  • 请求限流,限制数据库层的每秒访问次数。

解决办法二(事前预防)

  • 通过主从方式构建Redis高可靠集群。

缓存击穿

定义

  • 访问非常频繁的热点数据过期

解决

  • 热点数据不设置过期时间

缓存穿透

定义

  • 访问的数据Redis缓存中没有,数据库层也没有,此时应用无法从数据库层读取数据并写入到Redis中,如果有持续大量请求,就会给缓存和数据库带来压力。

原因一

  • 业务层误操作,缓存和数据库中的数据被删了。

解决办法一

  • 缓存空值和缺省值

解决办法二

  • 使用布隆过滤器,快速判断数据是否存在,避免从数据库中查询数据是否存在,减小数据库压力。

原因二

  • 恶意攻击,专门访问数据库中没有的数据

解决办法

  • 在请求入口前端实现恶意代码检测

![图片alt](/media/article/image/2021-01-07/1610008628309.png ‘‘图片title’’)

缓存污染

定义

  • 留存在缓存中的数据,实际上不会再访问了,但又占据缓存空间。

解决

  • LRU策略:关注数据的实效性。
  • LFU策略:关注数据的访问频次(优先使用)。
评论