Redis(六) 持久化与复制

Posted by ZhouJ000 on November 15, 2018
最后更新于:2018-11-15

Redis(一) 基础与api
Redis(二) 小功能
Redis(三) 阻塞与内存
Redis(四) 缓存设计
Redis(五) 客户端调用
Redis(六) 持久化与复制
Redis(七) 哨兵
Redis(八) 集群

持久化

redis支持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复

RDB

RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发

触发机制

手动触发分别对应 save 和 bgsave 命令:

  • save命令:阻塞当前redis服务器,直到RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用
  • bgsave命令:redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短

自动触发RDB机制:

  • 使用save相关配置,如’save m n’。表示m秒内数据集存在n次修改时,自动触发bgsave
  • 如果从节点执行全量复制操作,主节点自动执行bgsave生成RDB文件并发送给从节点
  • 执行debug reload命令重新加载redis时,也会自动触发save操作
  • 默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则自动执行bgsave

优缺点

优点:
1、RDB是一个紧凑压缩的二进制文件,代表redis在某个时间点上的数据快照。非常适合用于备份,全量复制等场景。比如每6小时执行bgsave备份,并把RDB文件拷贝到远程机器或文件系统(如hdfs),用于容灾备份
2、redis加载RDB恢复数据远远快于AOF的方式
缺点:
1、RDB方式数据没法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高
2、RDB文件使用特定二进制格式保存,redis版本演进过程由多个格式的RDB版本,存在老版本兼容问题

AOF

AOF持久化,以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的墓地。AOF的主要作用是解决了数据持久化的实时性,目前已是redis持久化的主流方式

使用AOF

开启AOF功能需要设置配置:appendonly yes,默认不开启。AOF文件名通过appendfilename配置设置,默认文件名是appendonly.aof。保存路径与RDB一样,通过dir配置指定

AOF工作流程操作:
1、命令写入(append)
2、文件同步(sync)
3、文件重写(rewrite)
4、重启加载(load)
流程如下:
1、所有的写入命令会追加到aof_buf(缓冲区)中
2、AOF缓冲区根据对应的策略向硬盘做同步操作
3、随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的
4、当redis服务器重启时,可以加载AOF文件进行数据恢复

问题定位

fork操作

redis做RDB或AOF重写时,必不可少操作就是执行fork操作创建子进程,对于大多数操作系统来说fork是个重量级操作

可以在info stats统计中查询lastest_fork_usec指标获取最近一次fork操作耗时,单位微秒

子进程开销监控

子进程的运行过程主要涉及CPU,内存,硬盘三部分的消耗

AOF追加阻塞

当开启AOF持久化时,常用的同步硬盘策略是everysec,用于平衡性能和数据安全性。对于这种方式,redis使用另一条线程每秒执行fsync同步硬盘。当系统硬盘资源繁忙时,会造成redis主线程阻塞

多实例部署

redis单线程架构导致无法充分利用CPU多核,通常会在一台机器上部署多个实例。当多个实例开启AOF重写后,彼此之间会产生对CPU和IO的竞争

复制

在分布式中为了解决单点问题,通常会把数据复制多个副本部署到其他机器,满足故障恢复和负载均衡等需求

配置

参与复制的redis实例划分为主节点(master)和从节点(slave)。默认情况下,redis都是主节点。每个从节点只能有一个主节点,主节点可以同时具有多个从节点。

配置复制的方式有三种:
1、在配置文件中加入slaveof {masterHost} {masterPort} 随redis启动生效
2、在redis-server启动命令后加入 –slaveof {masterHost} {masterPort}生效
3、直接使用命令slaveof {masterHost} {masterPort}生效

slaveof本身是异步命令,执行slaveof命令时,节点只保存主节点信息后返回,后续复制流程在节点内部异步执行。可以使用info replication命令查看复制相关状态

slaveof命令还可以用来断开复制,从节点上执行slaveof no one来断开与主节点的复制关系,从节点晋升为主节点

对于重要的数据节点,主节点会通过设置requirepass参数进行密码验证,这时所有客户端访问必须使用auth命令实现校验。从节点与主节点复制链接是通过一个特殊标识的客户端来完成,因此需要配置从节点的masterauth参数与主节点密码一致,保证正确连接到主节点复制

默认情况下,从节点使用slave-read-only=yes配置为只读模式

主从节点一般部署在不同机器上,复制时网络延迟就成为需要考虑的问题,redis提供了repl-disable-tcp-nodelay参数用于控制是否关闭TCP_NODELAY,默认为关闭

拓扑

redis的复制拓扑结构可以支持单层或多层复制关系,根据拓扑复杂性分为:一主一从、一主多从、树状主从结构

原理

复制过程大致分为6个过程:
1、保存主节点信息,执行slaveof后从节点只保存主节点地址信息便直接返回
2、从节点内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新节的主节点后,会尝试与该节点建立网络连接
3、发送ping命令,检测主从之间网络套接字是否可用,检测主节点当前是否可接受处理命令
4、权限验证
5、同步数据集,主从复制连接正常通信后,对于首次建立复制的场景,主节点会把数据发送给从节点,分为全量同步和部分同步
6、命令持续复制

从节点使用psync命令完成部分复制和全部复制功能

  • 全量复制:一般用于初次复制场景,redis早期支持的复制功能只有全量复制,会把主节点全部数据一次性发送给从节点
  • 部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,主节点会补发丢失数据给从节点
    • 复制偏移量
    • 复制积压缓冲区
    • 主节点运行ID

主从节点在建立复制后,它们之间维护着长连接并彼此发送心跳命令,通过client list命令查看复制相关客户端信息。主节点默认每隔10秒对从节点发送ping命令,判断从节点的存活性和连接状态。从节点在主线程中每隔1秒发送replconf ack {offset}命令,给主节点上报自身当前的复制偏移量

问题

读写分离

对于读占比比较高的场景,可以通过把一部分流量分摊到从节点来减轻主节点压力,同时需要永远只对主节点进行写操作

1、复制数据延迟:无法避免,延迟取决于网络带宽和命令阻塞情况。可以编写外部监控程序监听主从节点复制偏移量,当延迟较大时触发报警或通知客户端避免读取延迟过高的从节点
2、读到过期数据:redis内部需要维护数据删除策略,主要由惰性删除和定时删除
3、从节点故障:需要客户端维护可用的从节点列表,出现故障后立即切换到其他从节点或主节点上

主从配置不一致

对于有些配置主从之间可以不一致,但对于内存相关的配置必须要一致

避免全量复制

1、第一次建立复制:低峰时进行,或避免使用大数据量redis节点
2、节点运行ID不匹配:故障转移
3、复制积压缓冲区不足:根据网络中断时长,写命令数据量分析给出合理的积压缓冲区大小

避免复制风暴

复制风暴指大量从节点对同一主节点或同一台机器的多个主节点短时间内发起全量复制的过程。会对主节点或机器造成大量开销,导致CPU、内存、带宽消耗

1、单主节点复制风暴:减少主节点挂载从节点数量,或采用树状复制结构加入中间层从节点来保护主节点
2、单机器复制风暴:把主节点尽量分散在多台机器上,当主节点所在机器故障后提供故障转移机制避免机器恢复后进行密集的全量复制