redis主从集群架构图如下:

wKiom1cjPE-jZb1QAADi_DezMAw835.png

1.sentinel 说明

 (1)监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。

 (2)提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

 (3)自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。


Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。


2.redis 主从同步原理

(1)Slave服务器连接到master服务器.

(2)Slave服务器发送SYCN命令.

(3)Master服务器备份数据库到.rdb文件.

(4)Master服务器把.rdb文件传输给Slave服务器.

(5)Slave服务器把.rdb文件数据导入到数据库中.


3.架构规划

master:10.1.1.8:6379

salve1:10.1.1.11:6379

salve2:10.1.1.12:6379

salve3:10.1.1.13:6379


sentinel:10.1.1.11:26379

sentinel:10.1.1.12:26379

sentinel:10.1.1.13:26379


4.主从配置

安装redis略过

3.1.配置主从

配置主:

master:10.1.1.8

vim /etc/redis.conf
daemonize yes  //守护进程
pidfile "/var/run/redis.conf.pid"  //pid路径
port 6379   //监听端口
bind 0.0.0.0  //绑定地址
timeout 300  //超时时间
loglevel notice //日志级别
logfile "/data/redis/redis-server.log" //日志路径
databases 16  //实例个数
save 900 1  //900秒有1个变化写磁盘
save 300 10  //300秒有10个变化写磁盘
save 60 10000 //60秒有10000个变化写磁盘
rdbcompression yes  //支持RDB压缩
dbfilename "dump.rdb" //DB文件名
dir "/data/redis/lib" //RDB路径
slave-serve-stale-data yes  //如果 slave-serve-stale-data 设置成 'yes' (the default) slave会仍然响应客户端请求,此时可能会有问题。
appendonly no  //AOF关闭
appendfsync everysec  //每秒进行一次写磁盘
no-appendfsync-on-rewrite no //append only 文件的自动重写, 当AOF 日志文件即将增长到指定百分比时,Redis可以通过调用BGREWRITEAOF 来自动重写append only文件。
list-max-ziplist-entries 512 
list-max-ziplist-value 64 //如果set中整型元素的数量不超过512时,Redis将会采用该特殊编码
set-max-intset-entries 512
activerehashing yes //指定是否激活重置哈希,默认为开启
masterauth "456789" //认证密码
requirepass "456789"


配置slave1:

salve1:10.1.1.11:6379

daemonize yes
pidfile "/var/run/redis/redis-server.pid"
port 6379
bind 0.0.0.0
timeout 300
loglevel notice
logfile "/data/redis/redis-server.log"
databases 16
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename "dump.rdb"
dir "/data/redis/lib"
slave-serve-stale-data yes
appendonly no
appendfsync everysec
no-appendfsync-on-rewrite no
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
activerehashing yes
masterauth "456789"
requirepass "456789"
slaveof 10.1.1.8 6379

配置salve2:

salve1:10.1.1.12:6379

配置同slave1一致


配置salve3:

salve1:10.1.1.13:6379

配置同slave1一致


4.启动进程

启动master:10.1.1.8:

/usr/local/bin/redis-server /etc/redis.conf

启动salve1:10.1.1.11:6379

/usr/local/bin/redis-server /etc/redis.conf

启动salve2:10.1.1.12:6379

/usr/local/bin/redis-server /etc/redis.conf

启动salve3:10.1.1.13:6379

/usr/local/bin/redis-server /etc/redis.conf

查看master日志:

