文章目录
一、Redis持久化
1.1 概述
Redis 是内存数据库,即数据存储在内存。
如果不将内存中的数据保存到磁盘,一旦服务器进程退出,服务器中的数据也会消失。
这样会造成巨大的损失,所以 Redis 提供了持久化功能。
1.2 RDB
RDB,即 Redis DataBase。在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是 Snapshot 快照,恢复时是将快照文件直接读到内存里。
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。RDB 的缺点是最后一次持久化后的数据可能丢失。
RDB 保存的是 dump.rdb 文件
1.2.1 持久化触发机制
- 配置文件中默认的快照配置,建议多用一台机子作为备份,复制一份 dump.rdb。
- 保存配置:
- save:只管保存,其他不管,全部阻塞。
- bgsave:Redis 会在后台异步进行快照操作,快照同时还可以响应客户端请求。
- lastsave:获取最后一次成功执行快照的时间。
- 执行
flushall
命令,也会产生 dump.rdb 文件,但里面是空的,无意义 。 - 退出的时候也会产生 dump.rdb 文件。
1.2.2 如何恢复rdb文件
将备份文件 dump.rdb 移动到 redis 安装目录并启动服务即可。
本地数据库存放目录:
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" # 如果在这个目录下存在dump.rdb文件,启动时就会自动恢复其中的数据
1.2.3 优缺点
优点:
-
适合大规模的数据恢复。
-
对数据完整性和一致性要求不高时适用。
缺点:
- 在一定间隔时间做一次备份,所以如果 redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改。
- Fork 进程的时候,内存中的数据被克隆了一份,大致 2 倍的膨胀性,会占用空间。
1.3 AOF
AOF,即 Append Only File。以日志的形式来记录每个写操作,将 Redis 执行过的所有指令记录下来(读操作不记录),只许追加文件,但不可以改写文件,Redis 启动之初会读取该文件重新构建数据。换言之,Redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
AOF 保存的是 appendonly.aof 文件
1.3.1 恢复
正常恢复
- 启动:修改配置。修改默认的 appendonly no,改为 yes。
- 复制:将有数据的 aof 文件复制一份保存到对应目录(config get dir)。
- 恢复:重启 redis 然后重新加载。
异常恢复
- 启动:修改配置。修改默认的 appendonly no,改为 yes。
- 破坏:故意破坏 appendonly.aof 文件(写一些非 Redis 命令)。
- 修复:
redis-check-aof --fix appendonly.aof
进行修复。 - 恢复:重启 redis 然后重新加载。
1.3.2 重写
AOF 采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制。
当AOF文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩。
只保留可以恢复数据的最小指令集,可以使用命令 bgrewriteaof
。
重写原理
AOF 文件持续增长而过大时,会 Fork 出一条新进程来将文件重写(也是先写临时文件最后再 rename)。
遍历新进程的内存中数据,每条记录有一条的 set 语句。
重写 aof 文件的操作,并没有读取旧的 aof 文件,这点和快照有点类似。
触发机制
Redis 会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的 1 倍且文件大于 64M 时触发。
1.3.3 优缺点
appendonly no # 默认是不开启aof模式的,默认使用rdb方式持久化,在大部分情况下rdb完全够用
appendfilename "appendonly.aof" # 持久化文件的名字
# appendfsync always # 每次修改都会sync,消耗性能
appendfsync everysec # 每秒执行一次sync,可能会丢失这一秒的数据
# appendfsync no # 不执行sync,这个时候操作系统自己同步数据,速度最快
no-appendfsync-on-rewrite no # 重写
优点:
- 每次修改都同步,同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差,但数据完整性比较好。
- 每秒同步,异步操作,每秒记录 ,如果一秒内宕机,有数据丢失。
- 从不同步,效率最高。
缺点:
- 相同数据集的数据而言,AOF 文件要远大于 RDB 文件,恢复速度慢于 RDB。
- AOF 运行效率要慢于 RDB,每秒同步策略效率较好,不同步效率和 RDB 相同。Redis 默认的配置是 RDB 配置。
1.4 总结
- RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储。
- AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AO F命令以 Redis 协议追加保存每次写的操作到文件末尾,Redis 还能对 AOF 文件进行后台重写,使得 AOF 文件的体积不至于过大。
- 只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化。
- 同时开启两种持久化方式:
- 在这种情况下,当 redis 重启的时候会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。
- RDB 的数据不实时,同时使用两者时服务器重启也只会找 AOF 文件,那要不要只使用AOF呢?作者建议不要,因为 RDB 更适合用于备份数据库(AOF 在不断变化不好备份),快速重启,而且不会有 AOF 可能潜在的 Bug,留着作为一个万一的手段。
- 性能建议:
- 因为 RDB 文件只用作后备用途,建议只在 Slave(从节点) 上持久化 RDB 文件,而且只要 15 分钟备份一次就够了,只保留 save 900 1 这条规则。
- 如果开启 AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只 load 自己的AOF文件就可以了,代价一是带来了持续的 IO,二是AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 AOF rewrite 的频率,AOF重写的基础大小默认值 64M 太小了,可以设到 5G 以上,默认超过原大小 100% 大小重写可以改到适当的数值。
- 如果不开启 AOF ,仅靠 Master-Slave Repllcation(主从复制) 实现高可用性也可以,能省掉一大笔IO,也减少了 rewrite 时带来的系统波动。代价是如果 Master/Slave 同时挂掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB 文件,载入较新的那个(微博就是这种架构)。
二、Redis发布订阅
2.1 概述
Redis 发布订阅(pub / sub)是一种消息通信模式,发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
订阅/发布消息图:
第一个:消息发送者、第二个:频道、第三个:消息订阅者
频道和订阅频道的客户端之间的关系:
当有新消息通过 publish
命令发送给频道, 这个消息就会被发送给订阅它的客户端:
2.2 命令
这些命令被广泛用于构建即时通信应用,比如网络聊天室(chat room)和实时广播、实时提醒等。
2.3 实践
窗口1:消息订阅者
# 订阅一个频道wyc
127.0.0.1:6379> subscribe wyc
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "wyc"
3) (integer) 1
# 等待读取推送的消息
1) "message" # 消息
2) "wyc" # 频道名称
3) "hello world" 消息具体内容
1) "message" # 消息
2) "wyc" # 频道名称
3) "study redis" 消息具体内容
窗口2:消息发送者
# 发送者发布消息到频道wyc
127.0.0.1:6379> publish wyc "hello world"
(integer) 1
# 发送者发布消息到频道wyc
127.0.0.1:6379> publish wyc "study redis"
(integer) 1
2.4 原理
- Redis 是使用 C 实现的,通过分析 Redis 源码里的 pubsub.c 文件,可以了解发布和订阅机制的底层实现。
- Redis 通过 publish 、subscribe 和 psubscribe 等命令实现发布和订阅功能。
- 通过 subscribe 命令订阅某频道后,redis-server 里维护了一个字典,字典的键就是一个个 channel。
- 而字典的值则是一个链表,链表中保存了所有订阅这个 channel 的客户端。
- subscribe 命令的关键,就是将客户端添加到给定 channel 的订阅链表中。
- 通过 publish 命令向订阅者发送消息,redis-server 会使用给定的频道作为键,在它所维护的 channel 字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。
- pub / sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在 Redis 中,你可以设定对某一个 key 值进行消息发布及消息订阅,当一个 key 值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。
- 这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
使用场景:
- 实时消息系统
- 实时聊天(频道当作聊天室,将信息回显给所有人)
- 订阅、关注系统
稍微复杂的场景我们就会使用消息中间件(RabbitMQ、RocketMQ、Kafka等)