Redis主从复制&哨兵模式

一 什么是Redis主从复制

1.1 主从复制的架构

机器故障;容量瓶颈;QPS瓶颈

一主一从,一主多从

做读写分离

做数据副本

扩展数据性能

一个maskter可以有多个slave

一个slave只能有一个master

数据流向是单向的,从master到slave

Redis Replication是一种 master-slave 模式的复制机制,这种机制使得 slave 节点可以成为与 master 节点完全相同的副本,可以采用一主多从或者级联结构。架构如下:
在这里插入图片描述

主从复制的配置要点:

(1)配从库不配主,从库配置:slaveof 主库IP 主库端口

(2)查看redis的配置信息:info replication

1.2 主从复制的原理

  1. 副本库通过slaveof 127.0.0.1 6379命令,连接主库,并发送SYNC给主库
  2. 主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库
  3. 副本库接收后会应用RDB快照
  4. 主库会陆续将中间产生的新的操作,保存并发送给副本库
  5. 到此,我们主复制集就正常工作了
  6. 再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库.
  7. 所有复制相关信息,从info信息中都可以查到.即使重启任何节点,他的主从关系依然都在.
  8. 如果发生主从关系断开时,从库数据没有任何损坏,在下次重连之后,从库发送PSYNC给主库
  9. 主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的
    在这里插入图片描述

1.3 主库是否要开启持久化

如果不开,主库重启操作,有可能造成所有主从数据丢失!

1.4 辅助配置(主从数据一致性配置)

min-slaves-to-write 1
min-slaves-max-lag 3

#那么在从服务器的数量少于1个,或者三个从服务器的延迟(lag)值都大于或等于3秒
时,主服务器将拒绝执行写命令

二 主从复制配置

2.1 slave 命令

6380是从,6379是主

在6380上执行(去从库配置,配置主库)

slaveof 127.0.0.1 6379 #异步
slaveof no one #取消复制,不会把之前的数据清除

2.2 配置文件

# 主库
daemonize yes
port 6379
dir "/root/data"
logfile "6379.log"
# Generated by CONFIG REWRITE
slowlog-log-slower-than 0
slowlog-max-len 100
requirepass password

save 900 20
save 300 10
save 60  5
dbfilename dump.rdb

appendonly yes
appendfilename appendonly.aof
appendfsync everysec
no-appendfsync-on-rewrite yes

# 从库
daemonize yes
port 6380
dir "/root/data2"
logfile "6380.log"
# Generated by CONFIG REWRITE
slowlog-log-slower-than 0
slowlog-max-len 100
requirepass password

save 900 20
save 300 10
save 60  5
dbfilename dump.rdb

appendonly yes
appendfilename appendonly.aof
appendfsync everysec
no-appendfsync-on-rewrite yes
replicaof 127.0.0.1 6379
# 主库有密码需指定masterauth 参数
masterauth password

三 主从复制常见问题

1 读写分离

读流量分摊到从节点

可能遇到问题:复制数据延迟,读到过期数据,从节点故障

2 主从配置不一致

maxmemory不一致:丢失数据

数据结构优化参数:主节点做了优化,从节点没有设置优化,会出现一些问题

3 规避全量复制

第一次全量复制,不可避免:小主节点,低峰(夜间)

节点运行id不匹配:主节点重启(运行id变化)

复制挤压缓冲区不足:增大复制缓冲区大小,rel_backlog_size

4 规避复制风暴

单主节点复制风暴,主节点重启,所有从节点复制

四 Redis哨兵机制

在这里插入图片描述

4.1 什么是哨兵模式

在主从模式下(主从模式就是把上图的所有哨兵去掉),master节点负责写请求,然后异步同步给slave节点,从节点负责处理读请求。如果master宕机了,需要手动将从节点晋升为主节点,并且还要切换客户端的连接数据源。这就无法达到高可用,而通过哨兵模式就可以解决这一问题。

哨兵模式是Redis的高可用方式,哨兵节点是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。 哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过sentinel代理访问redis的主节点,当redis的主节点挂掉时,哨兵会第一时间感知到,并且在slave节点中重新选出来一个新的master,然后将新的master信息通知给client端,从而实现高可用。这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息。

哨兵的主要工作任务:

(1)监控:哨兵会不断地检查你的Master和Slave是否运作正常。

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

(3)自动故障迁移:当一个Master不能正常工作时,哨兵会进行自动故障迁移操作,将失
效Master的其中一个Slave升级为新的Master,并让失效Master的其他Slave改为复制新的
Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用新Master代替失效Master。

4.2 哨兵模式的搭建

步骤一:将服务调整为一主二从模式,6379带着6380、6381
步骤二:新建sentinel.conf文件,名字绝不能错
步骤三:编写sentinel.conf的内容

