redis高可用-主从复制
Redis高可用常见的有两种方式:
- 主从复制(Replication-Sentinel模式)
- Redis集群(Redis-Cluster模式)
下面将分别介绍这两种高可用方案
主从复制
背景
一般来说,要将 Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机,一主二从),原因如下:
1、从结构上,单个 Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大
2、从容量上,单个 Redis服务器内存容量有限,就算一台 Redis服务器内存容量为256G,也不能将所有内存用作 Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G。
要实现分布式数据库的更大的存储容量和承受高并发访问量,我们会将原来集中式数据库的数据分别存储到其他多个网络节点上。
一些概念
主从复制
主从复制,是指将一台 Redis服务器的数据,复制到其他的 Redis服务器。前者称为主节点( master/ leader),后者称为从节点(slave/ follower);数据的复制是单向的,只能由主节点到从节点。 Master以写为主,Slave以读为主。
默认情况下,每台 Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
全量复制
用于初次复制或其它无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作,当数据量较大时,会对主从节点和网络造成很 大的开销
部分复制
用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果(条件允许),主节点会补发丢失数据给从节点。 因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销,需要注意的是,如果网络中断时间过长,造成主节点没有能够完整地保存中断期间执行 的写命令,则无法进行部分复制,仍使用全量复制
复制偏移量
参与复制的主从节点都会维护自身复制偏移量。
主节点(master)在处理完写入命令后,会把命令的字节长度做累加记录,统计信息在 info relication
中的 master_repl_offset
指标
主节点也会保存从节点的复制偏移量,统计信息在 info relication
中的 slave0
指标
从节点在接收到主节点发送的命令后,也会累加记录自身的偏移量。统计信息在info relication
中的slave_repl_offset
中
复制积压缓冲区
复制积压缓冲区是保存在主节点上的一个固定长度的队列,默认大小为1MB,当主节点有连接的从节点(slave)时被创建,这时主节点(master)响应写命令 时,不但会把命令发送给从节点,还会写入复制积压缓冲区。
在命令传播阶段,主节点除了将写命令发送给从节点,还会发送一份给复制积压缓冲区,作为写命令的备份;除了存储写命令,复制积压缓冲区中还存储了其中 的每个字节对应的复制偏移量(offset) 。由于复制积压缓冲区定长且先进先出,所以它保存的是主节点最近执行的写命令;时间较早的写命令会被挤出缓冲区
缓冲区大小调整
由于缓冲区长度固定且有限,因此可以备份的写命令也有限,当主从节点offset的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。反过 来说,为了提高网络中断时部分复制执行的概率,可以根据需要增大复制积压缓冲区的大小(通过配置repl-backlog-size)来设置
例如 如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(特定协议格式)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见, 可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。
正常情况下redis是如何决定是全量复制还是部分复制
从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制
- 如果offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部分复制
- 如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制。
服务器运行id(runid)
每个Redis节点(无论主从),在启动时都会自动生成一个随机ID(每次启动都不一样),由40个随机的十六进制字符组成;runid用来唯一识别一个Redis节点。 通过info server
命令,查看节点的run_id
主从节点初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来;当断线重连时,从节点会将这个runid发送给主节点;主节点根据runid 判断能否进行部分复制: 如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓 冲区的情况) 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制
作用
1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式
2、故障恢复:当主节点岀现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写 Redis数据时应用连接主节点,读 Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4、读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量
5、高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是 Redis高可用的基础。
搭建(一主二从)
主从配置参考
配置从库的配置文件,主不需要配置
1
2
3
4
|
# 配置主服务器地址、端口号
slaveof 192.168.1.11 6379
# 主服务器密码
masterauth ""
|
为了避免一些问题,可以参照如下配置:
主库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#在slave和master同步后(发送psync/sync),后续的同步是否设置成TCP_NODELAY假如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加
同步延迟(40ms),造成master与slave数据不一致假如设置成no,则redis master会立即发送同步数据,没有延迟
#前者关注性能,后者关注一致性
repl-disable-tcp-nodelay no
#从库会按照一个时间间隔向主库发送PING命令来判断主服务器是否在线,默认是10秒
repl-ping-slave-period 10
#复制积压缓冲区大小设置
repl-backlog-size 1mb
#master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。单位为秒。
repl-backlog-ttl 3600
#redis提供了可以让master停止写入的方式,如果配置了min-slaves-to-write,健康的slave的个数小于N,mater就禁止写入。master最少得有多少个健康的slave存活才能执行写命令。这个配置虽然不能保证N个slave都一定能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不
能写入来避免数据丢失。设置为0是关闭该功能。
min-slaves-to-write 3
min-slaves-max-lag 10
|
从库
1
2
3
4
5
6
7
8
9
10
11
12
|
#设置该数据库为其他数据库的从数据库
slaveof <masterip> <masterport>
#主从复制中,设置连接master服务器的密码(前提master启用了认证)
masterauth <master-password>
slave-serve-stale-data yes
# 当从库同主库失去连接或者复制正在进行,从库有两种运行方式:
# 1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续相应客户端的请求
# 2) 如果slave-serve-stale-data设置为no,除了INFO和SLAVOF命令之外的任何请求都会返回一个错误"SYNC with master in progress"
#当主库发生宕机时候,哨兵会选择优先级最高的一个称为主库,从库优先级配置默认100,数值越小优先级越高
slave-priority 100
#从节点是否只读;默认yes只读,为了保持数据一致性,应保持默认
slave-read-only yes
|
启动服务
1
2
|
# 启动主从服务
docker run --privileged=true -p 6379:6379 - -v /docker/redis/conf/redis.conf:/etc/redis/redis.conf --name redis --restart=always -d redis redis-server /etc/redis/redis.conf
|
查看状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
# 登录主服务,查看是否配置成功
info replication
"# Replication
role:master #角色 master
connected_slaves:2 # 2个丛机
slave0:ip=192.168.1.13,port=6379,state=online,offset=42,lag=0
slave1:ip=192.168.1.12,port=6379,state=online,offset=42,lag=0
master_failover_state:no-failover
master_replid:60e64987fa9e8b4ada339763422fa76bff989764
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:42
"
# 从服务,查看状态
info replication
"# Replication
role:slave #角色 master
master_host:192.168.1.11 # 可以看到主机信息
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:364
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:60e64987fa9e8b4ada339763422fa76bff989764
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:364
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:29
repl_backlog_histlen:336
"
|
注:
主机可以写,从机不能写只能读!主机中的所有信息和数据,都会自动被从机所同步!
原理以及过程
主从复制过程大体可以分为3个阶段:连接建立阶段(即准备阶段)、数据同步阶段、命令传播阶段。
从节点执行slaveof命令后,会执行以下步骤(可以通过日志记录查看):
- 保存主节点信息。
- 主从建立socket连接。
- 发送ping命令
- 权限验证
- 同步数据集
- 命令持续复制
Slave启动成功连接到 master后会发送一个sync同步命令
Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后, master将传送整个数据文件到slave,并完成一次完全同步.
复制原理在详细看一下
slave与master建立socket链接后,会发送ping命令到master,然后在进行权限校验,然后Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后, master将传送整个数据文件到slave,并完成一次完全同步
全量复制:而 slave服务在接收到数据库文件数据后,将其存盘并加载到内存中
增量复制:Master继续将新的所有收集到的修改命令依次传给 slave,完成同步
但是只要是重新连接 master,一次完全同步(全量复制)将被自动执行
哨兵模式
产生背景
当主机宕掉,redis就无法提供服务了,为了解决这个问题,我们引入了哨兵
来进行选择主服务。
概念
能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
哨兵模式是一种特殊的模式,首先 Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待 Redis服务器响应,从而监控运行的多个 Redis实例。

