1、主从复制
1.1 介绍
主从复制:
一个服务器去复制另一个服务器,被复制的服务器为主服务器 master,复制的服务器为从服务器 slave。
- master 用来写数据,执行写操作时,将出现变化的数据自动同步到 slave,很少会进行读取操作
- slave 用来读数据,禁止在 slave 服务器上进行读操作
进行复制中的主从服务器双方的数据库将保存相同的数据,将这种现象称作数据库状态一致。
主从复制的特点:
- 薪火相传:一个 slave 可以是下一个 slave 的 master,slave 同样可以接收其他 slave 的连接和同步请求,那么该 slave 作为了链条中下一个的 master,可以有效减轻 master 的写压力,去中心化降低风险注意:主机挂了,从机还是从机,无法写数据了
- 反客为主:当一个 master 宕机后,后面的 slave 可以立刻升为 master,其后面的 slave 不做任何修改
主从复制的作用:
- 读写分离:master 写、slave 读,提高服务器的读写负载能力
- 负载均衡:基于主从结构,配合读写分离,由 slave 分担 master 负载,并根据需求的变化,改变 slave 的数量,通过多个从节点分担数据读取负载,大大提高 Redis 服务器并发量与数据吞吐量
- 故障恢复:当 master 出现问题时,由 slave 提供服务,实现快速的故障恢复
- 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
- 高可用基石:基于主从复制,构建哨兵模式与集群,实现 Redis 的高可用方案
三高架构:
- 高并发:应用提供某一业务要能支持很多客户端同时访问的能力,称为并发
- 高性能:性能最直观的感受就是速度快,时间短
- 高可用:
- 可用性:应用服务在全年宕机的时间加在一起就是全年应用服务不可用的时间
- 业界可用性目标 5 个 9,即 99.999%,即服务器年宕机时长低于 315 秒,约 5.25 分钟
1.2 搭建主从
(1)master节点配置
首先,我们打开master节点文件,文件位于vi/usr/local/redis/redis.conf目录下,然后修改配置如下:
bind 192.168.182.110 # 监听ip,多个ip用空格分隔
daemonize yes # 允许后台启动
logfile "/usr/local/redis/redis.log" # 日志路径
dir /opt/software/redis-7.0.3/data # 数据库备份文件存放目录
requirepass 123456 # 设置master连接密码,slave可省略
appendonly yes # 在/opt/software/redis-7.0.3/data目录生成appendonly.aof文件,
将每一次写操作请求都追加到appendonly.aof 文件中。
(2)slave1节点配置
接着,我们打开slave1节点文件,文件位于vi/usr/local/redis/redis.conf,修改配置如下:
bind 192.168.182.111 # 监听ip,多个ip用空格分隔
daemonize yes # 允许后台启动
logfile "/usr/local/redis/redis.log" # 日志路径
dir /opt/software/redis-7.0.3/data # 数据库备份文件存放目录
replicaof 192.168.182.110 6379 # replicaof用于追随某个节点的redis,被追随的节点为主节点,
追随的为从节点。就是设置master节点。
在5.0版本之前版本使用slaveof,之后版本使用replicaof。
masterauth 123456 # slave连接master密码,master可省略
appendonly yes # 在/opt/software/redis-7.0.3/data目录生成appendonly.aof文件,
将每一次写操作请求都追加到appendonly.aof 文件中
(3)slave2节点配置
打开slave2的节点文件,文件位于vi/usr/local/redis/redis.conf,修改配置如下:
bind 192.168.182.112 # 监听ip,多个ip用空格分隔
daemonize yes # 允许后台启动
logfile "/usr/local/redis/redis.log" # 日志路径
dir /opt/software/redis-7.0.3/data # 数据库备份文件存放目录
replicaof 192.168.182.110 6379 # replicaof用于追随某个节点的redis,被追随的节点为主节点,
追随的为从节点。就是设置master节点。
在5.0版本之前版本使用slaveof,之后版本使用replicaof。
masterauth 123456 # slave连接master密码,master可省略
requirepass 123456 # 设置master连接密码,slave可省略
appendonly yes # 在/opt/software/redis-7.0.3/data目录生成appendonly.aof文件,
将每一次写操作请求都追加到appendonly.aof 文件中
(4)启动各个redis服务
systemctl start redis # 启动redis
systemctl status redis # 查看redis状态
(5)查看集群
然后,使用下面的命令查看集群的一些数据:
# 交互式
redis-cli -h 192.168.182.110 -a 123456
192.168.182.110:6379> info replication
# 交互式
redis-cli -h 192.168.182.110
192.168.182.110:6379> auth 123456
192.168.182.110:6379> info replication
# 非交互式
redis-cli -h 192.168.182.110 -a 123456 info replication
如果一切配置都没有问题,Redis的主数据库会不定时的向从数据库同步数据,如下图所示。
1.3 数据同步机制
数据同步,是在首次从机首次启动、或者从机宕机重新启动的时候,进行数据同步,为保证数据一致性的机制。
1.3.1 全量同步
从服务器执行psync命令,执行数据同步。主从库间的复制是异步进行的。
大多用于从服务器首次同步,从服务器宕机重新启动时,同步的数据超过缓冲区大小也会执行全量同步。
全量复制:同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
过程:
- 从服务器向主服务器发送
PSYNC
命令来进行同步 - 收到
PSYNC
的主服务器执行BGSAVE
命令,在后台生成一个 RDB 文件,并使用一个缓冲区记录从现在开始执行的所有写命令 - 当
BGSAVE
命令执行完毕时,主服务器会将 RDB 文件发送给从服务器 - 从服务接收并载入 RDB 文件(从服务器会清空原有数据)
- 缓冲区记录了 RDB 文件所在状态后的所有写命令,主服务器将在缓冲区的所有命令发送给从服务器,从服务器执行这些写命令
- 至此从服务器的数据库状态和主服务器一致
全量同步缺点:
- 成 RDB 文件,耗费主服务器大量 CPU 、内存和磁盘 I/O 资源
- RDB 文件发送给从服务器,耗费主从服务器大量的网络资源(带宽和流量),并对主服务器响应命令请求的时间产生影响
- 从服务器载入 RDB 文件,期间会因为阻塞而没办法处理命令请求
主从服务时,尽量避免全量同步,尽可能只在首次启动的时候使用全量同步,部分同步尽量减少产生全量同步。
1.3.2 部分同步
部分同步:处理断线后重复制情况,主服务器可以将主从连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态,该过程又叫增量同步。
增量同步功能由以下三个部分构成:
- 主服务器的复制偏移量(replication offset)和从服务器的复制偏移量
- 主服务器的复制积压缓冲区(replication backlog)
- 服务器的运行 ID (Replication ID)
偏移量
主服务器和从服务器会分别维护一个复制偏移量,通过对比主从服务器的复制偏移量,可以判断主从服务器是否处于一致状态。
缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度(fixed-size)先进先出(FIFO)队列,默认大小为 1MB。
- 出队规则跟普通的先进先出队列一样
- 入队规则是当入队元素的数量大于队列长度时,最先入队的元素会被弹出,然后新元素才会被放入队列
当主服务器进行命令传播时,不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区,缓冲区会保存着一部分最近传播的写命令,并且缓冲区会为队列中的每个字节记录相应的复制偏移量。
部分同步过程:
从服务器会通过 PSYNC
命令将自己的复制偏移量 offset 发送给主服务器,主服务器会根据这个复制偏移量来决定对从服务器执行何种同步操作:
- offset 之后的数据(即 offset+1)仍然存在于复制积压缓冲区里,那么主服务器将对从服务器执行增量同步操作
- offset 之后的数据已经不在复制积压缓冲区,说明部分数据已经丢失,那么主服务器将对从服务器执行全量同步操作,会把生成RDB文件发给从服务器。
复制缓冲区大小设定不合理,会导致数据溢出。比如主服务器需要执行大量写命令,又或者主从服务器断线后重连接所需的时间较长,导致缓冲区中的数据已经丢失,则必须进行全量同步。
1.3.3 同步优化
主从同步可以保证主从数据的一致性,非常重要。
可以从以下几个方面来优化Redis主从就集群:
- 在master中配置
repl-diskless-sync yes
启用无磁盘复制,避免全量同步时的磁盘IO - Redis单节点上的内存占用不要太大,减少
RDB
导致的过多磁盘IO - 适当提高
repl_baklog
的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步 - 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
1.4 心跳机制
心跳机制:进入命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:REPLCONF ACK <replication_offset>
,replication_offset 是从服务器当前的复制偏移量。
心跳的作用:
- 检测主从服务器的网络连接状态
- 检测命令丢失
- 辅助保证主节点在不安全的情况下不执行写命令
(1)检测网络故障
如果主节点超过一秒没有收到从服务器发来的命令,则说明网络连接可能出现了故障。
在主服务器执行 INFO replication
命令,lag 一栏表示从服务器最后一次向主服务器发送 ACK 命令距离现在多少秒:
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0: ip=127.0.0.1,port=11111,state=online,offset=123,lag=0 # 刚刚发送过 REPLCONF ACK
slavel: ip=127.0.0.1,port=22222,state=online,offset=456,lag=3 # 3秒之前发送过REPLCONF ACK
在一般情况下,lag 的值应该在 0 或者 1 秒之间跳动,如果超过 1 秒说明主从服务器之间的连接出现了故障。
(2)检测命令丢失
检测命令丢失:由于网络或者其他原因,主服务器传播给从服务器的写命令丢失,那么当从服务器向主服务器发送 REPLCONF ACK
命令时,主服务器会检查从服务器的复制偏移量是否小于自己的,然后在复制积压缓冲区里找到从服务器缺少的数据,并将这些数据重新发送给从服务器。
说明:REPLCONF ACK
命令和复制积压缓冲区都是 Redis 2.8 版本新增的,在 Redis 2.8 版本以前,即使命令在传播过程中丢失,主从服务器都不会注意到,也不会向从服务器补发丢失的数据,所以为了保证主从复制的数据一致性,最好使用 2.8 或以上版本的 Redis。
(3)辅助保证主节点在不安全的情况下不执行写命令
Redis 的 min-slaves-to-write
和 min-slaves-max-lag
两个选项可以防止主服务器在不安全的情况下拒绝执行写命令。
比如向主服务器设置:
min-slaves-to-write
:主库最少有 N 个健康的从库存活才能执行写命令,没有足够的从库直接拒绝写入min-slaves-max-lag
:从库和主库进行数据复制时的 ACK 消息延迟的最大时间
min-slaves-to-write 5
min-slaves-max-lag 10
上述命令,主服务器将拒绝执行写命令的两种情况(满足任何一种都拒绝):
- 在从服务器的数少于 5 个(正常发送心跳的从服务器小于5个),
- 或者 5 个从服务器的延迟(lag)值都大于或等于10 秒时(5个从服务器发送心跳的时间都大于或等于10 秒)。
2、哨兵模式
1.1 概述
Sentinel(哨兵)是 Redis 的高可用性(high availability)解决方案,由一个或多个 Sentinel 实例 instance 组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器下线时进行故障转移。
图解:
- 双环图案表示主服务器
- 单环图案表示三个从服务器
哨兵的作用:监控redis服务器状态。如果主服务器宕机了,它会自动的将从服务器中的一台设为新的master,并且将其余的slave的配置文件自动修改,这样就切换出一套新的主从服务,不需要人工干预,且不会影响服务的使用。
首先哨兵是一个独立于主从服务之外的服务,它也是一个集群服务。哨兵实例会不断给主服务器发送Ping命令,主服务器在收到命令后,返回一个有效回复,这样哨兵实例认为服务器是正常的。
Sentinel 默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送 INFO
命令,来获取主服务器的信息。
1.2 主观与客观下线
主观下线
Sentinel 在默认情况下会以每秒一次的频率向所有与它创建了命令连接的实例(包括主从服务器、其他 Sentinel)发送 PING 命令,通过实例返回的 PING 命令回复来判断实例是否在线。
客观下线
当 Sentinel 将一个主服务器判断为主观下线之后,会向同样监视这一主服务器的其他 Sentinel 进行询问。Sentinel 使用命令询问其他 Sentinel 是否同意主服务器已下线。
如果超过配置中数量的sentinel认为主机下线了,就会从从机中选举出一个主服务器。
1.3 sentinel集群搭建
搭配三个sentinel实例。
首先新建三个文件夹(随便在哪个目录都行)。
sentinel26379 sentinel26380 sentinel26381
(1)sentinel实例26379
sentinel26379 目录下新建配置文件:
redis_sentinel_26379.conf
内容:
bind 0.0.0.0
port 26379
daemonize yes
dir "/data/redis/redis_sentinel/sentinel26379"
pidfile "/data/redis/redis_sentinel/sentinel26379/redis_sentinel26379.pid"
logfile "/data/redis/redis_sentinel/sentinel26379/redis_sentinel26379.log"
# Generated by CONFIG REWRITE
sentinel deny-scripts-reconfig yes
sentinel monitor testdb 127.0.0.1 6379 2
sentinel down-after-milliseconds testdb 5000
sentinel auth-pass testdb 123456
注意:redis从节点的信息无需配置,sentinel会根据主节点获取到从节点的数据信息。
配置文件主要参数说明:
参数名 | 说明 |
bind | 绑定的可以访问的主机IP,0.0.0.0 代表不限制 |
port | 哨兵实例的端口 |
sentinel monitor testdb 127.0.0.1 6379 1 | testdb任意定义,哨兵集群名称,127.0.0.1 6379 redis实例主节点 ;1 代表当1个哨兵实例判断主库不可用则进行master转移,生产环境节点数要配置多一点。 |
sentinel down-after-milliseconds testdb 5000 | testdb同上,down-after-milliseconds代表 master 最长响应时间,超过这个时间就主观判断它下线,5000 代表5000ms,即5s |
sentinel auth-pass testdb 123456 | 123456 是redis实例的登录密码 |
(2)sentinel实例26380
sentinel26379 目录下新建配置文件:
redis_sentinel_26380.conf
内容:
bind 0.0.0.0
port 26380
daemonize yes
dir "/data/redis/redis_sentinel/sentinel26380"
pidfile "/data/redis/redis_sentinel/sentinel26380/redis_sentinel26380.pid"
logfile "/data/redis/redis_sentinel/sentinel26380/redis_sentinel26380.log"
# Generated by CONFIG REWRITE
sentinel deny-scripts-reconfig yes
sentinel monitor testdb 127.0.0.1 6379 2
sentinel down-after-milliseconds testdb 5000
sentinel auth-pass testdb 123456
(3)sentinel实例26381
sentinel26379 目录下新建配置文件:
redis_sentinel_26381.conf
内容:
bind 0.0.0.0
port 26381
daemonize yes
dir "/data/redis/redis_sentinel/sentinel26381"
pidfile "/data/redis/redis_sentinel/sentinel26381/redis_sentinel26381.pid"
logfile "/data/redis/redis_sentinel/sentinel26381/redis_sentinel26381.log"
# Generated by CONFIG REWRITE
sentinel deny-scripts-reconfig yes
sentinel monitor testdb 127.0.0.1 6379 2
sentinel down-after-milliseconds testdb 5000
sentinel auth-pass testdb 123456
(4)启动哨兵实例
redis-sentinel /data/redis/redis_sentinel/sentinel26379/redis_sentinel_26379.conf
redis-sentinel /data/redis/redis_sentinel/sentinel26380/redis_sentinel_26380.conf
redis-sentinel /data/redis/redis_sentinel/sentinel26381/redis_sentinel_26381.conf
启动后配置文件会自动新增如下红框中的内容。
登录哨兵实例查看。
redis-cli -p 26379
(5)测试
测试将主节点down机。
复制redis-cli -p 6379 -a 123456 shutdown
再查看哨兵找那个的master结果,如下:
日志信息如下:
复制1895:X 29 Apr 23:57:31.778 # +sdown master testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:31.779 # +odown master testdb 127.0.0.1 6379 #quorum 1/1
1895:X 29 Apr 23:57:31.779 # +new-epoch 1
1895:X 29 Apr 23:57:31.779 # +try-failover master testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:31.795 # +vote-for-leader 4928b4d4dfd762cd50fa540b7a0903d2be3b0f95 1
1895:X 29 Apr 23:57:31.796 # +elected-leader master testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:31.796 # +failover-state-select-slave master testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:31.862 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:31.862 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:31.991 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:32.223 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:32.223 # +failover-state-reconf-slaves master testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:32.273 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:33.231 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:33.231 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:33.296 # +failover-end master testdb 127.0.0.1 6379
1895:X 29 Apr 23:57:33.296 # +switch-master testdb 127.0.0.1 6379 127.0.0.1 6380
1895:X 29 Apr 23:57:33.297 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ testdb 127.0.0.1 6380
1895:X 29 Apr 23:57:33.297 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ testdb 127.0.0.1 6380
1895:X 29 Apr 23:57:38.356 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ testdb 127.0.0.1 6380
再把6379端口启动,可以看到节点自动加入集群,且作为从节点。
1.4