一、Redis 持久化机制
Redis 是个基于内存的数据库。那服务一旦宕机,内存中数据必将全部丢失。所以丢失数据的恢复对于 Redis 是十分重要的,我们首先想到是可以从数据库中恢复,但是在由 Redis 宕机时(说明相关工作正在运行)且数据量很大情况下,从数据库恢复的话,会为数据库带来巨大的压力,进而导致程序相应缓慢。因此实现数据的持久化,避免从后端数据库中恢复数据,对于Redis 是十分必要的。
此外,Redis 可以通过创建快照来获得存储在内存里面的数据。创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用,其中 Redis 最常用的快照持久化机制分为两种,即 RDB 与 AOF。
1、Redis 持久化机制 RDB
RDB 持久化可以手动执行也可以根据配置定期执行,它的作用是将某个时间点上的数据库状态保存到 RDB 文件中,RDB 文件是一个压缩的二进制文件,通过它可以还原某个时刻数据库的状态。由于RDB文件是保存在硬盘上的,所以即使 Redis 崩溃或者退出,只要 RDB 文件存在,就可以用它来恢复还原数据库的状态。
可以通过 SAVE 或者 BGSAVE 来生成 RDB 文件:
- SAVE 命令会阻塞 Redis 进程,直到 RDB 文件生成完毕,在进程阻塞期间,redis 不能处理任何命令请求,这显然是不合适的。
- BGSAV E则是会 for k出一个子进程,然后由子进程去负责生成 RDB 文件,父进程还可以继续处理命令请求,不会阻塞进程。
2、Redis 持久化机制 AOF
AOF 和 RDB 不同,AOF 是通过保存 redis服务器所执行的写命令来记录数据库状态的。
AOF 通过追加、写入、同步三个步骤来实现持久化机制。
- 当 AOF 持久化处于激活状态,服务器执行完写命令之后,写命令将会被追加 append 到 aof_buf 缓冲区的末尾
- 在服务器每结束一个事件循环之前,将会调用 flushAppendOnlyFile 函数决定是否要将 aof_buf 的内容保存到AOF文件中,可以通过配置 appendfsync 来决定。
- always:aof_buf 内容写入并同步到 AOF 文件
- everysec:将 aof_buf 中内容写入到 AOF 文件,如果上次同步 AOF 文件时间距离现在超过1秒,则再次对 AOF 文件进行同步
- no:将 aof_buf 内容写入AOF文件,但是并不对 AOF 文件进行同步,同步时间由操作系统决定
- 如果不设置,默认选项将会是 everysec,因为 always 来说虽然最安全(只会丢失一次事件循环的写命令),但是性能较差,而 everysec 模式只不过会可能丢失1秒钟的数据,而 no 模式的效率和 everysec 相仿,但是会丢失上次同步 AOF 文件之后的所有写命令数据。
3、Redis 持久化机制 RDB 与 AOF 的区别
- 实现方式:RDB 持久化是通过将某个时间点 Redis 服务器存储的数据保存到 RDB 文件中来实现持久化的;AOF持久化是通过将 Redis 服务器执行的所有写命令保存到 AOF 文件中来实现持久化的;
- 文件体积:由上述实现方式可知,RDB 持久化记录的是结果,AOF 持久化记录的是过程,所以 AOF 持久化生成的 AOF 文件会有体积越来越大的问题,Redis 提供了 AOF 重写功能来减小 AOF 文件体积;
- 安全性:AOF 持久化的安全性要比 RDB 持久化的安全性高,即如果发生机器故障,AOF 持久化要比 RDB 持久化丢失的数据要少。因为 RDB 持久化会丢失上次 RDB 持久化后写入的数据,而 AOF 持久化最多丢失1s之内写入的数据(使用默认everysec 配置的话);
- 优先级:由于上述的安全性问题,如果 Redis 服务器开启了 AOF 持久化功能,Redis 服务器在启动时会使用 AOF 文件来还原数据,如果 Redis 服务器没有开启 AOF 持久化功能,Redis 服务器在启动时会使用 RDB 文件来还原数据,所以 AOF 文件的优先级比 RDB 文件的优先级高。
- | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
文件大小 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 根据策略决定 |
二、Redis 事务
1、Redis 事务
Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务机制,事务执行过程将一系列多个命令按照顺序一次性执行,并且在执行期间,事务不会被中断,也不会去执行客户端的其他请求,直到所有命令执行完毕。事务的执行过程如下:
- 服务端收到客户端请求,事务以 MULTI 开始
- 如果客户端正处于事务状态,则会把事务放入队列同时返回给客户端 QUEUED,反之则直接执行这个命令
- 当收到客户端 EXEC 命令时,WATCH 命令监视整个事务中的 key 是否有被修改,如果有则返回空回复到客户端表示失败,否则 Redis 会遍历整个事务队列,执行队列中保存的所有命令,最后返回结果给客户端
WATCH 的机制本身是一个 CAS 的机制,被监视的 key 会被保存到一个链表中,如果某个 key 被修改,那么 REDIS_DIRTY_CAS 标志将会被打开,这时服务器会拒绝执行事务。
2、Redis 事务相关命令
Redis 通过 MULTI、EXEC、DISCARD、WATCH 实现事务功能:
# MULTI 开始事务
> multi
OK
复制
MULTI 命令将 Redis 中的 Redis_multi 选项打开,让客户端从非事务状态变为事务状态
# 命令入队
> set bookName "LiZhengi"
QUEUED
> get bookName
QUEUED
> sadd tag "LiZhengi" "Old Book"
QUEUED
> smembers tag
QUEUED
复制
在 Redsi 进入事务状态后,Redis 命令并不是立即执行的,而是进入一个先进先出的事务队列。其中返回 QUEUED 表示这个命令已经入了事务队列。
# exec 提交事物
> exec
1) OK
2) "LiZhengi"
3) (integer) 2
4) 1) "LiZhengi"
2) "Old Book"
复制
可以看到:当执行 exec 命令时,Redis 根据客户端所保存的事务队列,事务队列中的命令以先进先出的方式执行。当 exec 命令执行完毕时,Redis 会将结果保存到一个回复队列,并将回复队列返回给客户端。客户端从事务状态退出,一个事务执行完毕。
# discard 取消事务
> multi
OK
> set bookName "LiZhengi"
QUEUED
> discard
OK
> get bookName
(nil)
复制
discard 取消一个事务的命令,表示这个事务被取消。客户端从事务状态退出,回到非事务状态,Redis_multi 选项关闭。
# watch 命令
watch 命令在事务开始之前监视任意数量的键:当调用 exce 命令执行事务时,如果任意一个被监视的键已经被其他客户端修改了,那么整个事务不再执行,直接返回失败。
3、关于 Pipeline
管道技术(Pipeline)是客户端提供的一种批处理技术,用于一次处理多个 Redis 命令,从而提高整个交互的性能。
通常情况下 Redis 是单行执行的,客户端先向服务器发送请求,服务端接收并处理请求后再把结果返回给客户端,这种处理模式在非频繁请求时不会有任何问题。
但如果出现集中大批量的请求时,因为每个请求都要经历先请求再响应的过程,这就会造成网络资源浪费,此时就需要管道技术来把所有的命令整合一次发给服务端,再一次响应给客户端,这样就能大大的提升了 Redis 的响应速度。
管道技术解决了多个命令集中请求时造成网络资源浪费的问题,加快了 Redis 的响应速度,让 Redis 拥有更高的运行速度。但要注意的一点是,管道技术本质上是客户端提供的功能,而非 Redis 服务器端的功能。
Pipeline 与 事务相比:
- pipeline 是客户端的行为,对于服务器来说是透明的,可以认为服务器无法区分客户端发送来的查询命令是以普通命令的形式还是以 pipeline 的形式发送到服务器的;
- 而事务则是实现在服务器端的行为,用户执行 MULTI 命令时,服务器会将对应这个用户的客户端对象设置为一个特殊的状态,在这个状态下后续用户执行的查询命令不会被真的执行,而是被服务器缓存起来,直到用户执行 EXEC 命令为止,服务器会将这个用户对应的客户端对象中缓存的命令按照提交的顺序依次执行。