作用
这里的哨兵有两个作用:
- 通过发送命令,让 Redis服务器返回监控其运行状态,包括主服务器和从服务器。
- 当哨兵监测到 master宕机,会自动将slave切换成 master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机
然而一个哨兵进程对Redis服务器进行监控,可能会岀现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行 failove过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行 failover【故障转移】操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线
搭建哨兵模式
哨兵配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
# Example sentinel. conf
# 哨兵 sentine1实例运行的端口 默认26379
port 26379
# 哨兵sentine1的工作目录
dir /tmp
#哨兵 sentinel1监控的redis主节点的 ip port
# master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9、这三个字符".-_"组成。
# quorum 配置多少个 sentinel哨兵统一认为 master主节点失联 那么这时客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor master 192.168.1.11 6379 2
# sentinel monitor slave1 192.168.1.12 6379 2
# sentinel monitor slave2 192.168.1.13 6379 2
#当在 Redis实例中开启了 requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码
# 设置哨兵 sentinel连接主从的密码 注意必须为主从设置一样的验证密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass master 123456
#sentinel auth-pass slave1 123456
#sentinel auth-pass slave2 123456
# 指定多少毫秒之后 主节点没有应答哨兵sentine1 此时哨兵主观上认为主节点下线 默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds master 30000
#sentinel down-after-milliseconds slave1 30000
#sentinel down-after-milliseconds slave2 30000
#这个配置项指定了在发生fai1over主备切换时最多可以有多少个slave同时对新 master进行同步
# 这个数字越小,完成fai1over所需的时间就越长
#但是如果这个数字越大,就意味着越多的s1ave因为replication而不可用。
#可以通过将这个值设为1来保证每次只有一个s1ave处于不能处理命令请求的状态。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs master 1
# 故障转移的超时时间 fai1over- tImeout可 以用在以下这些方面:
#1.同一个 sentinel对同一个master两次fai1over之间的间隔时间
#2.当一个s1ave从一个错误的 master那里同步数据开始计算时间。直到s1ave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的fai1over所需要的时间。
#4.当进行 failover时,配置所有slaves指向新的 master所需的最大时间。不过,即使过了这个超时, slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
#默认三分钟
#sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout master 180000
# SCRIPTS EXECUTION
#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
#通知型脚本:当 sentinel有任何警告级别的事件发生时(比如说 redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果 sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功.
#通知脚本
# sentinel notification-script <master-name> <script-path>
sentinel notification-script master /var/redis/notify.sh
#客户端重新配置主节点参数脚本
#当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于 master地址已经发生改变的信息。
#以下参数将会在调用脚本时传给脚本:
#<master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#目前< state>总是"fai1over",
# <ro1e>是“leader”或者“observer”中的一个。
#参数from-ip, from-port,to-ip,to-port是用来和旧的master和新的master(即旧的save)通信的
#这个脚本应该是通用的,能被多次调用,不是针对性的
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
|
启动哨兵服务
1
2
3
|
docker run --privileged=true -p 6379:6379 -p 26379:26379 -v /docker/redis/server/conf/redis.conf:/etc/redis/redis.conf -v /docker/redis/sentinel/conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf --name redis --restart=always -d redis redis-server /etc/redis/redis.conf && redis-sentinel /usr/local/etc/redis/sentinel.conf
docker run --name redis -v /docker/sentinel/conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf -d redis redis-sentinel /usr/local/etc/redis/sentinel.conf
|
查看状态
1
2
3
4
5
6
7
8
9
10
11
|
# 登录哨兵服务
redis-cli -p 26379
# 查看状态
127.0.0.1:26379> info sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=master,status=sdown,address=192.168.1.11:6379,slaves=0,sentinels=1
|
如果主机此时回来了,只能归并到新的主机下,当做从机,这就是哨兵模式的规则!
优缺点
优点
1、哨兵集群,基于主从复制模式,所有的主从配置优点,它全有
2、主从可以切换,故障可以转移,系统的可用性就会更好
3、哨兵模式就是主从模式的升级,手动到自动,更加健壮
缺点
1、 Redis不好在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦!
2、实现哨兵模式的配置其实是很麻烦的,里面有很多选择!
docker_compose 安装哨兵模式
目录结构
1
2
3
4
5
6
7
8
|
|-- docker
|-- redis
|-- conf
|-- data
|-- docker-compse.yml
|-- sentinel
|-- conf
|-- docker-compose.yml
|
redis/docker-compse.yml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
version: '3'
services:
# 主节点的容器
redis-server-master:
image: redis
container_name: redis
restart: always
# 为了规避Docker中端口映射可能带来的问题
# 这里选择使用host网络
network_mode: host
# 指定时区,保证容器内时间正确
environment:
TZ: "Asia/Shanghai"
volumes:
# 映射配置文件和数据目录
- ./redis-master.conf:/usr/local/etc/redis/redis.conf
- ./data/redis-master:/data
sysctls:
# 必要的内核参数
net.core.somaxconn: '511'
|
https://www.cnblogs.com/alinainai/p/14086960.html
原理
简单的主从集群有个问题,就是主节点挂了之后,无法从新选举新的节点作为主节点进行写操作,导致服务不可用。所以接下来介绍Sentinel(哨兵)功能的使用。哨兵是一个独立的进程,哨兵会实时监控master节点的状态,当master不可用时会从slave节点中选出一个作为新的master,并修改其他节点的配置指向到新的master。
该系统执行以下三个任务:
- 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
- 提醒(Notification):当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
https://www.jianshu.com/p/7d5fbf90bcd7