Redis支持事务吗?了解Redis的持久化机制吗?

Redis 支持事务吗?与关系型数据库事务的区别?

Redis 支持事务,但它的事务与 MSQL中的事务有所不同,MSOL中的事务主要支持 ACID 的特性,而 Redis中的事务主要保证的是多个命令执行的原子性,即所有的命令在一个原子操作中执行,不会被打断。还有一个很重要的点,就是 MySQL 中的事务是支持回滚的,而 Redis 中的事务是不支持回滚的。

Redis事务是指将多条命令加入队列,一次批量执行多条命令,每条命令会按顺序执行,事务执行过程中不会被其他客户端发来的命令所打断。也就是说,Redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

Redis事务和关系型数据库的事务不太一样,它不保证原子性,也没有隔离级别的概念。

事务不保证原子性,但是Redis命令本身是原子性的

  1. Redis事务没有隔离级别的概念:批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务里的查询要看到本事务的更新或其它事务的修改更新操作的问题。(Mysql里的事务的语句不是放入队列,而是直接执行)
  2. Redis不保证原子性:Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。

WATCH命令

WATCH命令可以监控一个或多个键,一旦其中有一个键被修改,之后的事务就不会执行(类似于乐观锁)。执行EXEC命令之后,就会自动取消监控。

java 复制代码
127.0.0.1:6379> watch name
OK
127.0.0.1:6379> set name 1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name 2
QUEUED
127.0.0.1:6379> set gender 1
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get gender
(nil)

比如上面的代码中:

  1. watch name开启了对name这个key的监控
  2. 修改name的值
  3. 开启事务a
  4. 在事务a中设置了namegender的值
  5. 使用EXEC命令进提交事务
  6. 使用命令get gender发现不存在,即事务a没有执行

使用UNWATCH可以取消WATCH命令对key的监控,所有监控锁将会被取消。

Redis事务支持隔离性吗?

Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。

Redis事务保证原子性吗,支持回滚吗?

Redis单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。

Redis 的 Lua 脚本功能是什么?如何使用?

Redis 的 Lua 脚本功能允许用户在 Redis 服务器端执行自定义的 Lua 脚本,以实现原子操作和复杂逻辑。其核心点包括:

  • 原子性:Lua 脚本的所有命令在执行过程中是原子的,避免了并发修改带来的问题。
  • 减少网络往返次数:通过在服务器端执行脚本,减少了客户端和服务器之间的网络往返次数,提高了性能。
  • 复杂操作:可以在 Lua 脚本中执行复杂的逻辑,比如批量更新、条件更新等,超过了单个 Redis 命令的能力。

例如常见基于 Redis 实现分布式锁就需要结合 lua 脚本来实现。

lua 本身是不具备原子性的,但由于 Redis的命令是单线程执行的,它会把整个|ua 脚本作为一个命令执行,会阻塞其间接受到的其他命令,这就保证了 lua 脚本的原子性。

Redis的持久化了解吗?

详细可以查看:https://www.seven97.top/database/redis/03-strategy1-persistence.html

持久化就是把内存的数据写到磁盘中,防止服务宕机导致内存数据丢失。

Redis支持两种方式的持久化,一种是RDB的方式,一种是AOF的方式。前者会根据指定的规则定时将内存中的数据存储在硬盘上 ,而后者在每次执行完命令后将命令记录下来。Redis 4.0 新增了 RDB 和 AOF 的混合持久化机制,一般将两者结合使用。

RDB方式

RDB是 Redis 默认的持久化方案。RDB持久化时会将内存中的数据写入到磁盘中,在指定目录下生成一个dump.rdb文件。Redis 重启会加载dump.rdb文件恢复数据。

bgsave是主流的触发 RDB 持久化的方式,执行过程如下:

  • 执行BGSAVE命令
  • Redis 父进程判断当前是否存在正在执行的子进程 ,如果存在,BGSAVE命令直接返回。
  • 父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞。
  • 父进程fork完成后,父进程继续接收并处理客户端的请求 ,而子进程开始将内存中的数据写进硬盘的临时文件
  • 当子进程写完所有数据后会用该临时文件替换旧的 RDB 文件

Redis启动时会读取RDB快照文件,将数据从硬盘载入内存。通过 RDB 方式的持久化,一旦Redis异常退出,就会丢失最近一次持久化以后更改的数据。

触发 RDB 持久化的方式:

  1. 手动触发 :用户执行SAVEBGSAVE命令。SAVE命令执行快照的过程会阻塞所有客户端的请求,应避免在生产环境使用此命令。BGSAVE命令可以在后台异步进行快照操作,快照的同时服务器还可以继续响应客户端的请求,因此需要手动执行快照时推荐使用BGSAVE命令。

  2. 被动触发

    • 根据配置规则进行自动快照,如SAVE 100 10,100秒内至少有10个键被修改则进行快照。
    • 如果从节点执行全量复制操作,主节点会自动执行BGSAVE生成 RDB 文件并发送给从节点。
    • 默认情况下执行shutdown命令时,如果没有开启 AOF 持久化功能则自动执行·BGSAVE·。

