Redis数据库:持久化策略与性能管理-程序员宅基地

技术标签: 运维  性能优化  数据库  redis  

目录

前言

一、Redis持久化

1、Redis持久化功能

2、Redis持久化的两种方式

3、RDB持久化

3.1 触发条件

3.2 执行流程

3.3 启动时加载

4、AOF持久化

4.1 开启AOF

4.2 执行流程

4.2.1 执行流程详解

4.2.2 执行流程图

4.3 启动时加载

5、RDB与AOF持久化的优缺点

5.1 RDB持久化优缺点

5.2 AOF持久化优缺点

二、Redis性能管理

1、查看Redis内存使用情况

2、内存碎片率 

3、内存使用率

4、内回收key(Internal Key Recycling)

三、Redis缓存穿透、击穿、雪崩

1、Redis缓存穿透

1.1 问题详细描述

1.2 缓存穿透发生的条件

1.3 缓存穿透发生的原因

1.4 解决方案

2、Redis缓存击穿

2.1 问题详细描述

2.2 缓存击穿的现象

2.3 缓存击穿发生的原因

2.4 解决方案

3、Redis缓存雪崩

3.1 问题详细描述

3.2 缓存雪崩的条件

3.3 缓存雪崩的原因

3.4 解决方案

四、总结

1、RDB与AOF持久化区别

2、RDB与AOF持久化过程

3、RDB与AOF触发方式

4、 RDB与AOF优先级

5、缓存穿透、击穿、雪崩区别


前言

Redis是一种流行的开源内存数据库,它支持多种持久化策略以确保数据在发生故障时不会丢失

本文详细介绍了RDB持久化策略和AOF持久化策略,这两种持久化方式可以单独使用,也可以同时使用,以提供更高级的数据安全性。选择何种方式或者两者结合取决于你的应用程序需求和对数据完整性的要求

通过合理配置持久化策略,可以确保Redis在面临硬件故障或断电等情况下,能够尽可能地保护数据

一、Redis持久化

1、Redis持久化功能

Redis是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致Redis进程异常退出后数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置

2、Redis持久化的两种方式

  • RDB(Redis DataBase)持久化:RDB持久化方式通过将内存中的数据保存到磁盘上的文件中来实现持久化。这种方式会周期性地将数据集的内容写入磁盘,可以通过配置定期保存快照的时间间隔和保存条件。RDB持久化生成的文件是一个经过压缩的二进制文件,可以在需要时进行恢复

  • AOF(Append Only File)持久化:AOF持久化记录了服务器接收的每一条写入命令,以文件追加的方式保存在磁盘上。当服务器重启时,可以通过重新执行AOF文件中的命令来还原数据集的状态。AOF持久化方式相对于RDB更加可靠,因为它可以提供更好的数据完整性保证,但相应地也会增加磁盘的写入负担

3、RDB持久化

RDB持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据。

3.1 触发条件

RDB持久化的触发分为手动触发和自动触发两种

  • 手动触发

save命令和bgsave命令都可以生成RDB文件

save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求

而bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即Redis主进程)则继续处理请求

bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用

  • 自动触发

在自动触发RDB持久化时,Redis也会选择bgsave而不是save来进行持久化

save m n 
#自动触发最常见的情况是在配置文件中通过save m n,指定当m秒内发生n次变化时,会触发bgsave

开启自动触发RDB持久化:

[root@localhost ~]#vim /etc/redis/6379.conf
 
219行以下三个save条件满足任意一个时,都会引起bgsave的调用
save 900 1      #当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
save 300 10     #当时间到300秒时,如果redis数据发生了至少10次变化,则执行bgsave
save 60 10000   #当时间到60秒时,如果redis数据发生了至少10000次变化,则执行bgsave
 
254行指定RDB文件名
dbfilename dump.rdb
 
264行指定RDB文件和AOF文件所在目录
dir /var/lib/redis/6379
 
242行是否开启RDB文件压缩
rdbcompression yes

[root@localhost ~]#/etc/init.d/redis_6379 restart
#若修改了配置文件,需重启服务

其他自动触发机制:

除了save m n 以外,还有一些其他情况会触发bgsave: 

  • 在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点
  • 执行shutdown命令时,自动执行rdb持久化

3.2 执行流程

