zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

Redis 聊聊主从复制需要注意的几个方面

Redis 需要 几个 注意 聊聊 主从复制 方面
2023-09-14 09:01:47 时间

数据同步


Redis在2.8及以上版本使用psync命令完成主从数据同步, 同步过程分为: 全量复制和部分复制。
· 全量复制: 一般用于初次复制场景, Redis早期支持的复制功能只有全量复制, 它会把主节点全部数据一次性发送给从节点, 当数据量较大时, 会对主从节点和网络造成很大的开销。

· 部分复制: 用于处理在主从复制中因网络闪断等原因造成的数据丢失场景, 当从节点再次连上主节点后, 如果条件允许, 主节点会补发丢失数据给从节点。 因为补发的数据远远小于全量数据, 可以有效避免全量复制的过高开销。部分复制是对老版复制的重大优化, 有效避免了不必要的全量复制操作。 因此当使用复制功能时, 尽量采用2.8以上版本的Redis。

psync命令运行需要以下组件支持:
·主从节点各自复制偏移量。
·主节点复制积压缓冲区。
·主节点运行id。

 

复制偏移量


参与复制的主从节点都会维护自身复制偏移量。 主节点(master) 在处理完写入命令后, 会把命令的字节长度做累加记录, 统计信息在info relication中的master_repl_offset指标中:(主节点查看)

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=2478,lag=0
.................................................
master_repl_offset:2478

从节点(slave) 每秒钟上报自身的复制偏移量给主节点, 因此主节点也会保存从节点的复制偏移量, 统计指标如下:(主节点查看)

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=2478,lag=0   --偏移量2478
...................................................

从节点在接收到主节点发送的命令后, 也会累加记录自身的偏移量。 统计信息在info relication中的slave_repl_offset指标中:(从节点查看)

127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
...............................................
slave_repl_offset:2674

复制偏移量的维护如图所示。通过对比主从节点的复制偏移量, 可以判断主从节点数据是否一致。

运维提示:
可以通过主节点的统计信息, 计算出master_repl_offset - slave_offset字节量, 判断主从节点复制相差的数据量, 根据这个差值判定当前复制的健康度。 如果主从之间复制偏移量相差较大, 则可能是网络延迟或命令阻塞等原因引起。

 

复制积压缓冲区


复制积压缓冲区是保存在主节点上的一个固定长度的队列, 默认大小为1MB, 当主节点有连接的从节点(slave) 时被创建, 这时主节点(master)响应写命令时, 不但会把命令发送给从节点, 还会写入复制积压缓冲区, 如图所示:

由于缓冲区本质上是先进先出的定长队列, 所以能实现保存最近已复制数据的功能, 用于部分复制和复制命令丢失的数据补救。 复制缓冲区相关统计信息保存在主节点的info replication中:

127.0.0.1:6379> info replication
# Replication
role:master
...
repl_backlog_active:1 // 开启复制缓冲区
repl_backlog_size:1048576 // 缓冲区最大长度
repl_backlog_first_byte_offset:7479 // 起始偏移量, 计算当前缓冲区可用范围
repl_backlog_histlen:1048576 // 已保存数据的有效长度。

根据统计指标, 可算出复制积压缓冲区内的可用偏移量范围:
[repl_backlog_first_byte_offset,repl_backlog_first_byte_offset+repl_backlog_histlen]。 
 


主节点运行ID


每个Redis节点启动后都会动态分配一个40位的十六进制字符串作为运行ID。 运行ID的主要作用是用来唯一识别Redis节点, 比如从节点保存主节点的运行ID识别自己正在复制的是哪个主节点。 如果只使用ip+port的方式识别主节点, 那么主节点重启变更了整体数据集(如替换RDB/AOF文件),从节点再基于偏移量复制数据将是不安全的, 因此当运行ID变化后从节点将做全量复制。 可以运行info server命令查看当前节点的运行ID:

127.0.0.1:6379> info server
# Server
redis_version:3.0.7
...
run_id:545f7c76183d0798a327591395b030000ee6def9

需要注意的是Redis关闭再启动后, 运行ID会随之改变, 例如执行如下命令:

# redis-cli -p 6379 info server | grep run_id
run_id:545f7c76183d0798a327591395b030000ee6def9
# redis-cli -p shutdown
# redis-server redis-6379.conf
# redis-cli -p 6379 info server | grep run_id
run_id:2b2ec5f49f752f35c2b2da4d05775b5b3aaa57ca

如何在不改变运行ID的情况下重启呢?当需要调优一些内存相关配置, 例如: hash-max-ziplist-value等, 这些配置需要Redis重新加载才能优化已存在的数据, 这时可以使用debug reload命令重新加载RDB并保持运行ID不变, 从而有效避免不必要的全量复制。 命令如下:

# redis-cli -p 6379 info server | grep run_id
run_id:2b2ec5f49f752f35c2b2da4d05775b5b3aaa57ca
# redis-cli debug reload
OK
# redis-cli -p 6379 info server | grep run_id
run_id:2b2ec5f49f752f35c2b2da4d05775b5b3aaa57ca

运维提示:
debug reload命令会阻塞当前Redis节点主线程, 阻塞期间会生成本地RDB快照并清空数据之后再加载RDB文件。 因此对于大数据量的主节点和无法容忍阻塞的应用场景, 谨慎使用。

 

psync命令


从节点使用psync命令完成部分复制和全量复制功能, 命令格式:psync{runId}{offset}, 参数含义如下:
·runId: 从节点所复制主节点的运行id。
·offset: 当前从节点已复制的数据偏移量。

流程说明:
1) 从节点(slave) 发送psync命令给主节点, 参数runId是当前从节点保存的主节点运行ID, 如果没有则默认值为?, 参数offset是当前从节点保存的复制偏移量, 如果是第一次参与复制则默认值为-1。
2) 主节点(master) 根据psync参数和自身数据情况决定响应结果:
·如果回复+FULLRESYNC{runId}{offset}, 那么从节点将触发全量复制流程。
·如果回复+CONTINUE, 从节点将触发部分复制流程。
·如果回复+ERR, 说明主节点版本低于Redis2.8, 无法识别psync命令,从节点将发送旧版的sync命令触发全量复制流程。

对应的日志如下:

Connecting to MASTER 192.168.75.136:6379
MASTER <-> REPLICA sync started
Non blocking connect for SYNC fired the event.  --开始非阻塞同步
Master replied to PING, replication can continue...
Partial resynchronization not possible (no cached master)
Full resync from master: 74fb29643971834fdf701beb1708ce9ddc23bdee:0  --全量同步
MASTER <-> REPLICA sync: receiving 193 bytes from master --接受数据
MASTER <-> REPLICA sync: Flushing old data  --清空以前缓存得数据
MASTER <-> REPLICA sync: Loading DB in memory  --加载数据库到内存
MASTER <-> REPLICA sync: Finished with success  --完成同步