redis 复制功能说明

By | 2015-01-26

redis 复制功能说明

一. 概述

redis的复制功能可以分为同步和命令这两阶段操作, 同步操作使得 slave 的状态更新到 master 当前所在的状态, 命令传播阶段则实现增量的状态更新, 使得 master 和 slave 达到一致的状态.

在复制功能的实现中, 同步即对应着初始复制阶段, 命令传播对应着增量复制阶段. 在 client 向 slave 发送 slaveof 命令时, 会使得 slave 开始复制 master, 首先 slave 需要执行初始复制, 即上述的同步阶段, 同步过程的通信流程如下:

  1. slave 发送 SYNC 给 master;
  2. master 收到 SYNC 后执行 BGSAVE, 生成 RDB 文件, 且使用缓冲区记录从当前开始执行的所有 write 操作;
  3. master 发送 RDB 文件给 slave, slave 接收并加载 RDB 文件, 此时 slave 状态更新到 master 执行 BGSAVE 时的状态;
  4. master 发送缓冲区的命令给 slave, slave 执行命令, 此时 slave 状态更新到 master 当前所处的状态.

初始复制完成后, 在 master 进行了更新操作,为确保 master 和 slave 之间的数据一致, master 需要将更新的命令发送给 slave, slave 执行后完成增量复制阶段.

二. 复制功能

不过对于增量复制的实现, redis 的新旧版实现方式确有很大不同, 2.8之前为旧版, 反之为新版.
旧版复制功能(2.8版本之前)
1. 初始复制(同上述的同步过程)
2. 增量复制(命令阶段同上, 但是在主从故障恢复后, 比如网络中断恢复, slave 向 master 继续发送SYNC, 重新执行初始复制过程,并不是我们认为的增量复制 )

主从中断后的复制机制, 发送SYNC命令, 所以在旧版中,一旦有主从中断的发生就会引起很多不必要的操作. 当然在2.8版本后这种方式得到了较好的解决.

新版复制功能(2.8及之后版本)

复制的整体过程类同上述所说, 不过使用 PSYNC 来代替 SYNC, 增量复制由以下部分构成:

  1. master 复制偏移量 ( replication offset ), 使用偏移量完成增量复制.
  2. master 复制积压缓冲区( replication backlog ) : 参数repl-backlog-size, 
  3. master 运行 ID ( run ID ): 机器启动后自动生成, 重启的时候会改变, slave同坐做全量同步(SYNC).

master的复制缓冲区中保存最近执行的更新命令,里面也保存着复制的偏移量, 主从断线后的复制机制, slave 发送 PSYNC 命令, 通过偏移值完成增量复制(如果 slave 的偏移值还在缓冲区中则进行增量复制, 反之执行初始复制.) 可以加大 repl-backlog-size 和 repl-backlog-ttl 参数的值来延长缓冲区失效的时间.

注意: 如果 master 或 slave 重启了则进行初始复制(同步操作),因为丢失了偏移值, 算是比较悲催的特性.

总结来看, 在旧版本中, master, slave 或网络的中断等原因都会引起初始复制, 新版本中网络中断等原因则进行增量复制.

三. 其它

vip高可用:
redis 服务通过 vip 对外服务, 需要注意 conf 配置中的 bind 选项需要监听所有端口, 比如仅监听一个内网地址, 在做主从切换后, 新的 master 的vip 不会生效,

内核参数设置:

# disanle vm, bgsave may fail under low memory condition 
sysctl -w vm.overcommit_memory=1

# 2.8v , redis must be restart after THP( Transparent_hugepage ) is disabled
echo never > /sys/kernel/mm/transparent_hugepage/enabled

# tcp backlog should less than the value of somaxconn 
sysctl -w net.core.somaxconn=600

OOM问题
如果担心系统的评分机制杀掉 redis 进程, 可以设置 redis 进程不参与评分, 以下操作:

echo '-17' >/proc/`pidof redis`/oom_adj