cat /data/redis/redis-server.log
....
16337:M 29 Apr 16:40:00.335 * DB loaded from disk: 0.000 seconds
16337:M 29 Apr 16:40:00.335 * The server is now ready to accept connections on port 6379
16337:M 29 Apr 16:40:14.757 * Slave 10.1.1.11:6379 asks for synchronization
16337:M 29 Apr 16:40:14.757 * Full resync requested by slave 10.1.1.11:6379
16337:M 29 Apr 16:40:14.757 * Starting BGSAVE for SYNC with target: disk
16337:M 29 Apr 16:40:14.757 * Background saving started by pid 16346
16346:C 29 Apr 16:40:14.765 * DB saved on disk
16346:C 29 Apr 16:40:14.766 * RDB: 6 MB of memory used by copy-on-write
16337:M 29 Apr 16:40:14.864 * Background saving terminated with success
16337:M 29 Apr 16:40:14.864 * Synchronization with slave 10.1.1.11:6379 succeeded //salve1 同步ok
16337:M 29 Apr 16:40:33.200 * Slave 10.1.1.12:6379 asks for synchronization
16337:M 29 Apr 16:40:33.200 * Full resync requested by slave 10.1.1.12:6379
16337:M 29 Apr 16:40:33.200 * Starting BGSAVE for SYNC with target: disk
16337:M 29 Apr 16:40:33.201 * Background saving started by pid 16347
16347:C 29 Apr 16:40:33.219 * DB saved on disk
16347:C 29 Apr 16:40:33.220 * RDB: 6 MB of memory used by copy-on-write
16337:M 29 Apr 16:40:33.308 * Background saving terminated with success
16337:M 29 Apr 16:40:33.308 * Synchronization with slave 10.1.1.12:6379 succeeded //salve2 同步ok
16337:M 29 Apr 16:40:35.257 * Slave 10.1.1.13:6379 asks for synchronization
16337:M 29 Apr 16:40:35.257 * Full resync requested by slave 10.1.1.13:6379
16337:M 29 Apr 16:40:35.258 * Starting BGSAVE for SYNC with target: disk
16337:M 29 Apr 16:40:35.260 * Background saving started by pid 16348
16348:C 29 Apr 16:40:35.274 * DB saved on disk
16348:C 29 Apr 16:40:35.275 * RDB: 8 MB of memory used by copy-on-write
16337:M 29 Apr 16:40:35.315 * Background saving terminated with success
16337:M 29 Apr 16:40:35.315 * Synchronization with slave 10.1.1.13:6379 succeeded //salve3 同步ok

登录主查看同步信息:

127.0.0.1:6379> info
....
# Replication
role:master    //角色未主
connected_slaves:3  //3个slave解决
slave0:ip=10.1.1.11,port=6379,state=online,offset=71,lag=1 //salve1信息
slave1:ip=10.1.1.12,port=6379,state=online,offset=71,lag=1 //slave2信息
slave2:ip=10.1.1.13,port=6379,state=online,offset=71,lag=1 //slave3信息
master_repl_offset:71  //复制偏移量
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:70
....

5.测试主从:

主上插入数据:

# /usr/local/bin/redis-cli 
127.0.0.1:6379> set name "ckl"
OK

salve1查看:

127.0.0.1:6379> get name
"ckl"
127.0.0.1:6379>

salve2查看:

127.0.0.1:6379> get name
"ckl"
127.0.0.1:6379>

salve3查看:

127.0.0.1:6379> get name
"ckl"
127.0.0.1:6379>

6.配置sentinel

配置sentinel:10.1.1.11:26379:

port 26379  
daemonize yes   
sentinel monitor ckl_master 10.1.1.12 6379 2 
sentinel failover-timeout ckl_master 900000 
sentinel auth-pass ckl_master 456789 
sentinel config-epoch ckl_master 1   
sentinel leader-epoch ckl_master 1  
logfile "/data/redis/sentinel.log"

配置文件解释:

port 26379  
#指定启动的端口

daemonize yes   
#后台守护进程启动

sentinel monitor ckl_master 10.1.1.12 6379 2 
#让sentinel去监控名称为ckl_master 的主节点,ip为10.1.1.8 端口为6379 当两个sentinel检测到失败,才执行切换

sentinel failover-timeout ckl_master 900000 
#sentinel判断master断开时间,默认为毫秒

sentinel auth-pass ckl_master 456789 
#设置认证密码

sentinel config-epoch ckl_master 1   
#从节点由于故障转移事件被提升为主节点时,为了取代它那失效的主节点,会把 configEpoch 设置为它赢得选举的时候的 configEpoch值。

logfile "/data/redis/sentinel.log"  
#指定日志路径

配置sentine2:10.1.1.12:26379:

同sentinel配置一致


配置sentine3:10.1.1.13:26379:

同sentinel配置一致