优点

  1. Redis 加载 RDB 恢复数据远远快于 AOF 的方式
  2. 使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis 的高性能

缺点

  1. RDB方式数据无法做到实时持久化 。因为BGSAVE每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本比较高。
  2. RDB 文件使用特定二进制格式保存,Redis 版本升级过程中有多个格式的 RDB 版本,存在老版本 Redis 无法兼容新版 RDB 格式的问题

Redis 在生成 RDB 文件时如何处理请求?

在 Redis 生成 RDB文件时是异步的(使用 bgsave 命令),采用了fork子进程的方式来进行快照操作,生成 RD8文件的过程由子进程执行,主进程维续处理客户端清求,所以可以保证 Redis在生成快照的过程中依然对外提供服务,不会影响正常请求。

生成 RDB 文件的时候,数据可以修改吗?

当然可以。主进程会正常处理客户端的请求,进行数据的修改,但数据被修改还叫快照吗?

此时就运用了写时复制的技术。当主进程 fork 出一个子进程后,并不会把主进程的所有内存数据重新复制一份给子进程,而是让主进程和子进程共享相同的内存页面。

底层的实现仅仅复制了页表,但映射的物理内存还是同一个。这样做可以加快 fork 的速度,减少性能损耗(fork会阻塞主进程)。

AOF方式

AOF(append only file)持久化:以独立日志的方式记录每次写命令,Redis重启时会重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是解决了数据持久化的实时性,AOF 是Redis持久化的主流方式。

默认情况下Redis没有开启AOF方式的持久化,可以通过appendonly参数启用:appendonly yes。开启AOF方式持久化后每执行一条写命令,Redis就会将该命令写进aof_buf缓冲区,AOF缓冲区根据对应的策略向硬盘做同步操作。

默认情况下系统每30秒 会执行一次同步操作。为了防止缓冲区数据丢失,可以在Redis写入AOF文件后主动要求系统将缓冲区数据同步到硬盘上。可以通过appendfsync参数设置同步的时机。

复制代码
appendfsync always //每次写入aof文件都会执行同步,最安全最慢,不建议配置
appendfsync everysec  //既保证性能也保证安全,建议配置
appendfsync no //由操作系统决定何时进行同步操作

接下来看一下 AOF 持久化执行流程:

  1. 所有的写入命令会追加到 AOP 缓冲区中。
  2. AOF 缓冲区根据对应的策略向硬盘同步。
  3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩文件体积的目的。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。
  4. 当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。

优点

  1. AOF可以更好的保护数据不丢失,可以配置 AOF 每秒执行一次fsync操作,如果Redis进程挂掉,最多丢失1秒的数据。
  2. AOF以append-only的模式写入,所以没有磁盘寻址的开销,写入性能非常高。

缺点

  1. 对于同一份文件AOF文件比RDB数据快照要大。
  2. 数据恢复比较慢。

RDF和AOF的区别?

  1. 记录的数据不一样:
    • RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据 ,而 AOF 文件记录的是命令操作的日志
    • AOF 文件的内容是操作命令 ;RDB 文件的内容是二进制数据
  2. 恢复数据和执行频率:
    • RDB是全量快照,恢复数据更快,AOF则需要额外执行操作命令,相对更慢。
    • RDB是全量快照,不宜频繁执行,而AOF数据文件更新比较及时,比RDB保存更完整的数据,这样在数据恢复时能够恢复尽量完整的数据,降低丢失数据的风险。因此发生故障时,RDB丢失的数据会比 AOF 持久化的方式更多
  3. 是否影响主进程
    • AOF的Always写回策略是主进程执行的,总是调用fsync函数;Everysec异步执行,不影响主线程;No则redis不控制写回,最终交给操作系统决定何时写回;不影响主线程。
    • RDB可以将工作交给子进程来做,此时Redis主线程还可以继续处理操作命令。

如果同时存在RDB文件和AOF文件,Redis会优先使用AOF文件进行数据恢复。

RDB和AOF如何选择?

RDB 比 AOF 的数据恢复速度快,但是快照的频率不好把握:

  • 如果频率太低,两次快照间一旦服务器发生宕机,就可能会比较多的数据丢失;
  • 如果频率太高,频繁写入磁盘和创建子进程会带来额外的性能开销。

因此可以使用混合持久化,混合持久化就是混合使用 AOF 日志和RDB

混合持久化工作在 AOF日志重写 过程中:

会把 Redis 的持久化数据,以 RDB 的格式写入到 AOF 文件的开头,之后写时复制时修改数据再以 AOF 的格式化追加的文件的末尾,写入完成后再新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。

优点:

  • 混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的恢复数据,同时结合 AOF 的优点,减低了大量数据丢失的风险。

缺点:

  • AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;
  • 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了。