(1)当bgsave命令向父进程发送持久化请求

(2)Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof的子进程,如果在执行则bgsave命令直接返回。 bgsave/bgrewriteaof的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题
(3)父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令
(4)父进程fork后,bgsave命令返回”Background saving started”信息并不再阻塞父进程,并可以响应其他命令
(5)子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
(6)子进程发送信号给父进程表示完成,父进程更新统计信息

3.3 启动时加载

RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AOF的优先级更高,因此当AOF开启时,Redis会优先载入 AOF文件来恢复数据;只有当AOF关闭时,才会在Redis服务器启动时检测RDB文件,并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止

Redis载入RDB文件时,会对RDB文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败

4、AOF持久化

RDB持久化是将进程数据写入文件,而AOF持久化,则是将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录; 当Redis重启时再次执行AOF文件中的命令来恢复数据

与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案

4.1 开启AOF

Redis服务器默认开启RDB,关闭AOF。所以要开启AOF,需要在配置文件中配置

[root@localhost ~]#vim /etc/redis/6379.conf
 
700行修改,开启AOF
appendonly yes
 
704行指定AOF文件名称
appendfilename "appendonly.aof"
 
796行是否忽略最后一条可能存在问题的指令
aof-load-truncated yes

[root@localhost ~]#/etc/init.d/redis_6379 restart

4.2 执行流程

4.2.1 执行流程详解

由于需要记录Redis的每条写命令,因此AOF不需要触发,下面介绍AOF的执行流程

AOF的执行流程主要包括:

  • 命令追加(append):将Redis的写命令追加到缓冲区aof_buf
  • 文件写入(write)和文件同步(sync):根据不同的同步策略将aof_buf中的内容同步到硬盘
  • 文件重写(rewrite):定期重写AOF文件,达到压缩的目的

(1)命令追加(append)

Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈

命令追加的格式是Redis命令请求的协议格式,它是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点。在AOF文件中,除了用于指定数据库的select命令(如select 0为选中0号数据库)是由Redis添加的,其他都是客户端发送来的写命令

(2)文件写入(write)和文件同步(sync)

Redis提供了多种AOF缓存区的同步文件策略,策略涉及到操作系统的write函数和fsync函数,说明如下:

为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性

AOF缓存区的同步文件策略存在三种同步方式,它们分别是:appendfsync always、appendfsync no、appendfsync everysec

#在/etc/redis/6379.conf的729~731行,可根据需要的生产环境来选择哪个同步方式
[root@localhost ~]#vim /etc/redis/6379.conf

# appendfsync always
appendfsync everysec    #默认的是appendfsync everysec同步方式
# appendfsync no

[root@localhost ~]#/etc/init.d/redis_6379 restart
#若修改了配置文件,需重启服务才能生效

  • appendfsync always: 命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命
  • appendfsync no: 命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证
  • appendfsync everysec: 命令写入aof_buf后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置

(3)文件重写(rewrite)

随着时间流逝,Redis服务器执行的写命令越来越多,AOF文件也会越来越大;过大的AOF文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长

文件重写是指定期重写AOF文件,减小AOF文件的体积。需要注意的是,AOF重写是把Redis进程内的数据转化为写命令,同步到新的AOF文件;不会对旧的AOF文件进行任何读取、写入操作

关于文件重写需要注意的另一点是:对于AOF持久化来说,文件重写虽然是强烈推荐的,但并不是必须的;即使没有文件重写,数据也可以被持久化并在Redis启动的时候导入;因此在一些实现中,会关闭自动的文件重写,然后通过定时任务在每天的某一时刻定时执行

文件重写之所以能够压缩AOF文件,原因在于:

  • 过期的数据不再写入文件
  • 无效的命令不再写入文件:如有些数据被重复设值(set mykey v1, set mykey v2)、有些数据被删除了(sadd myset v1, del myset)等
  • 多条命令可以合并为一个:如sadd myset v1, sadd myset v2, sadd myset v3可以合并为sadd myset v1 v2 v3

通过上述内容可以看出,由于重写后AOF执行的命令减少了,文件重写既可以减少文件占用的空间,也可以加快恢复速度