master性能:
有些案例建议在 master 配置中禁掉 SNAPSHOTTING, 即不让触发 redis 的 save 操作, 避免引起不是必要的性能损耗, 同时禁止aof等操作, 但是在 slave 中开启 save (和 aof功能), 这样能更大程度的提高 master 的性能, 也能减少故障引起的数据丢失. 另外 slave 故障恢复后, 由于网络, redis 数据文件的大小, 以及 slave 加载数据文件等原因, 应该适当增加 repl-timeout 参数值确保 slave 有足够的时间进行重做操作, 否则可能会引起重复的初始复制操作.

replication ack 检测:
在命令传播阶段, slave 以每秒一次的频率向 master 发送检测命令, 主要有以下作用
1. 检测主从网络连接状态
在 master 中执行 info replication :

role:master
connected_slaves:1
slave0:ip=10.0.21.7,port=6380,state=online,offset=4299,lag=1

lag值表示 slave 最后一次向 master 发送检测命令距离现在过了多少秒, 正常应该在0或1之间跳动.

2. 通过lag实现min-slaves配置选项

# slave 数量少于3, 或 3 个 slave 的延迟都 >= 10 秒时, master将拒绝执行写命令.
min-slaves-to-write 3
min-slaves-max-lag 10

3. 检测命令丢失
如果 master 传播给 slave 的命令丢失, 当 slave 向 master 发送检测命令的时候, master 会发现 slave 当前的偏移量 offset 小于自己的复制偏移量, 之后 master 会根据 slave 的偏移信息, 在复制积压缓冲区里面找到 slave 缺少的数据, 并重新发送给 slave.

ref: http://redisbook.com/

四. 故障切换

slave 以 slaveof 命令完成主从配置, slave 是否只读由 slave-read-only 参数决定, 线上默认打开. 如上所述, master 或 slave 重启都会引起初始复制, 尽管很简单, 但是故障恢复过程没有 MySQL 等软件那么有效, 由此 redis 主从切换的过程如下,
当 master 出现故障时:

1. 切换 vip 到 slave;
2. 连接 slave 执行 slaveof no one, 断掉主从关系, 同时置 slave 为新的 master, 该命令执行后, 关闭 slave-read-only 参数, 允许应用更新;  
3. 关闭旧 master 的服务;

自动切换过程可以通过 redis sentinel 或 keepalived(vip) + scripts 方式完成:
sentinel 是 redis 提供的高可用解决方案, 由一个或多个 sentinel 实例组成的系统可以监控任意多个 Server, 并完成下线或提升 slave 为 master 的操作, 过程类似于 MySQL Gelara 插件, 进行选举 quorum 再提升为 master 等, sentinel 中的 client-reconfig-script 和 client-reconfig-script 需要自定义完成;

keepalived + scripts 方式较为通用, 可以应用到较低版本, 也可以应用到多个一台主机的多个实例中. 应用连接 vip 进行读写, 在 master 出现故障的时候, keepalived 完成 vip 的切换, scripts 完成提升 slave 为 master 操作:
keepalived配置中增加以下配置分别完成 keepalived 进入 master 和 backup 状态时需要执行的操作, 配置见http://get.arstercz.com/tools/redis_ha.tar.gz

    notify_master "/home/redis/redis.sh -m"  # 提升为 master 
    notify_backup "/home/redis/redis.sh -s"  # 操作为 slave

redis脚本中 REDIS_MASTER_IP 指定为对端的实ip信息.比如:

10.0.21.5:6380 (master)
 +-- 10.0.21.7:6380 (slave)

则在21.5中, REDIS_MASTER_IP 设置为 10.0.21.7, 反之亦然.

One thought on “redis 复制功能说明

  1. cz

    如果redis, apache或nginx 和MySQL等在同一台主机, vm.overcommit_memory 参数需要权衡下是否关闭, 关闭vm需要谨慎操作, 大多数的数据库都能很好的解决 overcommit 带来的问题, 比如MySQL, 如果关闭overcommit, MySQL可能不会和一些依赖fork系统函数的程序很好的工作.

    https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-memory-captun.html

    http://www.psce.com/blog/2012/05/31/mysql-oom-killer-and-everything-related/

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *