Redis数据持久化的两种方式以及Redis实现订阅发布

Redis的数据持久化方式

Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘中,那么一旦服务器进程退出,那么服务器中的数据库状态也会消失,里面的数据同时会丢失,因此Redis提供了持久化功能。

在主从复制中,RDB就是用来备用的(在从机上)。

Redis的数据持久化方式有两种,分别是RDB方式和AOF方式,下面我们分别来介绍一下这两种方式。

一、RDB方式(Redis DataBase)

1、什么是RDB?

将 Redis 在内存中的数据库状态保存到磁盘里面,RDB 文件是一个经过压缩的二进制文件,通过该文件可以还原生成 RDB 文件时的数据库状态 ( 默认下,持久化到dump.rdb 文件,并且在 redis 重启后,自动读取其中文件,据悉,通常情况下一千万的字符串类型键,1GB 的快照文件,同步到内存中的 时间是 20-30 秒)。通俗的说就是在指定的时间间隔内将内存中的数据集以快照的方式写入到磁盘中,也就是行话讲的Snapshot快照,它恢复数据时就将快照文件直接读到内存里就可以了。

2、RDB持久化过程介绍

在这里插入图片描述
Redis首先会单独创建(fork)一个子进程来进行持久化,子进程会将所有数据写入到一个临时文件中,这个临时文件就是临时的RDB文件,这个文件要去做持久化操作,等到持久化过程结束以后,就将这个RDB临时文件替换上次持久化好的文件,也就会生成一个正式的RDB文件。在整个过程中,主线程是不进行任何IO操作的,这样就确保了极高的性能

应用:
如果需要进行大规模数据的恢复,且对数据恢复的完整性不是很敏感,那么RDB方式比AOF方式要更加的高效。但是RDB的缺点:就是最后一次持久化宕机了,数据可能会丢失,Redis默认的持久化方式就是RDB,我们一般不需要去修改这个配置。

3、配置文件中关于RDB的配置

rdb保存的文件名为是 :dump.rdb ,这些都是在配置文件中的快照选项中进行配置的。
在这里插入图片描述
配置文件中,对于快照的持久化频率默认设置如下所示:

#设置Redis进行快照镜像的频率
save 900 1         #如果900秒(15分钟)内,至少有一个key进行了修改,我们就进行持久化操作(写入到数据库的持久化文件中)
save 300 10       #如果300秒内(6分钟),有10个key进行了修改,就进行持久化操作
save 60 10000   #如果60秒内(1分钟),有10000个key进行了修改,就进行持久化操作(多线程)

4、RDB触发机制

  • 配置文件中save的规则满足的情况下,会自动触发rdb规则,产生rdb文件;
  • 当执行flushall命令的时候,也会触发rdb规则,产生rdb文件;
  • 退出Redis的时候,也会产生rdb文件。

备份就会自动生成一个dump.rdb文件。

5、如何恢复rdb文件?

  • 只要将dump.rdb文件放到我们redis的启动目录即可,redis在启动的时候会自动检查dump.rdb恢复其中的数据。
  • 使用config get dir命令可以查看启动目录,只要dump.rdb文件在这个目录下,启动就会自动恢复其中的数据。
    在这里插入图片描述

6、RDB手动执行命令SAVE和BGSAVE的介绍

  • SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求;
  • BGSAVE命令会派生(fork)出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求。(一般使用这种方式)
  • 在创建RDB文件未结束之前,也就是数据持久化没有完成之前,客户端再执行SAVE或者BGSAVE命令,都会被服务器拒绝,

7、应用场景以及缺点

  • 适用于大规模的数据恢复;
  • 对数据完整性不高的场合。

在生产环境中我们会将dump.rdb文件进行备份。

缺点:

  • 需要一定的时间间隔进行操作。
  • 如果Redis意外宕机了,最后一次修改数据就没了。
  • fork子进程的时候,会占用一定的内存空间。

二、AOF方式(Append Only File)

将我们所有写命令都记录下来,history,恢复的时候就把这个文件全部执行一遍。

1、AOF方式的工作原理

它是以日志的形式来记录每个写操作,将Redis执行过的所有指令都记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换而言之,Redis重启之后会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

AOF方式默认就是文件的无限追加,这样会导致文件会越来越大。

2、AOF持久化过程

在这里插入图片描述

首先父进程回去fork一个子进程,然后子进程就会根据内存中的数据快照将数据重新写入到一个AOF的临时文件,然后父进程就会将关于写的命令缓存起来并且将写命令写入到原来的AOF文件,当子进程写入完成之后就会通知父进程,父进程收到通知后将缓存中的写命令写入到AOF临时文件中,之后父进程再将该临时文件替换掉原来的AOF文件并且进行重命名完成持久化操作,最后如果后面再出现写命令就都往新的AOF文件中去追加。

3、配置文件中关于AOF的配置

AOF保存的文件名为:appendonly.aof,该方式默认是不开启的,如果需要使用AOF方式,就需要在配置文件中手动开启,配置详情如下所示:

#开启aof模式的配置,默认是不开启,因为Redis默认是使用rdb方式持久化的,在大部分的情况下,rdb完全够用了。
appendonly no

#aof持久化的文件名字
appendfilename "appendonly.aof"

#配置持久化同步sync的选项(持久化策略),默认是everysec每秒同步一次
# appendfsync always     #  每次修改都会同步sync ,这种方式比较耗性能
appendfsync everysec    #  每一秒执行一次同步sync,可能会丢失这1s的数据。
# appendfsync no           #  不执行同步sync,这个时候操作系统自己同步数据,速度最快。
#是否进行重写选项。在 aof 重写或者写入 rdb 文件的时候,会执行大量 IO,此时对于 everysec 和 always 的 aof 模式来说,执行同步(fsync) 会造成阻塞过长时间,no-appendfsync-on-rewrite 字段设置为默认设置为 no。如果对延迟要求很高的应用,这个字段可以设置为 yes,否则还是设置为 no,这样对持久化特性来说这是更安全的选择。设置为 yes 表示 rewrite 期间对新写操作不同步fsync,暂时存在内存中,等 rewrite 完成后再写入。
#默认为 no,建议 no,可以保证数据的安全性。Linux 的默认 fsync 策略是 30 秒。可能丢失 30 秒数据。
no-appendfsync-on-rewrite no

#aof文件的自动重写配置。当目前的aof文件大小超过上一次重写的aof文件大小的百分之多少的时候进行重写,当aof文件增长到一定大小的时候,Redis能够调用bgrewriteaof对日志进行重写。默认设置为100,设为100意思就是当前aof文件大小是上次日志重写的aof文件大小的两倍时,自动启动新的日志重写过程。
auto-aof-rewrite-percentage 100

#允许重写最小aof文件的大小设置,如果超过了64MB就会去写一些其它的文件。
auto-aof-rewrite-min-size 64mb

#指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,设置为yes会log并继续,设置为no会直接恢复失败
aof-load-truncated yes

#加载redis时,可以识别AOF文件以“redis”开头。
#字符串并加载带前缀的RDB文件,然后继续加载AOF尾巴
aof-use-rdb-preamble yes

AOF方式默认是不开启的,我们需要进行手动配置,只需要将appendonly no中的no改为yes就开启了AOF方式,然后重启Redis生效了。

4、如果appendonly.aof文件有问题、被破坏了或者破损了怎么解决?

当appendonly.aof文件被破坏时,我们连接Redis时会报以下错误(拒绝连接):
在这里插入图片描述
这是因为appendonly.aof文件有问题,Redis是启动不了的,所以我们需要修复这个aof文件。Redis给我们提供了一个redis-check-aof工具,可以对appendonly.aof文件进行修复。 该文件就在bin目录下。
命令:redis-check-aof --fix appendonly.aof
在这里插入图片描述
执行该命令后我们就可以看见AOF文件修复成功,再次连接就可以了。

5、优点和缺点

(1)优点:

  • 每一次修改都同步,文件的完整性会更好;
  • 每秒同步一次,可能会丢失一秒的数据;
  • 从不同步,效率最高;

(2)缺点:

  • 相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢;
  • AOF运行效率比RDB慢,所以Redis默认的配置是RDB。

扩展

1、RDB持久化方式能够在指定的时间间隔内对你的数据进行快照存储;

2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Redis协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大;

3、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你可以不使用任何持久化。