文件重写的触发,分为手动触发和自动触发:

  • 手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞
  • 自动触发:通过设置auto-aof-rewrite-min-size选项和auto-aof-rewrite-percentage选项来自动执行BGREWRITEAOF。 只有当auto-aof-rewrite-min-size和auto-aof-rewrite-percentage两个选项同时满足时,才会自动触发AOF重写,即bgrewriteaof操作
#在/etc/redis/6379.conf的771~772行,只有当这两个选项同时满足时,才会自动触发AOF重写,即bgrewriteaof操作
[root@localhost ~]#vim /etc/redis/6379.conf

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

[root@localhost ~]#/etc/init.d/redis_6379 restart
#若修改了配置文件,需重启服务才能生效

  • auto-aof-rewrite-percentage 100 :当前AOF文件大小(即aof_current_size)是上次日志重写时AOF文件大小(aof_base_size)两倍时,发生BGREWRITEAOF操作
  • auto-aof-rewrite-min-size 64mb :当前AOF文件执行BGREWRITEAOF命令的最小值,避免刚开始启动Reids时由于文件尺寸较小导致频繁的BGREWRITEAOF

关于文件重写的流程,有两点需要特别注意:

  • 重写由父进程fork子进程进行;
  • 重写期间Redis执行的写命令,需要追加到新的AOF文件中,为此Redis引入了aof_rewrite_buf缓存
4.2.2 执行流程图

(1)当bgrewriteaof命令向父进程发送持久化请求

(2)Redis父进程首先判断当前是否存在正在执行bgsave/bgrewriteaof的子进程,如果存在则bgrewriteaof命令直接返回,如果存在 bgsave命令则等bgsave执行完成后再执行。 
(3)父进程执行fork操作创建子进程,这个过程中父进程是阻塞的。父进程fork后,bgrewriteaof命令返回”Background append only file rewrite started”信息并不再阻塞父进程, 并可以响应其他命令
(4.1)Redis的所有写命令依然写入AOF缓冲区,并根据appendfsync策略同步到硬盘,保证原有AOF机制的正确
(4.2)由于fork操作使用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然在响应命令,因此Redis使用AOF重写缓冲区(aof_rewrite_buf)保存这部分数据,防止新AOF文件生成期间丢失这部分数据。也就是说,bgrewriteaof执行期间,Redis的写命令同时追加到aof_buf和aof_rewirte_buf两个缓冲区
(5)子进程根据内存快照,按照命令合并规则写入到新的AOF文件
(6.1)子进程写完新的AOF文件后,向父进程发信号,父进程更新统计信息,具体可以通过info persistence查看
(6.2)父进程把AOF重写缓冲区的数据写入到新的AOF文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致
(6.3)使用新的AOF文件替换老文件,完成AOF重写

4.3 启动时加载

当AOF开启时,Redis启动时会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会载入RDB文件恢复数据

当AOF开启,但AOF文件不存在时,即使RDB文件存在也不会加载

Redis载入AOF文件时,会对AOF文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败。但如果是AOF文件结尾不完整(机器突然宕机等容易导致文件尾部不完整),且aof-load-truncated参数开启,则日志中会输出警告,Redis忽略掉AOF文件的尾部,启动成功。aof-load-truncated参数默认是开启的

5、RDB与AOF持久化的优缺点

5.1 RDB持久化优缺点

  • 优点

RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多

当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小

  • 缺点

RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流

此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)

对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力

5.2 AOF持久化优缺点

  • 优点

与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好

  • 缺点

文件大、恢复速度慢、对性能影响大

对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO压力更大,甚至可能造成AOF追加阻塞问题

AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的IO压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对 Redis主进程性能的影响会更大

二、Redis性能管理

1、查看Redis内存使用情况

#登录到redis数据库,然后查看redis内存使用情况
redis-cli -h 172.16.12.10 -p 6379
172.16.12.10:6379> info memory

