Redis持久化
RDB (Redis DataBase)
RDB(Redis 数据库):RDB 持久性以指定的时间间隔执行数据集的时间点快照。实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件就称为RDB文件(dump.rdb),其中,RDB就是Redis DataBase的缩写。
可以用来在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot内存快照,它恢复时再将硬盘快照文件直接读回到内存里。Redis的数据都在内存中,保存备份时它执行的是全量快照,也就是说,把内存中的所有数据都记录到磁盘中,一锅端。Rdb保存的是dump.rdb文件。
配置:
Redis6.0.16以下
Redis6.2以及Redis-7.0.0
操作步骤:
自动触发
Redis7版本,按照redis.conf里配置的save < seconds > < changes >
本次案例5秒2次修改
修改dump文件保存路径
修改dump文件名称
触发备份
第一种情况
第二种情况
如何恢复
1.将备份文件(dump.rdb)移动到redis安装目录并启动服务即可
2.备份成功后故意用flushdb清空redis,看看是否可以恢复数据(结论:执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的,无意义)
3.物理恢复,一定服务和备份分机隔离B
手动触发:
save和bgsave:
Redis提供了两个命令来生成RDB文件,分别是save和bgsave,save在主程序中执行会阻塞当前redis服务器,直到持久化工作完成,执行save命令期间,Redis不能处理其他命令,线上禁止使用。
BGSAVE(默认)
Redis会在后台异步进行快照操作,不阻塞,快照同时还可以响应客户端请求,该触发方式会fork一个子进程由子进程复制持久化过程。Redis会使用bgsave对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主进程同时可以修改数据。在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,尽量避免膨胀。
可以通过lastsave命令获取最后一次成功执行快照的时间
优势:
适合大规模的数据恢复,按照业务定时备份,对数据完整性和一致性要求不高,RDB文件在内存中的加载速度要比AOF快得多
劣势:
在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失从当前至最近一次快照期间的数据,快照之间的数据会丢失。内存数据的全量同步,如果数据量太大会导致I/O严重影响服务器性能。RDB依赖于主进程的fork,在更大的数据集中,这可能会导致服务请求的瞬间延迟。fork的时候内存中的数据被克隆了士份,大致2倍的膨胀性,需要考虑。
数据丢失案例:
正常录入数据
kill -9故意模拟以外down机
redis重启恢复,查看数据是否丢失
如何检查修复dump.rdb文件
哪些情况会触发RDB快照
1.配置文件中默认的快照配置手动save/bgsave命令
2.执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的,无意义
3.执行shutdown且没有设置开启AOF持久化
4.主从复制时,主节点自动触发
如何禁用快照:
1.动态所有停止RDB保存规则的方法:redis-cli confia set save “”
2.快照禁用
RDB优化配置项详解
配置文件SNAPSHOTTING模块
stop-writes-on-bgsave-errorr
dbcompression
rdbchecksum
rdb-del-sync-files
总结:
AOF (Append only File)
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。默认情况下,redis是没有开启AOF(append only file)的。开启AOF功能需要设置配置: appendonly yes。Aof保存的是appendonly.aof文件
AOF持久化流程:
AOF缓冲区三种写回策略:Always(同步写回,每个写命令执行完立刻同步地将日志写回磁盘),everysec(每秒写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔1秒把缓冲区中的内容写入磁盘),no(操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘)
案例演示和说明
开启AOF
使用默认写回策略
aof文件-保存路径
Redis6 :AOF保存文件的位置和RDB保存文件的位置一样,都是通过redis.conf配置文件的dir配置
redis7之后最新
最终路径:
aof文件-保存名称
redis 6,有且只有一个名称
Redis7.0 Multi Part AOF的设计
数据恢复:
正常恢复:修改默认的appendonly no,改为yes,写操作继续,生成aof文件到指定的目录
恢复1:重启redis然后重新加载,结果OK
恢复2:
写入数据进redis,然后flushdb+shutdown服务器
新生成了dump和aof
备份新生成的aof.bak,然后删除dump/aof再看恢复
重启redis然后重新加载试试?? ?
停止服务器,拿出我们的备份修改后再重新启动服务器看看
异常恢复:
故意乱写正常的AOF文件,模拟网络闪断文件写error
重启Redis 之后就会进行AOF文件的载入,发现启动都不行,
异常修复命令:redis-check-aof --fix进行修复
重新OK
优势:更好的保护数据不丢失、性能高、可做紧急恢复
劣势:相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb。aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同
AOF重写机制
启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。
触发机制:
自动触发:满足配置文件中的选项后,Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时。
手动触发:客户端向服务器发送bgrewriteaof命令
启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。
举个例子:比如有个key
一开始你 set k1 v1
然后改成 set k1 v2
最后改成 set k1 v3
如果不重写,那么这3条语句都在aof文件中,内容占空间不说启动的时候都要执行一遍,共计3条命令;但是,我们实际效果只需要set k1 v3这一条,所以,开启重写后,只需要保存set k1 v3就可以了只需要保留最后一次修改值,相当于给aof文件瘦身减肥,性能更好。AOF重写不仅降低了文件的占用空间,同时更小的AOF也可以更快地被Redis加载。
重写原理:1:在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
2:与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
3:当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中
4:当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中
5:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
AOF优化配置项
配置文件APPEND_ONLY_MODE模块
总结:
RDB-AOF混合持久化
1.RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
2.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.。
同时开启两种持久化方式:
在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),留着rdb作为一个万一的手段。
推荐方式:
结合了RDB和AOF的优点,既能快速加载又能避免丢失过多的数据。
1 开启混合方式设置
设置aof-use-rdb-preamble的值为 yes yes表示开启,设置为no表示禁用
2 RDB+AOF的混合方式---------> 结论:RDB镜像做全量持久化,AOF做增量持久化
先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。----》AOF包括了RDB头部+AOF混写
纯缓存模式
同时关闭RDB+AOF
save “” :禁用rdb,禁用rdb持久化模式下,我们仍然可以使用命令save、bgsave生成rdb文件
appendonly no:禁用aof,禁用aof持久化模式下,我们仍然可以使用命令bgrewriteaof生成aof文件
Redis事务
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。可以用来在一个队列中,一次性、顺序性、排他性的执行一系列命令。
Redis事务VS数据库事务
怎么玩?
常用命令:
case1: 正常执行(MULTI,EXEC)
Case2:放弃事务(MULTI,DISCARD)
Case3:全体连坐
Case4:冤头债主
注意和传统数据库事务区别,不一定要么一起成功要么一起失败
Case5: watch监控
Redis使用Watch来提供乐观锁定,类似于CAS(Check-and-Set)。
悲观锁: 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
乐观锁:乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁策略:提交版本必须 大于 记录当前版本才能执行更新。
CAS:
watch:1.初始化k1和balance两个key,先监控再开启multi,保证两key变动在同一个事务内
2.有加塞篡改
watch命令是一种乐观锁的实现,Redis在修改的时候会检测数据是否被更改,如果更改了,则执行失败。第一个窗口蓝色框第5步执行结果返回为空,也就是相当于是失败,笔记见最下面官网说明
unwatch:
小结:
—旦执行了exec之前加的监控锁都会被取消掉了
当客户端连接丢失的时候(比如退出链接),所有东西都会被取消监视
小总结:
开启:以MULTI开始一个事务
入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
执行:由EXEC命令触发事务
Redis管道
面试题:如何优化频繁命令往返造成的性能瓶颈?
问题由来:
管道(pipeline)可以一次性发送多条命令给服务端,服务端依次处理完完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。pipeline实现的原理是队列,先进先出特性就保证数据的顺序性。
Pipeline是为了解决RTT往返回时,仅仅是将命令打包一次性发送,对整个Redis的执行不造成其它任何影响。批处理命令变种优化措施,类似Redis的原生批命令(mget和mset)。
案例演示:
小总结:
Pipeline与原生批量命令对比:
1.原生批量命令是原子性(例如:mset,mget), pipeline是非原子性
2.原生批量命令一次只能执行一种命令,pipeline支持批量执行不同命令
3.原生批命令是服务端实现,而pipeline需要服务端与客户端共同完成
Pipeline与事务对比:
1.事务具有原子性,管道不具有原子性
2.管道一次性将多条命令发送到服务器,事务是一条一条的发,事务只有在接收到exec命令后才会执行,管道不会执行事务时会3.阻塞其他命令的执行,而执行管道中的命令时不会
使用Pipeline注意事项:
1.pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发生异常,将会继续执行后续的指令
2.使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务端此时也被迫回复一个队列答复,占用很多内存
Redis发布订阅(了解即可)
是一种消息通信模式:发送者(PUBLISH)发送消息,订阅者(SUBSCRIBE)接收消息,可以实现进程间的消息传递。Redis可以实现消息中间件MQ的功能,通过发布订阅实现消息的引导和分流。不推荐使用该功能,专业的事情交给专业的中间件处理,redis就做好分布式缓存功能
能干嘛:
Redis客户端可以订阅任意数量的频道,类似我们微信关注多个公众号,
当有新消息通过PUBLISH命令发送给频道channel1时
小总结:
常用命令:
SUBSCRIBE channel [channel …]
1.订阅给定的一个或多个频道的信息
2.推荐先执行订阅后再发布,订阅成功之前发布的消息是收不到的
3.订阅的客户端每次可以收到一个3个参数的消息:1.消息的种类2.始发频道的名称3.实际的消息内容
PUBLISH channel message:发布消息到指定的频道
PSUBSCRIBE pattern [pattern …]:按照模式批量订阅,订阅一个或多个符合给定模式(支持*号?号之类的)的频道
PUBSUB subcommand [argument [argument …]]:
1.查看订阅与发布系统状态
2.PUBSUB CHANNELS:由活跃频道组或的列表
3.PUBSUB NUMSUB [channel [channel …]]:某个频道有几个订阅者
4.PUBSUB NUMPAT:只统计使用PSUBSCRIBE命令执行的,返回客户端订阅的唯一模式的数量
UNSUBSCRIBE [channel [channel …]]:取消订阅
PUNSUBSCRIBE [pattern [pattern …]]:退订所有给定模式的频道
案例演示:
开启3个客户端,演示客户端A、B订阅消息,客户端C发布消息
演示批量订阅和发布
取消订阅
小总结:
Redis可以实现消息中间件MQ的功能,通过发布订阅实现消息的引导和分流。不推荐使用该功能,专业的事情交给专业的中间件处理,redis就做好分布式缓存功能
Pub/Sub缺点:
1.发布的消息在Redis系统中不能持久化,因此,必须先执行订阅,再等待消息发布。如果先发布了消息,那么该消息由于没有订阅者,消息将被直接丢弃
2.消息只管发送对于发布者而言消息是即发即失的,不管接收,也没有ACK机制,无法保证消息的消费成功。
3.以上的缺点导致Redis的Pub/Sub模式就像个小玩具,在生产环境中几乎无用武之地,为此Redis5.0版本新增了Stream数据结构,不但支持多播,还支持数据持久化,相比Pub/Sub更加的强大