Redis 高性能、高可用机制

本文深入探讨了 Redis 的高性能特性,包括单线程模型、I/O 多路复用机制和数据持久化策略。Redis 通过 AOF 日志和 RDB 快照实现数据持久化,保证服务重启后的数据恢复。此外,文章详细阐述了 Redis 的高可用性,包括主从复制、哨兵模式和集群方案,确保在故障时能快速切换和恢复服务。
摘要由CSDN通过智能技术生成

1. Redis 高性能

  • Redis 的单线程
    Redis 单线程,主要指 Redis 的网络 I/O 线程,以及键值的 SET 和 GET 等读写操作都是由一个线程完成的。但 Redis 的持久化、集群同步等操作,则是由另外的线程来执行的。

  • Redis 采用单线程为什么还这么快?
    一般来说,单线程的处理能力应该比多线程差,但 Redis 还能达到每秒数万级的处理能力有如下几个原因:

    1. Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,比如哈希表(ziplist)和跳表。

    2. 单线程避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,避免同步机制的开销,也不会导致死锁问题。

    3. Redis 采用了 I/O 多路复用机制,处理大量的客户端 Socket 请求,让 Redis 可以高效地进行网络通信,因为 I/O 多路复用是基于非阻塞的 I/O 模型,就意味着 I/O 的读写流程不再阻塞。

      多路复用—附录 1

  • 线程模型

    • Redis 4.0 版本之前,使用单线程速度快的原因就是上述几个原因

    • Redis 4.0 版本之后,Redis 添加了多线程的支持,但这时的多线程主要体现在大数据的异步删除功能上,例如 unlink key、flushdb async、flushall async 等

      UNLINK 命令其实就是 DEL 的异步版本,它不会同步删除数据,而只是把 key 从 keyspace 中暂时移除掉,然后将任务添加到一个异步队列,最后由后台线程去删除,不过这里需要考虑一种情况是如果用 UNLINK 去删除一个很小的 key,用异步的方式去做反而开销更大,所以它会先计算一个开销的阀值,只有当这个值大于 64 才会使用异步的方式去删除 key,对于基本的数据类型如 List、Set、Hash 这些,阀值就是其中存储的对象数量。

    • Redis 6.0 版本之后,随着网络硬件的性能提升,采用多个 I/O 线程来处理网络请求,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上,所以为了提高网络请求处理的并行度,Redis 6.0 对于网络请求采用多线程来处理。但是对于读写命令,Redis 仍然使用单线程来处理。

      Redis 网络模型—附录 2

      https://zhuanlan.zhihu.com/p/356059845

2. Redis 高可用

2.1 数据持久化

Redis 如何实现数据不丢失?
缓存数据库的读写都是在内存中,所以它的性能才会高,但在内存中的数据会随着服务器的重启而丢失,为了保证数据不丢失,要把内存中的数据存储到磁盘,以便缓存服务器重启之后,还能够从磁盘中恢复原有的数据,这个过程就是 Redis 的数据持久化

Redis 的数据持久化有三种方式

2.1.1 AOF 日志

AOF 日志(Append Only File,文件追加方式):记录所有的操作命令,并以文本的形式追加到文件中,默认不会开启

MySQL 的日志是 WAL(Write Ahead Log)机制,“写前日志”,也就是在实际写数据之前,先把修改的数据记到日志文件中,以便当出现故障时进行恢复,比如 MySQL 的 redo log(重做日志),记录的就是修改后的数据。

AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的,不同的是,Redis 的 AOF 日志的记录顺序与 MySQL 数据库正好相反,它是写后日志,“写后”是指 Redis 要先执行命令,把数据写入内存,然后再记录日志到文件。整个过程可以分为三个阶段:

  • 命令传播:Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中。

  • 缓存追加:AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。

  • 文件写入和保存:

    写入:AOF 缓存中的内容被写入到 AOF 文件末尾
    保存:如果设定的 AOF 保存条件被满足的话, fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。

    AOF 保存策略—附录4

  • *AOF 后台重写(BGREWRITEAOF 命令)

    Redis 可以在 AOF体积变得过大时,自动地在后台(Fork子进程)对 AOF 进行重写,重写后的新 AOF文 件包含了恢复当前数据集所需的最小命令集合。

    AOF 重写原理过程—附录 5

为什么采用写后日志?

  1. Redis 在写入日志之前,不对命令进行语法检查;
  2. 只记录执行成功的命令,避免了出现记录错误命令的情况;
  3. 在命令执行完之后再记录,不会阻塞当前的写操作。

存在的风险:

  • 数据可能会丢失:如果 Redis 刚执行完命令,此时发生故障宕机,会导致这条命令存在丢失的风险。
  • 可能阻塞其他操作:虽然 AOF 是写后日志,避免阻塞当前命令的执行,但因为 AOF 日志也是在主线程中执行,所以当 Redis 把日志文件写入磁盘的时候,还是会阻塞后续的操作无法执行。