#查询结果显示
used_memory:853336               #当前使用的内存量,853336字节,约833.34K(千字节)              
used_memory_human:833.34K
used_memory_rss:3489792          #分配的内存总量,包括操作系统分配的内存,3489792字节,约3.33M(兆字节)
used_memory_rss_human:3.33M    
used_memory_peak:853336          #内存使用量的峰值,853336字节,约833.34K
used_memory_peak_human:833.34K    
used_memory_peak_perc:100.01%    #内存使用量相对于内存峰值的百分比,100.01%
used_memory_overhead:841110      #Redis实例的内存开销,841110字节
used_memory_startup:791416       #Redis实例启动时的内存使用量,791416字节
used_memory_dataset:12226        #数据集占用的内存量,12226字节
used_memory_dataset_perc:19.74%  #数据集占用的内存量相对于总内存的百分比,19.74%
allocator_allocated:1263152      #分配的总内存量,1263152字节
allocator_active:1581056         #活跃的内存量,1581056字节
allocator_resident:8519680       #实际驻留内存量,8519680字节
total_system_memory:3958075392   #系统总内存量,3958075392字节,约3.69G(千兆字节)
total_system_memory_human:3.69G
used_memory_lua:37888            #Lua引擎使用的内存量,37888字节,约37.00K(千字节)
used_memory_lua_human:37.00K    
used_memory_scripts:0            #脚本使用的内存量,0字节
used_memory_scripts_human:0B     
number_of_cached_scripts:0       #缓存的脚本数量,0
maxmemory:0                      #最大可用内存量,0字节
maxmemory_human:0B
maxmemory_policy:noeviction      #内存达到最大限制时的策略,noeviction(不会驱逐任何键)
allocator_frag_ratio:1.25        #分配器碎片化比率,1.25
allocator_frag_bytes:317904      #分配器碎片化量,317904字节
allocator_rss_ratio:5.39         #分配器驻留内存比率,5.39
allocator_rss_bytes:6938624      #分配器驻留内存量,6938624字节
rss_overhead_ratio:0.41          #驻留内存开销比率,0.41
rss_overhead_bytes:-5029888      #驻留内存开销量,-5029888字节
mem_fragmentation_ratio:4.30     ##内存碎片化比率,4.30
mem_fragmentation_bytes:2677480  #内存碎片化量,2677480字节
mem_not_counted_for_evict:0      #未计入驱逐的内存量,0字节
mem_replication_backlog:0        #复制积压的内存量,0字节
mem_clients_slaves:0             #从节点客户端数量,0
mem_clients_normal:49694         #正常客户端数量,49694
mem_aof_buffer:0                 #AOF(Append-Only File)缓冲区的内存量,0字节
mem_allocator:jemalloc-5.1.0     #内存分配器的类型和版本,jemalloc-5.1.0
active_defrag_running:0          #是否正在运行主动碎片整理,0表示否
lazyfree_pending_objects:0       #等待释放的对象数量,0

 2、内存碎片率 

操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存总量值 used_memory 计算得出内存碎片率,其中内存值 used_memory_rss 表示该进程所占物理内存的大小,即为操作系统分配给 Redis 实例的内存大小

除了用户定义的数据和内部开销以外,used_memory_rss 指标还包含了内存碎片的开销, 内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)

内存碎片率指Redis中已分配但未被使用的内存与总分配内存的比率,当Redis实例中存在大量的内存碎片时,可能会导致内存浪费和性能下降

例:

Redis 需要分配连续内存块来存储 1G 的数据集。如果物理内存上没有超过 1G 的连续内存块, 那操作系统就不得不使用多个不连续的小内存块来分配并存储这 1G 数据,该操作就会导致内存碎片的产生

跟踪内存碎片率对理解Redis实例的资源性能是非常重要的:

  • 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低,也说明 Redis 没有发生内存交换
  • 内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率。需要在redis-cli工具上输入shutdown save 命令,让 Redis 数据库执行保存操作并关闭 Redis 服务,再重启服务器
  • 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少 Redis 内存占用。

3、内存使用率

内存使用率是指Redis实例当前使用的内存量与其可用内存总量之间的比率。通常以百分比表示

rdis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换

避免内存交换发生的方法:

  • 针对缓存数据大小选择安装 Redis 实例
  • 尽可能的使用Hash数据结构存储
  • 设置key的过期时间

4、内回收key(Internal Key Recycling)

内回收key是指Redis在删除或更新某个键值对后,将其占用的内存空间标记为可重用,而不是立即释放给操作系统。这样做的目的是为了提高内存使用效率和性能

内回收key是内存清理策略,保证合理分配redis有限的内存资源

当达到设置的最大阀值时,需选择一种key的回收策略,默认情况下回收策略是禁止删除