4、同时开启两种持久化方式

  • 在这种情况下,当Redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

  • RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?这里建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的BUG,留着RDB作为以防万一的准备。

5、性能建议

  • 因为RDB文件只用作后备用途,建议只在Slave(从机)上持久化RDB文件,而且只要15分钟备份一次就够了,只保留额save 900 1 这一条规则。

  • 如果Enable AOF,好处就是在最恶劣的情况下也只会丢失不超过两秒的数据,启动脚本较简单,只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞机会是不可避免的,只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设置到5G以上,默认超过元大小100%大小重写可以改到适当的数值。

  • 如果不Enable AOF,仅靠Master-Slave Repllcation实现高可用也可以,能省掉一大笔IO,同时也减少了reweite时带来的系统波动,代价是如果Master/Slave同时倒掉(断电),会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件哪个更新,然后载入较新的那个,微博就是这种架构。

Redis的发布订阅

Redis发布订阅(pub/sub)是一种消息通信模式,发送者(pub)发送消息,订阅者(sub)接受消息。Redis客户端可以订阅任意数量的频道。

比如微信、微博、关注系统等等。

订阅/发布模型

在这里插入图片描述
消息发布者首先将消息发布到频道(Redis server)上,然后频道会对订阅者进行消息发布,只要是订阅了该频道的用户(消息订阅者)都会接受到从频道中发过来消息,如果没有订阅该频道就无法收到消息。

举个例子:比如说微信的公众号推送文章,当作者写好一篇文章之后,就将文章发布到公众号上,然后关注了该公众号的用户就会接收到该公众号发送过来的信息。

整个过程中,作者相当于就是图中的消息发布者,然后公众号就相当于频道,关注了该公众号(频道)的用户就是消息订阅者。

订阅关系介绍

1、下图中展示了频道channel1,以及订阅这个频道的三个客户端—client2、client5和client1之间的关系。
在这里插入图片描述
2、当有新消息通过PUBLISH命令发送给频道channel1时,这个消息就会被发送给订阅它的三个客户端:
在这里插入图片描述

3、相关命令介绍

(1)PSUBSCRIBE pattern [pattern .....]:订阅一个或者多个符合给定模式的频道。

(2)PUBSUB subcommand [argument [argument ....]]:查看订阅与发布系统状态。

(3)PUBLISH channel message:将信息message发送到指定的频道channel。

(4)PUNSUBSCRIBE [pattern [pattern ....]]:退订所有给定模式的频道。

(5)SUBSCRIBE channel [channel ....]:订阅给定的一个或者多个频道的信息。

(6)UNSUBSCRIBE [channel [channel ....]]:指退订给定的频道

以上命令被广泛用于构建即时通信应用,比如:网络聊天室(chatroom)和实时广播、实时提醒等。

4、测试:

首先准备两个客户端,一个用于消息发布者(pub)角色,一个用于消息订阅者(sub)角色。
在这里插入图片描述
(1)订阅者订阅java频道:
在这里插入图片描述
(2)发布者在java频道发布消息:
在这里插入图片描述
(3)订阅者收到来自Java频道的消息:
在这里插入图片描述

5、原理:

  • Redis是使用C实现的,通过分析Redis源码中的pubsub.c文件,了解发布和订阅机制的底层实现。

  • Redis通过publish、subscribe和psubsctibe等命令实现发布和订阅功能。

  • 通过sunsctibe命令订阅某频道后,redis-server里维护了一个字典,字典的键就是一个个channel,而字典的值则是一个链表,链表中保存了所有订阅这个channel的客户端。subscribe命令的关键就是将客户端添加到给定的channel的订阅链表中。

  • 通过publish命令向订阅者发送消息,redis-server会使用给定的频道作为键,在它所维护的channel字典中查找了记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。

  • Pub/Sub从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布以及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。

6、使用场景

  • 实时消息系统。
  • 实时聊天(频道当作聊天室,将信息回显给所有人即可)。
  • 订阅,关注系统都是可以的。

稍微复杂的场景就会使用消息中间件MQ。

创作不易,如果本文对你有帮助,可以点个赞支持一下。

猜你喜欢

转载自blog.csdn.net/weixin_43246215/article/details/108068797