【缓存与加速技术实践】Redis 高可用

文章目录

Redis 高可用

在Redis的语境中,高可用不仅仅是保证服务器能够持续提供服务(如99.9%、99.99%、99.999%的可用性),还涵盖了数据的安全、持久性、扩展性以及快速故障恢复等多个方面。

1. 持久化

作用

  • 数据备份:将数据从内存保存到硬盘上,确保在Redis进程崩溃或服务器宕机时,数据不会丢失。
  • 数据恢复:在Redis重启后,可以从持久化文件中恢复数据,保证服务的连续性。

类型

  • RDB(Redis Database):定期将内存中的数据快照保存到磁盘。优点是速度快,文件小,适合用于备份;缺点是可能会丢失最后一次快照到崩溃之间的数据。
  • AOF(Append Only File):记录每次写操作,以日志的形式追加到文件中。优点是数据更完整,几乎不会丢失数据;缺点是文件可能较大,重写操作会影响性能。

解决的问题

  • 数据丢失问题:通过定期或实时地将数据保存到硬盘,确保数据的持久性。

2. 主从复制

作用

  • 数据多机备份:将主节点的数据复制到从节点,实现数据的冗余备份。
  • 读操作负载均衡:从节点可以处理读请求,减轻主节点的压力。
  • 故障恢复:在主节点故障时,可以手动将某个从节点提升为主节点,继续提供服务。

缺陷

  • 故障恢复无法自动化:需要手动进行故障切换。
  • 写操作无法负载均衡:所有写操作仍然只能由主节点处理。
  • 存储能力受到单机的限制:无法水平扩展存储能力。

解决的问题

  • 数据冗余备份:提高数据的可靠性。
  • 读操作负载均衡:提高系统的读性能。

3. 哨兵(Sentinel)

作用

  • 监控:监控主从节点的运行状态,包括健康状态、连接状态等。
  • 自动故障恢复:在主节点故障时,自动选择一个从节点提升为主节点,实现服务的自动恢复。
  • 通知:通过API或其他方式通知管理员或系统其他部分,以便进行进一步处理。

缺陷

  • 写操作无法负载均衡:写操作仍然只能由新的主节点(原从节点)处理。
  • 存储能力受到单机的限制:哨兵模式没有解决存储扩展的问题。

解决的问题

  • 自动化故障恢复:减少人工干预,提高系统的可用性。

4. Cluster集群

作用

  • 数据分片:将数据分布到多个节点上,实现数据的水平扩展。
  • 自动故障恢复:在节点故障时,通过集群内的选举机制自动进行故障恢复。
  • 负载均衡:无论是读操作还是写操作,都可以实现负载均衡,提高系统的整体性能。

解决的问题

  • 写操作负载均衡:通过数据分片,实现写操作的分散处理。
  • 存储能力扩展:通过增加节点,实现存储能力的线性扩展。
  • 自动化故障恢复:减少人工干预,提高系统的稳定性和可用性。

Redis的高可用方案涵盖了数据持久化、主从复制、哨兵和Cluster集群等多个方面。这些技术相互补充,共同构成了Redis的高可用体系。通过合理配置和使用这些技术,可以显著提高Redis服务的可靠性和性能。

持久化

Redis是内存数据库,数据存储在内存中。为了避免服务器断电等原因导致Redis进程异常退出后数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,可以利用持久化文件实现数据恢复。此外,为了进行灾难备份,还可以将持久化文件拷贝到一个远程位置。

持久化的方式

