虽然Redis可以实现单机的数据持久化,但无论是RDB也好或者AOF也好,都解决不了单点宕机问题,即一旦单台 redis服务器本身出现系统故障、硬件故障等问题后,就会直接造成数据的丢失
此外,单机的性能也是有极限的,因此需要使用另外的技术来解决单点故障和性能扩展的问题。
一.redis主从复制
1.redis 主从复制架构
主从模式(master/slave),可以实现Redis数据的跨主机备份。
程序端连接到高可用负载的VIP,然后连接到负载服务器设置的Redis后端real server,此模式不需要在程序里面配 置Redis服务器的真实IP地址,当后期Redis服务器IP地址发生变更只需要更改redis 相应的后端real server即可, 可避免更改程序中的IP地址设置。
2.主从复制特点
-
一个master可以有多个slave
-
一个slave只能有一个master
-
数据流向是从master到slave单向的
3.主从复制的基本原理
配置设置:
主节点(Master):配置允许从节点连接,并记录所有数据变更(写操作)。
从节点(Slave):配置连接到主节点,并接收主节点发送的数据副本。复制流程:
主节点持续记录执行的写操作(包括SET、DEL等),并将这些写操作以命令的形式发送给所有连接的从节点。
从节点接收到这些命令并执行,以确保其数据与主节点保持同步。初始化同步:
新的从节点在连接到主节点时,可以选择全量复制(将主节点的所有数据复制一份到从节点)或者部分复制(只复制从连接后的数据变更)。
心跳检测和重连:
主从节点之间通过心跳机制保持连接。如果从节点与主节点断开连接,它会尝试重新连接并请求同步缺失的数据。
读写分离:
从节点可以用于处理只读操作,以减轻主节点的负载。客户端可以选择性地连接到从节点进行读取操作,从而分担主节点的读取压力。
当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。否则的话,由于延迟等问题,部署的主节点Redis服务应该要避免自动启动。
参考案例: 导致主从服务器数据全部丢失
1.假设节点A为主服务器,并且关闭了持久化。并且节点B和节点c从节点A复制数据
2.节点A崩溃,然后由自动拉起服务重启了节点A.由于节点A的持久化被关闭了,所以重启之后没有任何数据
3.节点B和节点c将从节点A复制数据,但是A的数据是空的,于是就把自身保存的数据副本删除。
在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel来实现Redis的高可用性,也是非常危险的。因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动启动。
4.命令行配置
命令 | 解释 |
---|---|
info replication | 查看主从状态 |
repliacaof | 添加主从配置 例子: repliacaof 192.168.91.100 6379 |
CONFIG SET masterauth 123456 | 设置密码 |
REPLICAOF no one | 取消 主从配置 |
5.实现主从复制
主服务器:192.168.240.13
[root@localhost ~]#vim /etc/redis/6379.conf
70 bind 0.0.0.0
#将监听端口改为任意端口
requirepass 12345
#设置密码
172 logfile /var/log/redis_6379.log
#指定日志文件目录
264 dir /var/lib/redis/6379
#指定工作目录
700 appendonly yes
#开启AOF持久化功能
从服务器:192.168.240.14
#安装redis略
#修改配置文件
70 bind 0.0.0.0
#将监听端口改为任意端口
172 logfile /var/log/redis_6379.log
#指定日志文件目录
264 dir /var/lib/redis/6379
#指定工作目录
288 replicaof 192.168.91.100 6379
#设置 主从配置
masterauth 123456
#如果有密码 设置此行
700 appendonly yes
#开启AOF持久化功能
5.1关闭防火墙和selinux
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# setenforce 0
5.2 进入从的配置文件
replicaof 192.168.240.13 6379
#主服务器地址 #端口号
如果需要添加密码,在主服务器配置文件中添加密码
requirepass a
在从服务器配置文件中加入
masterauth a
5.3 重新启动从服务器,并进入redis数据库查看主从状态
slave 状态只读无法写入数据
systemctl restart redis
redis-cli
127.0.0.1:6379> info replication
从服务器
role:slave
表示当前 Redis 服务器的角色是从服务器。
master_host:192.168.240.13
指定当前从服务器正在复制的主服务器的 IP 地址。
master_port:6379
指定当前从服务器正在复制的主服务器的端口号。
master_link_status:up
表示从服务器与主服务器之间的连接状态为正常(连接已建立)。
master_last_io_seconds_ago:8
指示从服务器上次与主服务器进行通信的时间,单位为秒,这里表示距离上次通信已经过去了8秒。
master_sync_in_progress:0
表示当前没有正在进行中的主从同步操作。
slave_repl_offset:24865
指示从服务器当前的复制偏移量,即从主服务器已经复制到的数据量。
slave_priority:100
从服务器的复制优先级,这里设置为100,表示当前从服务器在进行故障转移时的优先级。
slave_read_only:1
表示从服务器是否设置为只读模式,这里设置为1,表示从服务器不接受写操作。
connected_slaves:0
指示当前连接到该从服务器的从服务器数量,这里为0,表示该从服务器没有其他从服务器连接。
master_replid:9c941d96163ba330053c1cb212c8ab5af806adb4
主服务器的复制 ID,用于标识主服务器的唯一标识符。
master_replid2:0000000000000000000000000000000000000000
辅助用于复制的 ID,通常为 40 个零,表示在执行故障转移时用作附加标识。
master_repl_offset:24865
主服务器的复制偏移量,表示当前主服务器已经复制给从服务器的数据量。
second_repl_offset:-1
第二个复制偏移量,通常不使用,这里值为 -1。
repl_backlog_active:1
表示复制后备日志(replication backlog)是否处于活动状态(active),即是否正在使用。
repl_backlog_size:1048576
复制后备日志的大小,这里为 1048576 字节(1 MB),表示可用于复制的最大历史数据量。
repl_backlog_first_byte_offset:24796
复制后备日志的第一个字节的偏移量,表示第一个有效数据在复制后备日志中的位置。
repl_backlog_histlen:70
复制后备日志的历史长度,表示当前复制后备日志中存储的历史数据条目数。
主服务器
role:master
#表示当前 Redis 服务器的角色是主服务器。
connected_slaves:1
#表示当前连接的从服务器数量,这里有一个从服务器连接到了主服务器。
slave0:ip=192.168.240.14,port=6379,state=online,offset=24935,lag=1
#描述了从服务器的详细信息:
ip=192.168.240.14,port=6379:从服务器的 IP 地址和端口号。
state=online:从服务器的状态,这里是在线状态。
offset=24935:从服务器当前复制的偏移量(offset),即从主服务器同步的数据偏移量。
lag=1:从服务器与主服务器的复制延迟,即从服务器在处理复制数据时的滞后量(以秒为单位)。
master_replid:9c941d96163ba330053c1cb212c8ab5af806adb4
#主服务器的复制 ID,用于标识主服务器的唯一标识符。
master_replid2:0000000000000000000000000000000000000000
#辅助用于复制的 ID,通常为 40 个零,表示在执行故障转移时用作附加标识。
master_repl_offset:24935
#主服务器的复制偏移量,表示当前主服务器已经复制给从服务器的数据量。
second_repl_offset:-1
#第二个复制偏移量,通常不使用,这里值为 -1。
repl_backlog_active:1
#表示复制后备日志(replication backlog)是否处于活动状态(active),即是否正在使用。
repl_backlog_size:1048576
#复制后备日志的大小,这里为 1048576 字节(1 MB),表示可用于复制的最大历史数据量。
repl_backlog_first_byte_offset:24796
#复制后备日志的第一个字节的偏移量,表示第一个有效数据在复制后备日志中的位置。
repl_backlog_histlen:140
#复制后备日志的历史长度,表示当前复制后备日志中存储的历史数据条目数。
测试:
6.删除主从复制
在从服务器执行 REPLIATOF NO ONE 指令可以取消主从复制
#取消复制,在slave上执行REPLIATOF NO ONE,会断开和master的连接不再主从复制, 但不会清除slave
上已有的数据
127.0.0.1:6379> REPLICAOF no one
7.主从复制故障恢复
master故障后,只能手动提升一个slave为新master,不支持自动切换。
之后将其它的slave节点重新指定新的master为master节点
Master的切换会导致master_replid发生变化,slave之前的master_replid就和当前master不一致从而会引发所有 slave的全量同步。
8.主从复制完整过程
1)从服务器连接主服务器,发送PSYNC命令
2)主服务器接收到PSYNC命令后,开始执行BGSAVE命令生成RDB快照文件并使用缓冲区记录此后执行的所有
写命令
3)主服务器BGSAVE执行完后,向所有从服务器发送RDB快照文件,并在发送期间继续记录被执行的写命令
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照至内存
5)主服务器快照发送完毕后,开始向从服务器发送缓冲区中的写命令
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
7)后期同步会先发送自己slave_repl_offset位置,只同步新增加的数据,不再全量同步
复制缓冲区配置参数
#复制缓冲区大小,建议要设置足够大
repl-backlog-size 1mb
#Redis同时也提供了当没有slave需要同步的时候,多久可以释放环形队列:
repl-backlog-ttl 3600
9.主从同步优化配置
Redis在2.8版本之前没有提供增量部分复制的功能,当网络闪断或者slave Redis重启之后会导致主从之间的全量同步,即从2.8版本开始增加了部分复制的功能。
repl-diskless-sync:
功能: 控制是否使用无盘同步 RDB 文件。当设置为yes
时,主服务器不会将 RDB 文件保存到磁盘上,而是直接通过 socket 文件发送给从服务器。
建议配置: 根据实际情况选择,如果希望减少磁盘 I/O 操作并且网络条件良好,可以考虑设置为yes
。repl-diskless-sync-delay:
功能: 在使用无盘同步时,从服务器等待接收 RDB 数据的时间延迟。
建议配置: 默认值为 5 秒通常是一个合理的设置,可以根据网络延迟和从服务器的性能调整。repl-ping-slave-period:
功能: 从服务器向主服务器发送 ping 的时间间隔,用于保持连接。
建议配置: 默认值为 10 秒通常是合适的,可以根据网络稳定性调整,不建议设置得太短以避免过多的网络开销。repl-timeout:
功能: 设置主从连接的超时时间,超过此时间没有收到响应将认为连接断开。
建议配置: 默认值为 60 秒通常是合适的,可以根据网络环境和延迟进行微调。repl-disable-tcp-nodelay:
功能: 控制是否启用 TCP_NODELAY。启用后可以减少网络带宽消耗,但可能会增加同步延迟。
建议配置: 根据数据的一致性要求和网络性能进行选择。通常选择no
,以确保数据同步的及时性和准确性。repl-backlog-size:
功能: 主服务器用于保存复制数据的写入缓冲区大小。
建议配置: 根据从服务器断开连接后能容忍的最长时间和主服务器的写入速率来设置。建议按照需求调整,确保足够的缓冲区来支持断线重连时的数据传输。repl-backlog-ttl:
功能: 如果一段时间后没有从服务器连接到主服务器,定义主服务器写入缓冲区的超时时间。建议配置: 根据系统的需求设置合适的时间,以免长时间未使用的资源占用内存。slave-priority:
功能: 设置从服务器的优先级,用于在主服务器故障后选举新的主服务器。
建议配置: 如果有多个从服务器,可以设置不同的优先级以影响选举结果。min-replicas-to-write:
功能: 设置主服务器至少需要多少个可用从服务器,否则拒绝执行写操作。
建议配置: 根据系统的容错需求进行设置,确保即使部分从服务器不可用也能保持系统的可写性。min-slaves-max-lag:
功能: 当从服务器的复制延迟超过设定值时,主服务器不再接受写操作。
建议配置: 根据系统的性能和复制链路的稳定性设置合适的延迟阈值,以避免数据不一致性问题。
二.哨兵模式(Sentinel)
edis 哨兵模式是一种用于高可用性(High Availability, HA)的解决方案,它允许 Redis 在主从复制的基础上,提供自动故障恢复和故障转移的功能。主要用途是监控 Redis 实例,并在主节点失效时自动将一个从节点晋升为新的主节点,以保证服务的持续可用性。
1.主要组件和概念
哨兵(Sentinel):
哨兵是一个运行在独立进程中的程序,其主要任务是监控 Redis 实例的状态(主节点和从节点),并在主节点失效时执行自动故障转移。
主节点(Master):
Redis 中的主节点负责接收写操作,并将数据同步到所有从节点。
从节点(Slave):
从节点是主节点的复制品,它们复制主节点的数据,并在需要时可以晋升为新的主节点。
2.哨兵模式的工作原理
哨兵模式包括多个哨兵进程和多个 Redis 节点(主节点和从节点)。哨兵进程定期检查 Redis 实例的健康状态,并在发现故障时采取自动化的措施。
监控:
每个哨兵进程会定期检查监控的 Redis 实例的健康状态,包括主节点和从节点。
故障检测:
如果一个哨兵进程发现主节点不可用(比如网络故障、进程崩溃等),它会开始执行一系列故障检测步骤,以确保主节点确实不可用。
选举新主节点:
当主节点被确认为不可用时,哨兵会通过一种投票机制选举一个从节点作为新的主节点。这个过程会考虑每个哨兵的优先级和配置,确保选举出的主节点具有一致性和可靠性。
故障转移:
一旦新的主节点被选出,哨兵会协调所有的 Redis 客户端和其他哨兵,使它们知道新的主节点的位置。这个过程称为故障转移(failover),通常会在几秒钟内完成。
配置同步:
新的主节点上任后,哨兵还会确保所有从节点正确地重新配置为新的主节点的从节点,并开始从新的主节点同步数据。
3.优点和适用场景
-
自动化的高可用性:哨兵模式使得 Redis 集群在主节点故障时可以自动化地完成故障转移,减少了人工介入和服务中断的可能性。
-
实时监控和通知:哨兵可以实时监控 Redis 的健康状况,并在必要时通过警报或通知管理员进行干预。
-
简化扩展和维护:通过自动处理故障转移,哨兵模式简化了 Redis 集群的扩展和维护工作。
4.实现哨兵模式
哨兵的前提是已经实现了一个redis的主从复制的运行环境,从而实现一个一主两从基于哨兵的高可用
redis架构
注意: master 的配置文件中masterauth 和slave 都必须相同
所有主从节点的redis.conf中关健配置
主服务器:192.168.240.13 端口:6379 哨兵1
从服务器1:192.168.240.14 端口:6379 哨兵2
从服务器2:192.168.240.12 端口:6379 哨兵3
1)关闭防火墙关闭selinux
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# setenforce 0
2)配置主从复制
3)编辑哨兵的配置文件
sentinel配置
Sentinel实际上是一个特殊的redis服务器,有些redis指令支持,但很多指令并不支持.默认监听在26379/tcp端口.
哨兵可以不和Redis服务器部署在一起,但一般部署在一起以节约成本
所有redis节点使用相同的以下示例的配置文件
[root@localhost redis-5.0.7]# cp sentinel.conf /apps/redis/etc/
[root@localhost redis-5.0.7]# vim /apps/redis/etc/sentinel.conf
bind 0.0.0.0 #修改监听端口
port 26379 #不用修改默认
daemonize yes # 不用修改如果是systemd 启动模式, 修改后启动不了
pidfile "/apps/resdis/run/redis-sentinel.pid" #指定pid文件
logfile "/apps/redis/log/sentinel_26379.log" # 指定日志文件
dir "/tmp" #工作目录不用修改
sentinel monitor mymaster 10.0.0.8 6379 2
#mymaster是集群的名称,此行指定当前mymaster集群中master服务器的地址和端口
#2为法定人数限制(quorum),即有几个sentinel认为master down了就进行故障转移,一般此值是所有sentinel节点(一般总数是>=3的 奇数,如:3,5,7等)的一半以上的整数值,比如,总数是3,即3/2=1.5,取整为2,是master的ODOWN客观下线的依据
sentinel auth-pass mymaster 123456
#mymaster集群中master的密码,注意此行要在上面行的下面
sentinel down-after-milliseconds mymaster 30000
#(SDOWN)判断mymaster集群中所有节点的主观下线的时间, 单位:毫秒,建议3000(3秒) 否则等待时间过长
sentinel parallel-syncs mymaster 1
#发生故障转移后,可以同时向新master同步数据的slave的数量,数字越小总同步时间越长,但可以减轻新master的负载压力
sentinel failover-timeout mymaster 180000
#所有slaves指向新的master所需的超时时间,单位:毫秒
sentinel deny-scripts-reconfig yes #禁止修改脚本
修改文件的内容
[root@localhost etc]#grep -vE "^#|^$" sentinel.conf
bind 0.0.0.0
port 26379
daemonize yes
pidfile /apps/redis/run/redis-sentinel.pid
logfile "/apps/redis/log/sentinel.log"
dir /tmp
sentinel monitor mymaster 192.168.240.13 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 3000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
4)准备service 文件 注意先开 主再开从 全部节点都需要
cat >> /lib/systemd/system/redis-sentinel.service <<eof
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-sentinel /apps/redis/etc/sentinel.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
eof
[root@localhost etc]# systemctl daemon-reload
[root@localhost etc]# systemctl start redis-sentinel.service
5)将主服务器上的sentinel.conf传输到两台从服务器
scp -r /apps/redis/etc/sentinel.conf 192.168.240.14://apps/redis/etc/
scp -r /apps/redis/etc/sentinel.conf 192.168.240.12://apps/redis/etc/
6)将所有节点上的sentinel.conf文件权限属主属组改为redis
[root@localhost ~]# cd /apps/redis/etc/
[root@localhost etc]# ls
redis.conf sentinel.conf
[root@localhost etc]# chown redis.redis sentinel.conf
[root@localhost etc]# ll
总用量 76
-rw-r--r--. 1 redis redis 61857 7月 9 16:09 redis.conf
-rw-r--r--. 1 redis redis 9804 7月 10 17:48 sentinel.conf
7)刷新配置文件,先开启主上的哨兵在开启从
[root@localhost etc]# systemctl daemon-reload
[root@localhost etc]# systemctl start redis-sentinel.service
[root@localhost etc]# systemctl status redis-sentinel.service
8)主从服务器上查看日志文件
tail -f /apps/redis/log/sentinel.log
ss -natp |grep 26379
主服务器
从服务器
9)测试,关闭主服务器redis
systemctl stop redis
查看日志
主服务器
从服务器1成为新的主服务器
从服务器1
从服务器1成为新的主服务器
从服务器2
从服务器1成为新的主服务器,从2指向新主
当再次开启原主服务器时
这是不会抢占主的位置会成为新主的从服务器