Redis主从复制与哨兵模式
redis.conf 配置文件
- redis.conf 配置项说明如下:
Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程, 在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程。但当daemonize选项设置成no时,当前界面将进入redis的命令行界面,exit强制退出或者关闭连接工具(putty,xshell等)都会导致redis进程退出。
daemonize no
当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
pidfile /var/run/redis.pid
指定Redis监听端口,默认端口为6379,为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字
port 6379
绑定的主机地址
bind 127.0.0.1
当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
timeout 300
指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
loglevel verbose
日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
logfile stdout
设置数据库的数量,默认数据库为0,可以使用
SELECT <dbid>
命令在连接上指定数据库iddatabases 16
指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
save <seconds> <changes>
- Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000 - 分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。
- Redis默认配置文件中提供了三个条件:
指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
rdbcompression yes
指定本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
指定本地数据库存放目录
dir ./
设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
slaveof <masterip> <masterport>
当master服务设置了密码保护时,slav服务连接master的密码
masterauth <master-password>
设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过
AUTH <password>
命令提供密码,默认关闭requirepass 123456
设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置
maxclients 0
,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息maxclients 128
指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
maxmemory <bytes>
指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no
指定更新日志文件名,默认为appendonly.aof
appendfilename appendonly.aof
指定更新日志条件,共有3个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
everysec:表示每秒同步一次(折中,默认值)
appendfsync everysec指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)
vm-enabled no
虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap
将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0
vm-max-memory 0
Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值
vm-page-size 32
设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。
vm-pages 134217728
设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4
vm-max-threads 4
设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
glueoutputbuf yes
指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)
activerehashing yes
指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include /path/to/local.conf
Redis中的内存维护策略: redis作为优秀的中间缓存件,时常会存储大量的数据,即使采取了集群部署来动态扩容,也应该即使的整理内存,维持系统性能。在redis中有两种解决方案
- 一是为数据设置超时时间,
- 二是采用LRU算法动态将不用的数据删除。内存管理的一种页面置换算法,对于在内存中但又不用的数据块(内存块)叫做LRU,操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据。
- volatile-lru:设定超时时间的数据中,删除最不常使用的数据.
- allkeys-lru:查询所有的key中最近最不常使用的数据进行删除,这是应用最广泛的策略.
- volatile-random:在已经设定了超时的数据中随机删除.
- allkeys-random:查询所有的key,之后随机删除.
- volatile-ttl:查询全部设定超时时间的数据,之后排序,将马上将要过期的数据进行删除操作.
- noeviction:如果设置为该属性,则不会进行删除操作,如果内存溢出则报错返回.
- volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
- allkeys-lfu:从所有键中驱逐使用频率最少的键
主从复制
redis服务器的硬盘损坏了可能会导致数据丢失, 主从复制机制就可以避免单点故障,设置一个主数据库和n个从数据库
所有的写操作都在主数据库执行
读操作在从数据库执行
为保证数据的一致性,将主数据库的数据会复制到从数据库。
说明:
主redis中的数据有两个副本(replication)即从redis1和从redis2,即使一台redis服务器宕机其它两台redis服务也可以继续提供服务。
主redis中的数据和从redis上的数据保持实时同步,当主redis写入数据时通过主从复制机制会复制到两个从redis服务上。
只有一个主redis,可以有多个从redis。
主从复制不会阻塞master,在同步数据时,master 可以继续处理client 请求
一个redis可以即是主又是从,如下图:
设置主从复制
- 192.168.2.100为主服务器,192.168.2.101为从服务器
配置主服务器配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13[root@localhost redis-4.0.10]# vim /etc/redis/6379.conf
# 1. 将bind 127.0.0.1这行注释或者指定ip。(本例是注释,即所有ip都能连接)
# bind 127.0.0.1
# 2. 开启守护进程
daemonize yes
# 3. 设置访问密码 建议线上把密码设置非常复杂,最好能在第2步中指定ip
requirepass 123456
# 4. 设置客户端最大连接数(maxclients),默认是10000,可根据需求更改
maxclients 10000
# 5. 最大内存(默认不受限制,建议还是设置个低于服务器内存的值)
# maxmemory <bytes>
# 6. 内存策略,如果内存足够用则不用管,如果内存不够用,建议设置最近最少使用策略(LRU),默认是内存不够则报错
# maxmemory-policy noevication使用配置文件启动redis服务
1
[root@localhost redis-4.0.10]# service redisd start
配置从服务器有2种方式:
- 在redis.conf中设置slaveof :
slaveof <masterip> <masterport>
- 使用redis-cli客户端连接到redis服务,执行slaveof命令:
slaveof <masterip> <masterport>
,重启后将失去主从复制关系 - 5.0后新版本的命令是replicaof,旧版本是slaveof命令
1
2
3
4
5
6
7
8
9
10# 1. 前四步与主服务器配置基本一致
# 2. 配置所属主服务器ip和端口
slaveof 192.168.2.100 6379
# replicaof 192.168.2.100 6379
# 3. 配置所属主服务器的密码
masterauth 123456
# 4. 从服务器通常是只读,所以要配置只读(默认是只读,不要更改即可)
slave-read-only yes
# replica-read-only yes
# 5. 如果是同一机器下 port 更改为与主redis(6379)不相同既可- 在redis.conf中设置slaveof :
启动从节点的redis
1
./redis-server ~/config/slave/redis.conf &
Redis客户端连接上6379端口,查看Redis主从关系
- role:角色信息
- slaveX:从库信息
- connected_slaves:从库数量
# 查看主从信息 info replication
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
## Sentinel哨兵模式
- 主从复制同时存在以下几个问题:
- 一旦主节点宕机,从节点晋升成主节点,同时需要修改应用方的主节点地址,还需要命令所有 从节点去复制新的主节点,整个过程需要人工干预。
- 主节点的写能力受到单机的限制。
- 主节点的存储能力受到单机的限制。
- 原生复制的弊端在早期的版本中也会比较突出,比如:Redis 复制中断后,从节点会发起 psync。此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时,可能会造成毫秒或秒级的卡顿。
### Sentinel的架构
- Sentinel[ˈsentɪnl],哨兵机制就是解决我们以上主从复制存在缺陷(选举问题),保证我们的Redis高可用,实现自动化故障发现与故障转移。
- 该系统执行以下三个任务:
- 监控:哨兵会不断检查你的主服务器和从服务器是否运作正常。
- 提醒:当被监控的某个Redis服务器出现问题时,哨兵可以通过API给程序员发送通知
- 自动故障转移:主服务器宕机,哨兵会开始一次自动故障转移操作,升级一个从服务器为主服务器,并让其他从服务器改为复制新的主服务器.
- 配置提供者:在 Redis Sentinel 模式下,客户端应用在初始化时连接的是 Sentinel 节点集合,从中获取主节点的信息。
![](6-Redis主从复制与哨兵模式/24151fd4648b290dae9b8e664208eafa.jpg)
### Sentinel配置
- Redis 源码中包含了一个名为 sentinel.conf 的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。
- 运行一个 Sentinel 所需的最少配置如下所示:
```sh
1)sentinel monitor mymaster 192.168.10.202 6379 2
Sentine监听的maste地址,第一个参数是给master起的名字,第二个参数为master IP,第三个为master端口,第四个为当该master挂了的时候,若想将该master判为失效,
在Sentine集群中必须至少2个Sentinel同意才行,只要该数量不达标,则就不会发生故障迁移。
值一般为:sentinel总数/2 +1 ,master才算真正失效
2)sentinel down-after-milliseconds mymaster 30000
表示master被当前sentinel实例认定为失效的间隔时间,在这段时间内一直没有给Sentine返回有效信息,则认定该master主观下线。
只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线,将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。
3)sentinel parallel-syncs mymaster 2
当在执行故障转移时,设置几个slave同时进行切换master,该值越大,则可能就有越多的slave在切换master时不可用,可以将该值设置为1,即一个一个来,这样在某个
slave进行切换master同步数据时,其余的slave还能正常工作,以此保证每次只有一个从服务器处于不能处理命令请求的状态。
4)sentinel can-failover mymaster yes
在sentinel检测到O_DOWN后,是否对这台redis启动failover机制
5)sentinel auth-pass mymaster 20180408
设置sentinel连接的master和slave的密码,这个需要和redis.conf文件中设置的密码一样
6)sentinel failover-timeout mymaster 180000
failover过期时间,当failover开始后,在此时间内仍然没有触发任何failover操作,当前sentinel将会认为此次failoer失败。
执行故障迁移超时时间,即在指定时间内没有大多数的sentinel 反馈master下线,该故障迁移计划则失效
7)sentinel config-epoch mymaster 0
选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步。这个数字越小, 完成故障转移所需的时间就越长。
8)sentinel notification-script mymaster /var/redis/notify.sh
当failover时,可以指定一个"通知"脚本用来告知当前集群的情况。
脚本被允许执行的最大时间为60秒,如果超时,脚本将会被终止(KILL)
9)sentinel leader-epoch mymaster 0
同时一时间最多0个slave可同时更新配置,建议数字不要太大,以免影响正常对外提供服务。
1 | ### 搭建 |
1 | port 26380 |
启动
1
2
3
4
5[root@zy01 redis]# mkdir data
[root@zy01 redis]# cd conf/
[root@zy01 conf]# redis-sentinel sentinel1.conf
[root@zy01 conf]# redis-sentinel sentinel2.conf查看文件
cat sentinel1.conf
,在最后出现了下面的一些内容1
2
3
4
5
6
7
8
9
10# Generated by CONFIG REWRITE
protected-mode no
user default on nopass ~* &* +@all
sentinel myid 95e50b7f9db387c25b0d0a33cdfe1744f52f67dc
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel current-epoch 0
sentinel known-replica mymaster 127.0.0.1 6381
sentinel known-replica mymaster 127.0.0.1 6380
sentinel known-sentinel mymaster 127.0.0.1 26380 9c31e456f0bfd3fbad41dddaedfa64d2a11970e6连接哨兵节点
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94[root@zy01 conf]# redis-cli -p 26379
127.0.0.1:26379> ping
PONG
127.0.0.1:26379> info
# Server
redis_version:6.2.3
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:37744dab1e0d5d0c
redis_mode:sentinel
os:Linux 4.18.0-80.el8.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:8.3.1
process_id:22026
process_supervised:no
run_id:fbf4cf65e97342c3afacfc50e5b036fc456e0e90
tcp_port:26379
server_time_usec:1621866579936231
uptime_in_seconds:308
uptime_in_days:0
hz:11
configured_hz:10
lru_clock:11253843
executable:/usr/local/redis/conf/redis-sentinel
config_file:/usr/local/redis/conf/sentinel1.conf
io_threads_active:0
# Clients
connected_clients:2
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:32
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0
# CPU
used_cpu_sys:0.515450
used_cpu_user:0.291560
used_cpu_sys_children:0.000000
used_cpu_user_children:0.000000
used_cpu_sys_main_thread:0.511878
used_cpu_user_main_thread:0.282033
# Stats
total_connections_received:3
total_commands_processed:409
instantaneous_ops_per_sec:2
total_net_input_bytes:21986
total_net_output_bytes:7010
instantaneous_input_kbps:0.14
instantaneous_output_kbps:0.02
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:7
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
total_forks:0
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:1
dump_payload_sanitizations:0
total_reads_processed:402
total_writes_processed:400
io_threaded_reads_processed:0
io_threaded_writes_processed:0
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=2通过哨兵查看集群状态
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[root@alex redis-4.0.10]# ./src/redis-cli -p 26379
127.0.0.1:26379> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "172.16.0.169"
5) "port"
6) "6379"
7) "runid"
127.0.0.1:26379> sentinel slaves mymaster
1) 1) "name" # slave 1
2) "127.0.0.1:6381"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6381"
7) "runid"
8) "0419f313098f6af1b4ccdb189d6beb22edf27a1c"
2) 1) "name" # slave2
2) "127.0.0.1:6380"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6380"
7) "runid"
8) "5b00b502a93245f7916efd1f564bd40b16aa7b22"模拟主节点down掉,观察sentinel的状态
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# 模拟主down掉
[zy@zy01 ~]$ ps -ef | grep redis
root 21780 1 0 21:46 ? 00:00:03 redis-server 127.0.0.1:6379
root 21786 1 0 21:46 ? 00:00:02 redis-server 127.0.0.1:6380
root 21794 1 0 21:46 ? 00:00:02 redis-server 127.0.0.1:6381
root 22026 1 0 22:24 ? 00:00:01 redis-sentinel *:26379 [sentinel]
root 22032 1 0 22:25 ? 00:00:01 redis-sentinel *:26380 [sentinel]
root 22039 15820 0 22:29 pts/2 00:00:00 redis-cli -p 26379
zy 22044 21807 0 22:35 pts/1 00:00:00 grep --color=auto redis
[zy@zy01 ~]$ sudo kill -9 21780
# 查看节点
127.0.0.1:26379> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6380" # 已经从6379切换到6380
7) "runid"
8) "0419f313098f6af1b4ccdb189d6beb22edf27a1c"
# 相应的slave也做了切换
127.0.0.1:26379> sentinel slaves mymaster
1) 1) "name"
2) "127.0.0.1:6379"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6379"
7) "runid"
8) ""
9) "flags"
10) "s_down,slave,disconnected"
2) 1) "name"
2) "127.0.0.1:6380"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6381"
7) "runid"
8) "5b00b502a93245f7916efd1f564bd40b16aa7b22"
日志分析
打开哨兵的日志
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 该哨兵认为该节点已经主观宕机,也就是sdown
5508:X 28 May 2021 16:09:30.105 # +sdown master mymaster 192.168.56.101 6379
# 哨兵集群内有超过两个哨兵都认为master sdown了,因此转化成客观宕机,也就是odown。
5508:X 28 May 2021 16:09:30.196 # +odown master mymaster 192.168.56.101 6379 #quorum 2/2
# 递增集群状态版本号,这个版本号将被接下来选举出的新的master采用。
5508:X 28 May 2021 16:09:30.196 # +new-epoch 1
# 开始对IP为192.168.50.121,端口为6379,名为"mymaster"的Redis集群进行故障转移。
5508:X 28 May 2021 16:09:30.196 # +try-failover master mymaster 192.168.56.101 6379
# 在哨兵集群中投票选举出一个哨兵,作为本次执行故障转移操作的leader。 当前哨兵投票给自己满意的slave
5508:X 28 May 2021 16:09:30.200 # +vote-for-leader c990635de9ed91282027c9ab9a3167ac4b4087b4 1
# 另一个哨兵投票给自己满意的slave
5508:X 28 May 2021 16:09:30.208 # 68ff8149e5eefeb2da9685172c5f01844a63480e voted for c990635de9ed91282027c9ab9a3167ac4b4087b4 1
# 在哨兵集群中再次确认进行故障转移的leader是哪一个slave。
5508:X 28 May 2021 16:09:30.285 # +elected-leader master mymaster 192.168.56.101 6379
# leader开始在集群中寻找合适的slave。(从这里可以看出,找出新的slave不单单是通过投票,可能还和其它的因素有关。)
5508:X 28 May 2021 16:09:30.285 # +failover-state-select-slave master mymaster 192.168.56.101 6379
5508:X 28 May 2021 16:09:30.358 # -failover-abort-no-good-slave master mymaster 192.168.56.101 6379
5508:X 28 May 2021 16:09:30.434 # Next failover delay: I will not start a failover before Fri May 28 16:15:30 2021
5508:X 28 May 2021 16:15:30.388 # +new-epoch 2
主观下线和客观下线
- 主观下线:指的是单个 Sentinel 实例对服务器做出的下线判断。
- 客观下线:指的是多个 Sentinel 实例在对同一个服务器做出SDOWN主观下线判断。
Sentinel的工作原理
每个 Sentinel 以每秒一次的频率向它所知的主服务器、从服务器以及其他 Sentinel 实例发送一个 PING 命令。
如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel 标记为主观下线。
如果一个主服务器被标记为主观下线,那么正在监视这个服务器的所有 Sentinel 节点,要以每秒一次的频率确认主服务器的确进入了主观下线状态。
如果一个主服务器被标记为主观下线,并且有足够数量的 Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线。
一般情况下,每个 Sentinel 会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。
当一个主服务器被标记为客观下线时,Sentinel 向下线主服务器的所有从服务器发送 INFO 命令的频率,会从 10 秒一次改为每秒一次。
Sentinel 和其他 Sentinel 协商客观下线的主节点的状态,如果处于 SDOWN 状态,则投票自动选出新的主节点,将剩余从节点指向新的主节点进行数据复制。
当没有足够数量的 Sentinel 同意主服务器下线时,主服务器的客观下线状态就会被移除。
当主服务器重新向 Sentinel 的 PING 命令返回有效回复时,主服务器的主观下线状态就会被移除。
两种数据丢失的情况
- 主备切换的过程,可能会导致数据丢失
- 异步复制导致的数据丢失: old master node 中内存的数据没来得及给slave node就挂了,重新选举后的master会丢失这部分数据。
- 脑裂导致的数据丢失:某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着,此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master这个时候,集群里就会有两个master,也就是所谓的脑裂。此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了,因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据
减少异步复制数据丢失
min-slaves-max-lag 10
:数据复制和同步的延迟不能超过10秒- 如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了,上面两个配置可以减少异步复制和脑裂导致的数据丢失
- 有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
- 客户端做降级处理,写到本地磁盘,client对外的接收请求做降级限流处理,减慢请求速度,或者将数据临时写入kafka消息队列,每隔10分钟去队列去除,尝试重新发送到master节点。
减少脑裂的数据丢失
min-slaves-to-write 1
:要求至少有1个slave如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置同时配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求,因此在脑裂场景下,最多就丢失10秒的数据