可通过修改配置文件中 maxmemory-policy 属性值:

#在/etc/redis/6379.conf的第598行,可根据需要的生产环境来选择哪种maxmemory-policy 属性值
[root@localhost ~]#vim /etc/redis/6379.conf

maxmemory-policy noenviction
#maxmemory-policy 属性值有volatile-lru、volatile-ttl、volatile-random、allkeys-lru、allkeys-random、noenviction

#volatile-lru:使用LRU算法从已设置过期时间的数据集合中淘汰数据(移除最近最少使用的key,针对设置了TTL的key)
#volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰(移除最近过期的key)
#volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰(在设置了TTL的key里随机移除)
#allkeys-lru:使用LRU算法从所有数据集合中淘汰数据(移除最少使用的key,针对所有的key)
#allkeys-random:从数据集合中任意选择数据淘汰(随机移除key)
#noenviction:禁止淘汰数据(不删除直到写满时报错)

[root@localhost ~]#/etc/init.d/redis_6379 restart
#若修改了配置文件,需重启服务才能生效

 

三、Redis缓存穿透、击穿、雪崩

1、Redis缓存穿透

指的是恶意请求或者不存在的数据频繁访问缓存,导致这些请求直接绕过缓存,直接查询数据库,从而造成数据库压力过大

1.1 问题详细描述

key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源(数据库),从而可能压垮数据源。比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库

1.2 缓存穿透发生的条件

  • 应用服务器压力变大
  • redis 命中率降低
  • 一直查询数据库,使得数据库压力太大而压垮
  • 其实 redis 在这个过程中一直平稳运行,崩溃的是我们的数据库(如 MySQL)

1.3 缓存穿透发生的原因

  • 恶意查询黑客或者其他非正常用户频繁进行很多非正常的 url 访问,使得 redis 查询不到数据库,从而绕过缓存直接查询数据库,导致数据库压力增加
  • 系统错误:例如程序bug、异常输入等情况,导致大量的无效查询请求