2.1.2 RDB 快照

RDB 快照(Redis DataBase):将某一时刻的内存数据,以二进制的方式写入磁盘。

由于 AOF 日志记录的是操作命令,不是实际的数据,所以用 AOF 方法做故障恢复时,需要全量把日志都执行一遍,一旦日志非常多,会造成 Redis 的恢复操作缓慢。

为了解决这个问题,可以使用 Redis RDB 内存快照(内存快照:就是将内存中的某一时刻状态以数据的形式记录在磁盘中)的操作,它即可以保证可靠性,又能在宕机时实现快速恢复。

和 AOF 不同的是,RDB 记录 Redis 某一时刻的数据,而不是操作,所以在做数据恢复时候,只需要直接把 RDB 文件读入内存,完成快速恢复。

触发方式

  • 符合自定义配置的快照规则

    在redis.conf中配置:save 多少秒内 数据变了多少
    
    save "" # 不使用RDB存储 不能主从
    save 900 1 # 表示15分钟(900秒钟)内至少1个键被更改则进行快照。 
    save 300 10 # 表示5分钟(300秒)内至少10个键被更改则进行快照。 
    save 60 10000 # 表示1分钟内至少10000个键被更改则进行快照。
    
  • 执行save或者bgsave命令

  • 执行flushall命令

  • 执行主从复制操作 (第一次时)

是否会阻塞主线程?
Redis 提供了两个命令来生成 RDB 快照文件,分别是 save 和 bgsave。save 命令在主线程中执行,会导致阻塞。而 bgsave 命令则会创建一个子进程,用于写入 RDB 文件的操作,避免了对主线程的阻塞,这也是 Redis RDB 的默认配置。

RDB 执行流程—附录6

RDB 生成快照时数据能否修改?

  • 如果此时可以执行写操作:意味着 Redis 还能正常处理写操作,就可能出现正在执行快照的数据是已经被修改了的情况;

  • 如果此时不可以执行写操作:意味着 Redis 的所有写操作都得等到快照执行完成之后才能执行,那么就又出现了阻塞主线程的问题。

Redis 利用 bgsave 的子进程

image-20210805105105387

  • 如果主线程执行读操作,则主线程和 bgsave 子线程互不影响;
  • 如果主线程执行写操作,则被修改的数据会复制一份副本,然后 bgsave 子进程会把该副本数据写入 RDB 文件,在这个过程中,主线程仍然可以直接修改原来的数据。

RDB 优点:二进制压缩文件,占用空间小,便于传输(传给slaver);主进程 fork 子进程,可以最大化 Redis 性能,但复制过程中主进程阻塞;恢复速度比 AOF 快

RDB 缺点:不保证数据完整性,会丢失最后一次快照以后更改的所有数据;fork 子进程时会消耗 CPU;阅读性差

2.1.3 混合持久化方式

混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDB 和 AOF 的优点。fork 出的子进程先将共享的内存副本全量数据以 RDB 的方式写入文件,再将后续的操作命令以 AOF 的格式存入文件,既保证了 Redis 重启速度,又降低数据丢失风险。

2.2 数据复制

Redis 如何实现服务的高可用?
“高可用性”(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性。可以采用 Redis 多机和集群的方式来保证Redis的高可用性。

2.2.1 主从同步 (主从复制)

解决数据高可用的手段是集群策略,集群实现依靠副本,而副本技术有个非常关键的一点,那就是各个副本之间的快速数据同步,也就是主从复制。

这是 Redis 高可用服务的最基础的保证,实现方案就是将从前的一台 Redis 服务器,同步数据到多台从 Redis 服务器上。在 Redis 中,任何节点都可以成为主节点,通过 Slaveof 命令可以开启复制。

作用:1. 主从复制一方面可以作为数据备份,通过实现主从节点之间的最终数据一致性,保证数据尽量不丢失。2. 除了数据备份,从节点扩展主节点的读请求支持能力,这样我们就可以对 Redis 做读写分离了,主节点作为写节点,从节点支持读请求,来承载更多的并发操作。

原理:与 MySQL 主从复制原理一样

主从同步原理—附录 7

2.2.2 Redis Sentinel(哨兵模式)

在使用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器出现故障宕机时,需要手动进行恢复,为了解决这个问题,Redis 增加了哨兵模式(因为哨兵模式做到了可以监控主从服务器,并且提供自动容灾恢复的功能)。当主服务器进入下线状态时,sentinel 可以将该主服务器下的某一从服务器升级为主服务器继续提供服务,从而保证 Redis 的高可用性。

image-20210805105319558

Redis-Sentinel 是一个独立运行的进程,假如主节点宕机,它还可以进行主从之间的切换。主要实现了以下的功能:

  • 不定期监控 Redis 服务运行状态

  • 发现 Redis 节点宕机,可以通知上游的客户端进行调整

  • 当发现 Master 节

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值