Redis提供两种持久化方式:RDB持久化和AOF持久化。

  1. RDB持久化

    • 原理:将Redis在内存中的数据库记录定时保存到磁盘上,生成快照文件(.rdb文件)。
    • 触发条件:RDB持久化的触发分为手动触发和自动触发两种。手动触发可以通过执行save命令或bgsave命令来实现。其中,save命令会阻塞Redis服务器进程,直到RDB文件创建完毕;而bgsave命令会创建一个子进程来负责创建RDB文件,父进程则继续处理请求。自动触发则是在配置文件中通过save m n来指定触发条件,当在m秒内发生n次变化时,会触发bgsave。
    • 优点:RDB文件是经过压缩的二进制文件,占用空间较小,恢复速度快。
    • 缺点:RDB持久化是定时保存快照,因此可能会丢失最后一次快照之后的数据。
  2. AOF持久化(Append Only File)

    • 原理:将Redis的操作日志以追加的方式写入文件。当Redis服务器重启时,可以通过重新执行这些命令来恢复数据。
    • 同步策略:AOF持久化可以配置同步策略,如每秒同步一次(everysec)或者每次写操作都同步(always)。其中,everysec策略是Redis的默认配置,相对来说兼顾安全性和性能。
    • 重写机制:为了避免AOF文件过大,Redis提供了重写机制。当AOF文件的大小超过所设定的阈值时,Redis会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。
    • 优点:AOF持久化可以记录每一次写操作,因此数据恢复时更加完整。
    • 缺点:AOF文件通常比RDB文件大,恢复速度较慢。同时,AOF持久化对性能有一定影响,因为每次写操作都需要追加到文件中。

数据恢复

当Redis出现问题时,可以通过以下方式进行数据恢复:

  1. 快照恢复:通过加载最新的RDB快照文件来恢复数据。
  2. AOF日志恢复:通过重新执行AOF文件中的写操作来恢复数据。

RDB 持久化

RDB 持久化是 Redis 提供的一种数据快照存储方式,它会在指定的时间间隔内将内存中的数据生成快照并保存到硬盘上。这种持久化方式主要依赖于 Redis 内部的 fork 机制和操作系统的写时复制技术。

触发条件

RDB 持久化的触发条件分为手动触发和自动触发两种:

  • 手动触发

    • save 命令:会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕。由于会阻塞服务器,通常不推荐在生产环境中使用。
    • bgsave 命令:会创建一个子进程来负责创建 RDB 文件,父进程则继续处理请求。这是生产环境中常用的方式。
  • 自动触发

    • 在 Redis 配置文件中,可以通过 save m n 来指定当在 m 秒内发生 n 次变化时,会触发 bgsave 进行快照。
    • 在主从复制场景下,如果从节点执行全量复制操作,主节点会执行 bgsave 命令,并将 RDB 文件发送给从节点。
    • 执行 shutdown 命令时,如果 AOF 持久化未开启或 AOF 文件为空,则会自动执行 bgsave
执行流程
  1. Redis 父进程判断当前是否在执行 savebgsave/bgrewriteaof 的子进程,如果是,则 bgsave 命令直接返回。
  2. 父进程执行 fork 操作创建子进程,这个过程中父进程是阻塞的。
  3. fork 完成后,父进程恢复执行,bgsave 命令返回"Background saving started"信息,并不再阻塞父进程。
  4. 子进程根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换。
  5. 子进程发送信号给父进程表示完成,父进程更新统计信息。
启动时加载

Redis 服务器在启动时会自动加载 RDB 文件来恢复数据。但需要注意的是,如果 AOF 持久化开启且 AOF 文件存在,Redis 会优先载入 AOF 文件来恢复数据。

AOF 持久化

AOF 持久化是 Redis 提供的另一种持久化方式,它将 Redis 执行的每次写、删除命令记录到单独的日志文件中,当 Redis 重启时再次执行 AOF 文件中的命令来恢复数据。

开启 AOF

Redis 服务器默认关闭 AOF 持久化,需要在配置文件中通过 appendonly yes 来开启。

执行流程

AOF 持久化的执行流程包括命令追加、文件写入和文件同步、文件重写三个部分:

  • 命令追加 :Redis 先将写命令追加到缓冲区 aof_buf,而不是直接写入文件。
  • 文件写入和文件同步 :根据不同的同步策略(alwaysnoeverysec),将 aof_buf 中的内容同步到硬盘。
  • 文件重写 :定期重写 AOF 文件,达到压缩的目的。重写过程中,Redis 会创建子进程进行重写操作,父进程继续处理请求,并将新的写命令追加到重写缓冲区 aof_rewrite_buf。重写完成后,用新的 AOF 文件替换旧的文件。
启动时加载

当 AOF 开启时,Redis 启动时会优先载入 AOF 文件来恢复数据。如果 AOF 文件不存在或损坏(但 aof-load-truncated 参数开启),Redis 会尝试使用 RDB 文件来恢复数据。