7.启动sentinel

启动sentine1:10.1.1.11:26379:

/usr/local/bin/redis-sentinel /etc/sentinel.conf

启动sentine2:10.1.1.12:26379:

/usr/local/bin/redis-sentinel /etc/sentinel.conf

启动sentine3:10.1.1.13:26379:

/usr/local/bin/redis-sentinel /etc/sentinel.conf

查看进程:

# ps -ef | grep redis
root     11360     1  0 16:40 ?        00:00:03 /usr/local/bin/redis-server 0.0.0.0:6379   
root     11437     1  0 18:06 ?        00:00:00 /usr/local/bin/redis-sentinel *:26379           
root     11443 11306  0 18:07 pts/1    00:00:00 grep redis

查看sentinel日志:

...
[11501] 29 Apr 18:06:23.656 # Sentinel runid is 2535af9a6926391270af19cb872c93a1cd499ea9
[11501] 29 Apr 18:06:23.656 # +monitor master ckl_master 10.1.1.8 6379 quorum 2
[11501] 29 Apr 18:06:23.657 * +slave slave 10.1.1.11:6379 10.1.1.11 6379 @ ckl_master 10.1.1.8 6379 //salve1同主的信息
[11501] 29 Apr 18:06:23.704 * +slave slave 10.1.1.12:6379 10.1.1.12 6379 @ ckl_master 10.1.1.8 6379 //salve2同主的信息
[11501] 29 Apr 18:06:23.711 * +slave slave 10.1.1.13:6379 10.1.1.13 6379 @ ckl_master 10.1.1.8 6379 //salve3同主的信息
[11501] 29 Apr 18:06:23.973 * +sentinel sentinel 10.1.1.12:26379 10.1.1.12 26379 @ ckl_master 10.1.1.8 6379
[11501] 29 Apr 18:06:25.133 * +sentinel sentinel 10.1.1.11:26379 10.1.1.11 26379 @ ckl_master 10.1.1.8 6379
...

发现sentinel配置文件发生变化,增加了如下:

# Generated by CONFIG REWRITE
dir "/home/chenkangle"
sentinel known-slave ckl_master 10.1.1.13 6379 
sentinel known-slave ckl_master 10.1.1.11 6379
sentinel known-slave ckl_master 10.1.1.12 6379
sentinel known-sentinel ckl_master 10.1.1.12 26379 3feafdc8dd9dd92bc01034ce2d059db517c2feee
sentinel known-sentinel ckl_master 10.1.1.13 26379 2535af9a6926391270af19cb872c93a1cd499ea9
sentinel current-epoch 1

登录到3个sentinel中的一个查看信息:

# /usr/local/bin/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
master0:name=qm_master,status=ok,address=10.1.1.8:6379,slaves=3,sentinels=3
....

8.sentinel检测主节点下线原理

主观下线和客观下线

    (1)主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。

    (2)客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。


客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 Sentinel 永远不会达到客观下线条件。

只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对失效的主服务器执行自动故障迁移操作。


