简单介绍
什么是主从复制集群?
试想一下,你的网站在某一天突然火了,流量爆炸,访问量直线飙升,你的redis单机服务器摇摇欲坠,这该如何是好啊?赶紧启动两个redis节点,成为你那个主服务器(master)的从节点(slave)吧,分担大部分读请求的访问压力!
-
有一个主节点,多个从节点。
-
主节点负责读、写任务,从节点负责读任务。
-
主从节点通过一定的数据复制手段,保证从节点能尽量和主节点的数据保持一致,即:主从复制。
-
从节点宕机重启还可以自动连接主节点(如果你配置文件中配置了的话),全自动恢复集群完整。
什么是主从复制?
-
分为全量复制和增量复制。
-
全量复制:主节点生成rdb快照传递给从节点,并且将生成快照期间产生的写命令缓存在replication backlog,传递完快照之后一并输送给从节点。
-
增量复制:从节点重启之后,向主节点请求复制,主节点传递replication backlog缓冲区中的写命令。
搭建集群(使用docker)
搭建主从集群
基础操作
# 文件夹目录
/home/work/docker_data/redis_copy
- master 主节点
- redis.conf
- redis.log
- slave 从节点
- slave1
- redis.log
- slave2
- redis.log
- redis.conf
# --subnet是docker的CIDR网络,超网划分
docker network create --subnet 172.30.1.0/24 redis_net
配置主从节点
# 基础配置(主从节点都要有)
# 接收所有ip的客户端
bind 0.0.0.0
# 设置日志的路径
logfile "./redis.log"
# 从节点额外配置
# 设置主节点 replicaof <主节点ip> <主节点端口>
replicaof 172.30.1.2 6379
启动主从节点
# 主节点
docker run --name master \
-v /home/work/docker_data/redis_copy/master/redis.conf:/usr/local/etc/redis/redis.conf \
-v /home/work/docker_data/redis_copy/master:/data \
-d --network=redis_net \
redis redis-server /usr/local/etc/redis/redis.conf
# 从节点1
docker run --name slave1 \
-v /home/work/docker_data/redis_copy/slave/redis.conf:/usr/local/etc/redis/redis.conf \
-v /home/work/docker_data/redis_copy/slave/slave1:/data \
-d --network=redis_net \
redis redis-server /usr/local/etc/redis/redis.conf
# 从节点2
docker run --name slave2 \
-v /home/work/docker_data/redis_copy/slave/redis1.conf:/usr/local/etc/redis/redis.conf \
-v /home/work/docker_data/redis_copy/slave/slave2:/data \
-d --network=redis_net \
redis redis-server /usr/local/etc/redis/redis.conf
验证是否成功
# 打开docker容器控制台
docker exec -it master bash
# 连接主节点
redis-cli -h 172.30.1.2 -p 6379
# 查看主从集群信息
# 或者ROLE命令
info replication
进阶配置解析
主从节点
# 主节点密码(如果主节点有的话)
masterauth <密码>
# 主节点用户(如果主节点有的话,即ACL)
masteruser <用户>
# 如果主节点有定义用户,命令还可以合并成
AUTH <账户> <密码>
# 从节点如果和主节点断开或者正在进行同步时,
# 客户端发来的读命令(除了INFO,REPLICAOF...)将会被允许(可能会返回nil或者旧数据)
# 设置成‘no’,则会返回报错
replica-serve-stale-data yes
# redis2.6之后从节点默认只读
# 设置成‘no’,则可以接受写命令,用来存放一些临时数据,向主节点同步后删除
replica-read-only yes
# 默认情况下主节点全量复制生成的rdb文件不转存硬盘,内存折半(一般用来存放rdb文件),
# 并且在生成完成后等待一定时间(可配置)后,尽可能发送给多个从节点
# 设置成‘no’,则会转存硬盘,相对来说会慢一点
repl-diskless-sync yes
# 设置全量复制生成rdb文件后的等待时间(s)
# 设置‘0’,则表示没有等待时间
repl-diskless-sync-delay 5
# 全量复制从节点最大连接数,如果达到了该数量,
# 则本次同步repl-diskless-sync-delay失效,会立即传输rdb文件
# 默认‘0’,表示无论如何都要等待设置的时间
repl-diskless-sync-max-replicas 0
# 主节点每隔10s向从节点发送PING命令检查其是否存活
repl-ping-replica-period 10
# 主节点发送ping,超过时间(60s)未接收到从节点的ACK,则算超时
# 从节点发送REPLCONF ACK ping,超过时间(60s)未接收到主节点的回复,则算超时
# 处理主节点的数据同步超过该时间,算超时(所以要,配置时间 > 同步时间)
# 超时则重新连接主节点进行同步
repl-timeout 60
# 一般情况下默认关闭,
# 开启会导致redis同步时,发送更少的TCP报文(压缩rdb文件)
# 且占用更少的带宽(流量大时使用)
repl-disable-tcp-nodelay no
# 设置replication backlog缓冲区的大小
# 至少有一个从节点,才会分配该缓冲区
repl-backlog-size 1mb
# 当主节点最后一个从节点断联时间超过3600s时,
# 则会释放replication backlog缓冲区。
# 从节点则永远不会因为超时释放缓冲区,
# 因为如果未来升级为主节点,其他从节点可以进行增量同步,而不是全量同步
# 设置为‘0’,永远不会释放replication backlog
repl-backlog-ttl 3600
# redis支持全量同步时直接加载接收主节点发送来的rdb文件到内存
# 选项
# - disabled 无论如何,都先加载到硬盘,然后再加载到内存
# - swapdb 将当前数据集维持再RAM中,并从套接字直接加载rdb文件,
# 总内存 > rdb文件 + 当前数据集,不然会OOM
# - on-empty-db 仅当当前数据集为空,才进行无盘加载
repl-diskless-load disabled
# 用于哨兵选举
# 数字越小,优先级越高
# 0代表永远无法成为主节点
replica-priority 100
# 如果在主从复制期间传播的命令有误
# 或者读取aof文件(命令形式)有误时
# - ignore 默认会忽略错误,保留数据不一致的情况
# - panic(panic-on-replicas) 保证数据一致性
propagation-error-behavior ignore
# 主从复制时,从节点接收并执行主节点发送的写命令后,
# 持久化到磁盘时(开启aof),出现错误时
# - no 关闭从节点
# - yes 仅在日志打印waring,不推荐,仅为了兼容老版本
replica-ignore-disk-write-errors no
# 哨兵执行sentinel replicas <master>命令时无法被感知
# 但是设置成no,依然可以被选举成master
replica-announced yes
# 主节点仅在至少有3个从节点的延迟小于等于10秒的情况下才会接受写命令
# 其中一个值为0,则该功能被禁止
# 从从节点最后一次接收到ping命令开始计算(心跳检测)
# 这个可以有效控制脑裂发生的可能性,后面会讲
min-replicas-to-write 3
min-replicas-max-lag 10
# 正常情况下,master通过info replication或者role
# 可以查看slave的ip和port
# 但是在端口转发或者网络转换的时候(NAT),
# 显示出来的可能不是slave真正的ip和port,
# 因为master是检查slave连接自己时socket携带的ip和port
# 将下面的设置成自身的ip和port可以保证master可以查看自己真实的ip,port
replica-announce-ip 5.5.5.5
replica-announce-port 1234
底层原理
全量复制+命令传播
-
1.2中发送的命令其实是psync {runId} {offset}
-
主节点生成rdb文件,可以通过repl-diskless-sync yes设置不经过磁盘(更快但需要double内存!!!)
-
从节点接收rdb文件,可以通过repl-diskless-load swapdb设置不经过磁盘(更快但需要double内存!!!)
-
如果从节点开启了aof持久化(appendonly yes),则会立即执行bgrewriteaof命令重写aof文件
增量复制
-
offset的判断有两种,不合法会拒绝增量同步,进而转换成全量同步
-
offset超过int类型最大值(offset会不断累加,全量复制会重置offset)
-
主节点新增写命令覆盖了未同步给从节点的数据部分
-