RDB 和 AOF 的优缺点

  • RDB 持久化

    • 优点:文件紧凑、体积小、恢复速度快、对性能影响小。
    • 缺点:无法做到实时持久化、数据可能会丢失、兼容性差。
  • AOF 持久化

    • 优点:支持秒级持久化、兼容性好、数据安全性高。
    • 缺点:文件大、恢复速度慢、对性能影响大、可能存在 AOF 追加阻塞问题。

redis性能管理

查看 Redis 内存使用

sh 复制代码
192.168.9.236:7001> info memory

内存碎片率

  • mem_fragmentation_ratio : 内存碎片率,计算公式为 used_memory_rss / used_memory
    • used_memory_rss: Redis 向操作系统申请的内存。
    • used_memory: Redis 中的数据占用的内存。
    • used_memory_peak: Redis 内存使用的峰值。

内存碎片产生原因 :

Redis 内部有自己的内存管理器,删除数据后,释放的内存空间由内存分配器管理,不会立即返回给操作系统。这导致操作系统记录的内存占用与实际可用内存不一致,形成内存碎片。

跟踪内存碎片率的重要性:

  • 碎片率在 1 到 1.5 之间是正常的。
  • 超过 1.5 表示 Redis 消耗了实际需要物理内存的 150%,其中 50% 是内存碎片。
  • 低于 1 表示 Redis 内存分配超出了物理内存,操作系统正在进行内存交换。

解决碎片率大的问题:

  • Redis 4.0 以下版本:

    sh 复制代码
    shutdown save

    重启服务器后,Redis 会将没用的内存归还给操作系统。

  • Redis 4.0 及以上版本:

    sh 复制代码
    config set activedefrag yes
    memory purge

开启自动内存碎片清理:

sh 复制代码
activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100
active-defrag-cycle-min 1
active-defrag-cycle-max 25
active-defrag-max-scan-fields 1000

内存使用率

当 Redis 实例的内存使用率超过可用最大内存,操作系统将开始进行内存与 swap 空间交换。
查看 Redis 内存是否发生 Swap:

sh 复制代码
redis-cli info | grep process_id
process_id: 5332

cat /proc/5332/smaps | egrep '^(Swap|Size)'

解决内存 Swap 的方法:

  • 设置 key 的过期时间。
  • 增加 Redis 集群的实例个数,分摊每个实例服务的数据量。
  • 设置 key 的过期时间。

回收 Key

当达到设置的最大阀值时,需选择一种 key 的回收策略,默认情况下回收策略是禁止删除。
配置文件中修改 maxmemory-policy 属性值:

sh 复制代码
vim /usr/local/redis/conf/redis.conf
  • allkeys-lru: 淘汰最近最少访问的 key。
  • volatile-lru: 淘汰最近最少访问且设置了过期时间的 key。
  • allkeys-random: 随机淘汰 key。
  • volatile-random: 随机淘汰设置了过期时间的 key。
  • allkeys-ttl: 淘汰即将过期的 key。
  • noeviction: 不淘汰任何 key,实例内存达到 maxmemory 后,再写入新数据直接返回错误。
  • allkeys-lfu: 淘汰访问频率最低的 key(4.0+版本支持)。
  • volatile-lfu: 淘汰访问频率最低且设置了过期时间的 key(4.0+版本支持)。

其它限制相关

  • maxclients: 设置 Redis 同时可以与多少个客户端进行连接,默认为 10000 个客户端。
  • maxmemory: 设置 Redis 可以使用的内存量,建议必须设置,否则可能造成服务器宕机。
  • maxmemory-samples: 设置样本数量,LRU 算法和最小 TTL 算法都是估算值,可以设置样本的大小,默认检查 5 个 key。

通过以上配置和管理策略,可以有效管理 Redis 的内存使用,避免性能瓶颈和服务器宕机。

总结