1.4 解决方案

  • 对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
  • 设置可访问的名单(白名单):使用 bitmaps 类型定义一个可以访问的名单,名单 id 作为 bitmaps 的偏移量,每次访问和 bitmap 里面的 id 进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,不允许访问
  • 采用布隆过滤器:布隆过滤器(Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量 (位图) 和一系列随机映射函数(哈希函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难
  • 进行实时监控:当发现 Redis 的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务

2、Redis缓存击穿

指的是针对某一热点数据的并发访问,当该热点数据失效时,大量并发请求同时涌入,导致这些请求绕过缓存,直接查询数据库,加重了数据库负担

2.1 问题详细描述

key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮

2.2 缓存击穿的现象

  • 数据库访问压力瞬时增加,数据库崩溃
  • redis 里面没有出现大量 key 过期
  • redis 正常运行

2.3 缓存击穿发生的原因

  • 热点数据失效:某一热点数据的缓存突然失效,导致大量请求直接绕过缓存查询数据库
  • 并发访问:对该热点数据的并发访问增加,使得在缓存失效后,大量请求同时涌入

2.4 解决方案

key 可能会在某些时间点被超高并发地访问,是一种非常 “热点” 的数据

  • 预先设置热门数据:在 redis 高峰访问之前,把一些热门数据提前存入到 redis 里面,加大这些热门数据 key 的时长
  • 实时调整:现场监控哪些数据热门,实时调整 key 的过期时长
  • 使用锁:

就是在缓存失效的时候(判断拿出来的值为空),不是立即去 load db
①先使用缓存工具的某些带成功操作返回值的操作(比如 Redis 的 SETNX)去 set 一个 mutex key
②当操作返回成功时,再进行 load db 的操作,并回设缓存,最后删除 mutex key;
③当操作返回失败,证明有线程在 load db,当前线程睡眠一段时间再重试整个 get 缓存的方法。

3、Redis缓存雪崩

指的是缓存层出现大规模失效,导致大量请求直接访问后端存储系统,造成存储系统压力骤增,甚至引起宕机

3.1 问题详细描述

key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮

缓存雪崩与缓存击穿的区别在于这里针对很多 key 缓存,前者则是某一个 key 正常访问

3.2 缓存雪崩的条件

  • 大规模的缓存数据集中在同一时间段内失效
  • 系统中存在某种依赖关系,使得多个缓存数据之间存在相关性,一旦其中一个失效,其余的也可能会失效

3.3 缓存雪崩的原因

  • 相似过期时间: 缓存数据集中的很多数据设置了相似的过期时间,导致它们在同一时间内失效
  • 服务器宕机重启: 当服务器宕机并重新启动时,所有缓存都需要重新加载,此时如果大量缓存同时失效,就容易引发雪崩效应
  • 数据热点: 如果系统中存在热点数据,一旦这些数据失效,将导致大量请求直接访问数据库,增加数据库负担

3.4 解决方案

  • 构建多级缓存架构:nginx 缓存 + redis 缓存 + 其他缓存(ehcache 等)
  • 使用锁或队列:用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上,该方法不适用高并发情况
  • 设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际 key 的缓存
  • 将缓存失效时间分散开:比如可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件

四、总结

1、RDB与AOF持久化区别

RDB 是 Redis 的一种持久化方式,它通过将内存中的数据以快照的形式保存到硬盘上的文件中。这个过程是周期性的,可以根据配置的条件来自动触发

AOF 是另一种持久化方式,它记录了对 Redis 服务器执行的所有写操作,以追加的方式写入到文件中

区别 RDB持久化 AOF持久化
数据完整性  RDB 是周期性的快照 AOF 则是记录每一次写操作,可提供更好的数据完整性和安全性
恢复速度 RDB是快照模式,恢复大量数据更快 AOF 则需要逐条重放命令,较慢
文件大小 比AOF小 比RDB大,因为AOF记录了每一次写操作
故障恢复 较差 更好
兼容性 较差 更好


2、RDB与AOF持久化过程

RDB:①内存中 ----> 写入磁盘中保存的方式

           ②结果数据 ----> 写入磁盘中保存数据对象

           ③内存 ----> 写入磁盘后,会进行压缩,来减小 “*.rdb” 的磁盘占用空间量

AOF:①内存 ----> append 追加的缓存区 ----> 调用cpu资源来写入到磁盘中

           ②操作日志记录中执行的语句 ----> 追加到缓存区 ----> 调用cpu资源来写入到磁盘中

           ③内存 ----> 缓存 ----> 磁盘写入后会周期性的重新,跳过一些无效操作来保存

3、RDB与AOF触发方式

RDB:①手动触发:可以通过向 Redis 服务器发送 save 或 bgsave 命令来手动触发 RDB 持久化

           ②自动触发: save m n(假设 save 900 60 则 表示900s内60条语句执行,则触发RDB持久化)

           ③特殊触发:在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点;当收手动关闭redis时(如shutdown),会进行RDB持久化的方式,但kill进程,不会触发RDB持久化

AOF:①手动触发: 每次执行写命令时都会将相应的命令追加到 AOF 文件中,从而实现持久化

           ②自动触发:

          appendfsync always:每条语句,同步执行持久化(有强制一致性要求的场景)

          appendfsync no:不进行持久化

          appendfsync everysec:每秒进行一次AOF持久化(建议使用的,负载均衡的场景)

4、 RDB与AOF优先级

RDB 和 AOF 持久化方式可以同时开启。当两者都开启时,Redis 会优先使用 AOF 文件来恢复数据,因为 AOF 文件包含了更加完整的历史操作记录,可以提供更好的数据完整性和安全性。如果 AOF 文件不存在或损坏,则会使用 RDB 文件来进行数据恢复

因此,AOF 的优先级高于 RDB

5、缓存穿透、击穿、雪崩区别

区别 缓存穿透 缓存击穿 缓存雪崩
概念 请求的数据在数据库中不存在,导致每次请求都要访问数据库 某个热点数据突然失效,导致大量请求直接访问数据库 缓存层大规模失效,导致大量请求直接访问数据库
针对情况 针对不存在的数据请求 针对热点数据失效的情况 整个缓存层失效的情况
解决方法 使用布隆过滤器或者在数据库中也保存一个空对象的缓存 使用加锁或者短暂的缓存过期时间 设置不同的缓存失效时间、使用多级缓存或者熔断机制等方式来应对
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_71815887/article/details/137276422

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签