每个Sentinel实例都执行的定时任务

    (1) 每个 Sentinel 以每秒钟一次的频率向它所知的主服务器、从服务器以及其他 Sentinel 实例发送一个 PING 命令。

    (2)  如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个实例会被 Sentinel 标记为主观下线。 一个有效回复可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。

    (3) 如果一个主服务器被标记为主观下线, 那么正在监视这个主服务器的所有 Sentinel 要以每秒一次的频率确认主服务器的确进入了主观下线状态。

    (4)  如果一个主服务器被标记为主观下线, 并且有足够数量的 Sentinel (至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断, 那么这个主服务器被标记为客观下线。

    (5)  在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。 当一个主服务器被 Sentinel 标记为客观下线时, Sentinel 向下线主服务器的所有从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。

    (6)  当没有足够数量的 Sentinel 同意主服务器已经下线, 主服务器的客观下线状态就会被移除。 当主服务器重新向 Sentinel 的 PING 命令返回有效回复时, 主服务器的主管下线状态就会被移除。


9.模拟测试主节点down掉:

# /usr/local/bin/redis-cli 
127.0.0.1:6379> SHUTDOWN

查看sentinel日志:

# tailf /data/redis/sentinel.log 
...
[11501] 29 Apr 18:23:17.377 # +sdown master ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:17.435 # +odown master ckl_master10.1.1.8 6379 #quorum 3/2  //3分之2检测到节点down掉
[11501] 29 Apr 18:23:17.435 # +new-epoch 2
[11501] 29 Apr 18:23:17.435 # +try-failover master ckl_master10.1.1.8 6379  //主解决故障转移
[11501] 29 Apr 18:23:17.442 # +vote-for-leader 2535af9a6926391270af19cb872c93a1cd499ea9 2
[11501] 29 Apr 18:23:17.455 # 10.1.1.12:26379 voted for 2535af9a6926391270af19cb872c93a1cd499ea9 2
[11501] 29 Apr 18:23:17.456 # 10.1.1.11:26379 voted for 2535af9a6926391270af19cb872c93a1cd499ea9 2
[11501] 29 Apr 18:23:17.534 # +elected-leader master ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:17.534 # +failover-state-select-slave master ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:17.634 # +selected-slave slave 10.1.1.11:6379 10.1.1.116379 @ ckl_master10.1.1.8 6379 //选举新的主节点
[11501] 29 Apr 18:23:17.635 * +failover-state-send-slaveof-noone slave 10.1.1.11:6379 10.1.1.116379 @ ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:17.711 * +failover-state-wait-promotion slave 10.1.1.11:6379 10.1.1.116379 @ ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:18.535 # +promoted-slave slave 10.1.1.11:6379 10.1.1.116379 @ ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:18.535 # +failover-state-reconf-slaves master ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:18.541 * +slave-reconf-sent slave 10.1.1.13:6379 10.1.1.136379 @ ckl_master10.1.1.8 6379 //重设配置指定新的主节点
[11501] 29 Apr 18:23:19.532 * +slave-reconf-inprog slave 10.1.1.13:6379 10.1.1.136379 @ ckl_master10.1.1.8 6379 
[11501] 29 Apr 18:23:19.532 * +slave-reconf-done slave 10.1.1.13:6379 10.1.1.136379 @ ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:19.584 # -odown master ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:19.584 * +slave-reconf-sent slave 10.1.1.12:6379 10.1.1.12 6379 @ ckl_master10.1.1.8 6379 //重设配置指定新的主节点
[11501] 29 Apr 18:23:20.589 * +slave-reconf-inprog slave 10.1.1.12:6379 10.1.1.12 6379 @ ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:20.589 * +slave-reconf-done slave 10.1.1.12:6379 10.1.1.12 6379 @ ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:20.640 # +failover-end master ckl_master10.1.1.8 6379
[11501] 29 Apr 18:23:20.640 # +switch-master ckl_master10.1.1.8 6379 10.1.1.116379
[11501] 29 Apr 18:23:20.640 * +slave slave 10.1.1.13:6379 10.1.1.136379 @ ckl_master10.1.1.116379
[11501] 29 Apr 18:23:20.640 * +slave slave 10.1.1.12:6379 10.1.1.12 6379 @ ckl_master10.1.1.116379
[11501] 29 Apr 18:23:20.641 * +slave slave 10.1.1.8:6379 10.1.1.8 6379 @ ckl_master10.1.1.116379
[11501] 29 Apr 18:23:50.669 # +sdown slave 10.1.1.8:6379 10.1.1.8 6379 @ ckl_master10.1.1.116379

查看新选举的主节点信息:

10.1.1.11

# /usr/local/bin/redis-cli
127.0.0.1:6379> info
....
# Replication
role:master
connected_slaves:2
slave0:ip=10.1.1.13,port=6379,state=online,offset=67708,lag=0
slave1:ip=10.1.1.12,port=6379,state=online,offset=67852,lag=0
master_repl_offset:67852
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:67851

测试新的主从同步:

10.1.1.11:6379

# /usr/local/bin/redis-cli
127.0.0.1:6379> set port "1090"


10.1.1.12:6379

127.0.0.1:6379> get port
"1090"


10.1.1.13:6379

127.0.0.1:6379> get port
"1090"