redis持久化

  • RDB持久化:定时的将redis在内存的数据进行快照并压缩保存到硬盘里

    • 手动触发:手动执行 bgsave 命令
    • 自动触发:满足配置文件中 save n m 的规则(在n秒内发生了m次数据更新就会自动触发);主从复制在做全量复制时;执行shutdown命令关闭数据库时
    • 工作流程:redis主进程会fork子进程来进行RDB持久化快照保存内存数据到硬盘里,文件名为 dump.rdb
    • 优缺点:RDB持久化保存的文件占用空间较小,网络传输快,恢复速度比AOF更快,性能影响比AOF更小
      • 实时性不如AOF,兼容性较差,持久化期间在fork子进程时会阻塞redis主进程响应客户端命令
  • AOF持久化:实时的以追加的方式将redis写操作命令保存到aof文件里

    • 工作流程:命令追加(将写操作命令追加到aof_buf缓冲区)
      • 文件写入和同步(按照同步策略将缓冲区里的数据同步到硬盘,文件名:appendonly.aof;同步策略:everysec(每秒刷盘一次)、always(每条命令写入都刷盘)、no(让系统自行刷盘))
        -文件重写(减少aof文件占用空间和加快恢复速度,定时执行bgrewriteaof命令触发)
    • 优缺点:实时性比RDB更好,支持秒级持久化,兼容性较好;
      • 持久化保存的文件占用空间更大,恢复速度更慢,性能影响更大,AOF文件重写期间在fork子进程时也会阻塞redis主进程,且IO压力更大

RDB和AOF的区别可从 工作方式、实时性、占用空间、恢复速度、兼容性、IO性能影响 这几方面进行描述。

redis性能优化:

  1. 设置内存上限(maxmemory),并设置内存数据淘汰策略(maxmemory-policy),一般采用lru或random
  2. 开启AOF持久化(实时性好),设置AOF刷盘策略为everysec;关闭自动AOF文件重写,采用定期在业务低峰期执行bgrewriteaof命令触发AOF文件重写,减少IO的压力
  3. 开启自动内存碎片清理(activedefrag yes)
  4. 缩短键值对存储长度,避免存储bigkey导致操作耗时(建议string类型数据控制在20KB以内,hash、list、set、zset控制元素数量在5000以内)
  5. 给key设置合理的过期时间,尽量避免大量key集中过期
  6. 开启lazy-free机制(lazyfree-lazy-* yes),将删除过期key的操作放到后台线程执行,减少大量的删除操作对redis主进程的阻塞
  7. 尽量使用物理机而非虚拟机部署redis服务,使用高速固态硬盘作为AOF日志的写入盘
  8. 使用分布式架构(主从复制、哨兵、集群)实现读写分离、分散bigkey来提升读写速度,并实现高可用
  9. 禁用内存大页(echo never > /sys/kernel/mm/transparent_hugepage/enabled),因为开启内存大页会到fork子进程的速度变慢,也会拖慢写操作的执行速度

redis的三大缓存问题:

正常情况下,大部分的访问请求应该时先被redis缓存响应,在redis那里得不到响应的小部分访问请求才会去请求MySQL数据库获取数据,这样MySQL数据库的负载压力会非常小,能够正常稳定工作。
缓存雪崩/穿透/击穿问题的根本原因是在于redis缓存命中率下降,大量请求会直接发送给MySQL数据库,导致数据库负载压力过大而崩溃。
缓存雪崩:redis中大量不同的缓存key集中过期

缓存穿透:大量请求访问redis和MySQL数据库都不存在的数量

缓存击穿:redis中一个热点key过期,此时又有大量请求访问这个热点key
缓存雪崩解决方案:

使用随机数设置key的过期时间,防止集中过期

设置二级缓存

使用互斥锁,在查数据库时加锁,缓冲大量请求
缓存穿透解决方案:

使用布隆过滤器进行判断拦截一定不存在的无效请求

对空值数据也进行缓存

在业务层使用脚本等方式对用户的请求进行校验,排查非法请求
缓存击穿解决方案:

对热点缓存不设置过期时间

预先对热点数据进行缓存预热

使用互斥锁,在查数据库时加锁,缓冲大量请求

相关推荐
sun0077001 小时前
ubuntu dpkg 删除安装包
运维·服务器·ubuntu
oi772 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
mqiqe2 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
工业甲酰苯胺2 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
BestandW1shEs2 小时前
谈谈Mysql的常见基础问题
数据库·mysql
重生之Java开发工程师2 小时前
MySQL中的CAST类型转换函数
数据库·sql·mysql
教练、我想打篮球2 小时前
66 mysql 的 表自增长锁
数据库·mysql
Ljw...2 小时前
表的操作(MySQL)
数据库·mysql·表的操作