sentinel monitor mymaster 127.0.0.1 6379 1
sentinel auth-pass mymaster password

其中mymaster为监控对象起的服务器名称, 1 为至少有多少个哨兵同意迁移的数量。
auth-pass设置主服务器的密码。

步骤四:启动哨兵

redis-sentinel ./sentinel.conf

在这里插入图片描述

步骤五:测试哨兵是否起作用,手动关闭主服务器。

# 查看主从关系
info Replication 

# 关掉主库
shutdown

在这里插入图片描述

当主机挂掉,从机选举中产生新的主机
(大概10秒左右可以看到哨兵窗口日志,切换了新的主机)。哪个从机会被选举为主机呢?根据优先级别:replica-priority ,并且原主机重启后会变为从机。)
在这里插入图片描述

4.3 3个哨兵3个redis服务(一主两从)

第一步:搭建一主两从

# 主配置文件
daemonize yes
pidfile /var/run/redis.pid
port 6379
dir "/root/redis/data"
logfile 6379.log

# 从配置文件
daemonize yes
pidfile /var/run/redis2.pid
port 6378
dir "/root/redis/data1"
logfile 6378.log
slaveof 127.0.0.1 6379
slave-read-only yes

# 从配置文件
daemonize yes
pidfile /var/run/redis3.pid
port 6377
dir "/root/redis/data2"
logfile 6377.log
slaveof 127.0.0.1 6379
slave-read-only yes

# 启动redis服务
redis-server ./redis-6379.conf
redis-server ./redis-6378.conf
redis-server ./redis-6377.conf

第二步:搭建哨兵

# 创建三个配置文件分别叫sentinel_26379.conf sentinel_26378.conf  sentinel_26377.conf

vim sentinel_26379.conf
port 26379
daemonize yes
dir /root/redis/data
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000

vim sentinel_26378.conf
port 26378
daemonize yes
dir /root/redis/data1
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel1.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000

vim sentinel_26377.conf
port 26377
daemonize yes
dir /root/redis/data2
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel2.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000


sentinel monitor <master-name> <ip> <redis-port> <quorum>
告诉sentinel去监听地址为ip:port的一个master,这里的master-name可以自定义,quorum
是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效

sentinel auth-pass <master-name> <password>
设置连接master和slave时的密码,注意的是sentinel不能分别为master和slave设置不同的
密码,因此master和slave的密码应该设置相同。

sentinel down-after-milliseconds <master-name> <milliseconds> 
这个配置项指定了需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用
的。 单位是毫秒,默认为30秒

sentinel parallel-syncs <master-name> <numslaves> 
这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 
同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着
越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 
处于不能处理命令请求的状态。

sentinel failover-timeout <master-name> <milliseconds>
failover-timeout 可以用在以下这些方面:     
1. 同一个sentinel对同一个master两次failover之间的间隔时间。   
2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正
确的master那里同步数据时。    
3.当想要取消一个正在进行的failover所需要的时间。    
4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则
来了。

# 启动三个哨兵
redis-sentinel ./sentinel_26379.conf
redis-sentinel ./sentinel_26378.conf
redis-sentinel ./sentinel_26377.conf

第三步:登录哨兵,查看信息

redis-cli -p 26379

info

在这里插入图片描述
第四步:主库停掉,会自动做故障切换

# 连接上主库
shutdown

6378已经变成主库,6377是从库。

在这里插入图片描述

# 重新启动6379库就变成了从库

在这里插入图片描述

4.4 python操作哨兵

# python操作哨兵,代码中需要单独写了,跟之前不一样了
from redis.sentinel import Sentinel

# 连接哨兵服务器(主机名也可以用域名)
sentinel = Sentinel([
    ('127.0.0.1', 26379),
    ('127.0.0.1', 26378),
    ('127.0.0.1', 26377)
],
    socket_timeout=5)

print(sentinel)
# Sentinel<sentinels=[127.0.0.1:26379,127.0.0.1:26378,127.0.0.1:26377]>

# 获取主服务器地址
master = sentinel.discover_master('mymaster')
print(master)
# ('127.0.0.1', 6379)

# 获取从服务器地址
slave = sentinel.discover_slaves('mymaster')
print(slave)
# [('127.0.0.1', 6377), ('127.0.0.1', 6378)]

##### 读写分离
# 获取主服务器进行写入
master = sentinel.master_for('mymaster', socket_timeout=5)
master.set('name', 'xuxiaoxu')
master.set('age', 18)

slave = sentinel.slave_for('mymaster', socket_timeout=5)
name = slave.get('name')
age = slave.get('age')
print(name)
# b'xuxiaoxu'
print(age)
# b'18'

猜你喜欢

转载自blog.csdn.net/weixin_68531269/article/details/128537213