文章目录
- 一、Redis主从复制
- redis主从复制架构
- 主从复制实现
- 主从复制故障恢复
- 主从复制优化
- 主从复制过程
- 主从同步优化配置
- 二、哨兵模式 (Sentinel)
- redis集群介绍
- 哨兵 (Sentinel)工作原理
- 实现哨兵
- 主从复制
- 哨兵配置文件
- 三、Redis cluster架构
- 工作原理
- Redis cluster架构
- 实现集群
虽然Redis可以实现单机的数据持久化,但无论是RDB也好或者AOF也好,都解决不了单点宕机问题,即一旦单台 redis服务器本身出现系统故障、硬件故障等问题后,就会直接造成数据的丢失。此外,单机的性能也是有极限的,因此需要使用另外的技术来解决单点故障和性能扩展的问题。
一、Redis主从复制
redis主从复制架构
主从模式(master/slave),可以实现Redis数据的跨主机备份。
程序端连接到高可用负载的VIP,然后连接到负载服务器设置的Redis后端real server,此模式不需要在程序里面配 置Redis服务器的真实IP地址,当后期Redis服务器IP地址发生变更只需要更改redis 相应的后端real server即可, 可避免更改程序中的IP地址设置。
主从复制特点:
- 一个master可以有多个slave
- 一个slave只能有一个master
- 数据流向是从master到slave单向的
主从复制实现
Redis Slave 也要开启持久化并设置和master同样的连接密码,因为后期slave会有提升为master的可能,Slave 端切换master同步后会丢失之前的所有数据,而通过持久化可以恢复数据。
一旦某个Slave成为一个master的slave,Redis Slave服务会清空当前redis服务器上的所有数据并将master的数据导入到自己的内存,但是如果只是断开同步关系后,则不会删除当前已经同步过的数据。
当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。否则的话,由于延迟等问题,部署的主节点Redis服务应该要避免自动启动。
在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel来实现Redis的高可用性,也是非常危险的。因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动启动。
命令行配置
命令 | 解释 |
---|---|
info replication | 查看主从状态 |
repliacaof 或者 ( slaveof ) | 添加主从配置 例子: repliacaof 192.168.91.100 6379 |
CONFIG SET masterauth 123456 | 临时设置密码 |
repliacaof masterip masterport | 临时添加主设置 |
REPLICAOF no one | 取消 主从配置 |
启用主从同步
默认redis 状态为master,需要转换为slave角色并指向master服务器的IP+PORT+Password在从节点执行 REPLICAOF MASTER_IP PORT 指令可以启用主从同步复制功能,早期版本使用 SLAVEOF 指令。
配置操作
主上面的配置
[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持久化功能
从的配置
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持久化功能
主从复制成功。
删除主从同步
在从节点执行 REPLIATOF NO ONE 指令可以取消主从复制。
主从复制故障恢复
从down掉。
master节点故障和恢复
master故障后,只能手动提升一个slave为新master,不支持自动切换。之后将其他的slave节点重新指定新的master为master节点。
Master的切换会导致master_replid发生变化,slave之前的master_replid就和当前master不一致从而会引发所有 slave的全量同步。
主从复制优化
主从复制过程
Redis主从复制分为全量同步和增量同步。
全量复制过程
首次主从同步是全量同步,主从同步可以让从服务器从主服务器同步数据,而且从服务器还可再有其它的从服务器,即另外一台redis服务器可以从一台从服务器进行数据同步,redis 的主从同步是非阻塞的,master收到从服务器的psync(2.8版本之前是SYNC)命令,会fork一个子进程在后台执行bgsave命令,并将新写入的数据写入到一个缓冲区中,bgsave执行完成之后,将生成的RDB文件发送给slave,然后master再将缓冲区的内容以redis协议格式再全部发送给slave,slave 先删除旧数据,slave将收到后的RDB文件载入自己的内存,再加载所有收到缓冲区的内容 从而这样一次完整的数据同步Redis全量复制一般发生在Slave首次初始化阶段,这时Slave需要将Master上的所有数据都复制一份。
增量复制过程
全量同步之后再次需要同步时,从服务器只要发送当前的offset位置(等同于MySQL的binlog的位置)给主服务器,然后主服务器根据相应的位置将之后的数据(包括写在缓冲区的积压数据)发送给从服务器,再次将其保存到从节点内存即可。
主从同步具体过程
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 最长保持时间 3600秒
Redis 环形队列(Circular Queue)是一种特殊的队列数据结构,它在 Redis 中通常使用列表(List)来实现。环形队列的主要特点是当队列达到最大长度时,新元素会覆盖最旧的元素,形成一个循环。
作用:
复制缓冲区
作用:存储最近执行的写命令,用于主从复制。
实现:固定大小的循环缓冲区。
重要性:支持部分重同步,提高复制效率。
初次同步:
主节点生成RDB文件发送给从节点
同时将新写入的命令存入复制缓冲区
断线重连:
从节点重连后,请求部分重同步
主节点检查复制缓冲区,决定是否可以部分重同步
避免全量复制
- 第一次全量复制不可避免,后续的全量复制可以利用小主节点(内存小),业务低峰时进行全量。
- 节点运行ID不匹配:主节点重启会导致RUNID变化,可能会触发全量复制,可以利用故障转移,例如哨兵或集群,而从节点重启动,不会导致全量复制。
- 复制积压缓冲区不足: 当主节点生成的新数据大于缓冲区大小,从节点恢复和主节点连接后,会导致全量复制.解决方法将repl-backlog-size 调大。
避免复制风暴
单主节点复制风暴
当主节点重启,多从节点复制。通过更换拓扑即可解决该问题。
单机器多实例复制风暴
机器宕机后,大量全量复制
解决方法:主节点分散多机器。
主从同步优化配置
Redis在2.8版本之前没有提供增量部分复制的功能,当网络闪断或者slave Redis重启之后会导致主从之间的全量同步,即从2.8版本开始增加了部分复制的功能。
相关配置 | 含义 |
---|---|
repl-diskless-sync no | 是否使用无盘同步RDB文件,默认为no,no为不使用无盘,需要将RDB文件保存到磁盘后再发送给slave,yes为支持无盘,支持无盘就是RDB文件不需要保存至本地磁盘,而且直接通过socket文件发送给slave |
repl-diskless-sync-delay 5 | 无磁盘复制时,服务器等待的延迟时间 |
repl-ping-slave-period 10 | slave端向server端发送ping的时间间隔,默认为10秒 |
repl-timeout 60 | 设置主从ping连接超时时间,超过此值无法连接,master_link_status显示为down,并记录错误日志 |
repl-disable-tcp-nodelay no | 是否启用TCP_NODELAY,如设置成yes,则redis会合并小的TCP包从而节省带宽, 但会增加同步延迟(40ms),造成master与slave数据不一致,假如设置成no,则redis master会立即发送同步数据,没有延迟,yes关注网络性能,no关注redis服务中的数据一致性。 |
repl-backlog-size 1mb | master的写入数据缓冲区,用于记录自上一次同步后到下一次同步过程中间的写入命令,计算公式:repl-backlog-size = 允许从节点最大中断时长 * 主实例offset每秒写入量,比如master每秒最大写入64mb,最大允许60秒,那么就要设置为64mb*60秒=3840MB(3.8G),建议此值是设置的足够大 |
repl-backlog-ttl 3600 | 3600秒 如果一段时间后没有slave连接到master,则backlog size的内存将会被释放。如果值为0则 表示永远不释放这部份内存。 |
slave-priority 100 | slave端的优先级设置,值是一个整数,数字越小表示优先级越高。当master故障时将会按照优先级来选择slave端进行恢复,如果值设置为0,则表示该slave永远不会被选择。 |
min-replicas-to-write 1 | 设置一个master的可用slave不能少于多少个,否则master无法执行写 |
min-slaves-max-lag 20 | 设置至少有上面数量的slave延迟时间都大于多少秒时,master不接收写操作(拒绝写入) |
二、哨兵模式 (Sentinel)
redis集群介绍
主从架构无法实现master和slave角色的自动切换,即当master出现redis服务异常、主机断电、磁盘损坏等问题导致master无法使用,而redis主从复制无法实现自动的故障转移(将slave 自动提升为新master),需要手动修改环境配置,才能切换到slave redis服务器,另外当单台Redis服务器性能无法满足业务写入需求的时候,也无法横向扩展Redis服务的并行写入性能。
需要解决以上的两个核心问题:
- master和slave角色的无缝切换,让业务无感知从而不影响业务使用
- 可横向动态扩展Redis服务器,从而实现多台服务器并行写入以实现更高并发的目的。
Redis 集群实现方式:
- 客户端分片: 由应用决定将不同的KEY发送到不同的Redis服务器
- 代理分片: 由代理决定将不同的KEY发送到不同的Redis服务器,代理程序如:codis,twemproxy等
- Redis Cluster
哨兵 (Sentinel)工作原理
Sentinel架构
Sentinel 故障转移
Sentinel 进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用,此功能在redis2.6+的版本已引用,Redis的哨兵模式到了2.8版本之后就稳定了下来。一般在生产环境也建议使用Redis的2.8版本的以后版本。
哨兵(Sentinel) 是一个分布式系统,可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossip protocols)来接收关于Master主服务器是否下线的信息,并使用投票协议(Agreement Protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。
每个哨兵(Sentinel)进程会向其它哨兵(Sentinel)、Master、Slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定配置时间(此项可配置)内未得到回应,则暂时认为对方已离线,也就是所谓的”主观认为宕机” (主观:是每个成员都具有的独自的而且可能相同也可能不同的意识),英文名称:Subjective Down,简称SDOWN。
有主观宕机,对应的有客观宕机。当“哨兵群”中的多数Sentinel进程在对Master主服务器做出SDOWN 的判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,这种方式就是“客观宕机”(客观:是不依赖于某种意识而已经实际存在的一切事物),英文名称是:Objectively Down, 简称 ODOWN。
通过一定的vote算法,从剩下的slave从服务器节点中,选一台提升为Master服务器节点,然后自动修改相关配置,并开启故障转移(failover)。Sentinel 机制可以解决master和slave角色的自动切换问题,但单个 Master 的性能瓶颈问题无法解决,类似于MySQL中的MHA功能。
Redis Sentinel中的Sentinel节点个数应该为大于等于3且最好为奇数,因为投票不会出现偶数的问题。
客户端初始化时连接的是Sentinel节点集合,不再是具体的Redis节点,但Sentinel只是配置中心不是代理。Redis Sentinel 节点与普通redis 没有区别,要实现读写分离依赖于客户端程序。redis 3.0 之前版本中,生产环境一般使用哨兵模式,3.0后推出redis cluster功能,可以支持更大规模的生产环境。
Sentinel的三个定时任务
-
每10秒每个sentinel对master和slave执行info, 发现slave节点,确认主从关系。
-
每2秒每个sentinel通过master节点的channel交换信息(pub/sub)。
通过sentinel__:hello频道交互
交互对节点的“看法”和自身信息
- 每1秒每个sentinel对其他sentinel和redis执行ping。
实现哨兵
主从复制
实现哨兵的前提是已经实现了一个redis的主从复制的运行环境,从而实现一个一主两从基于哨兵的高可用。
注意:
master 的配置文件中masterauth 和slave 都必须相同。
先实现主从复制即可。过程同上,不再赘述。
在所有的主从节点配置
vim /etc/redis.conf
masterauth "123456"
requirepass "123456"
masterauth “123456”,设置主节点的认证密码,在主从复制中,从节点连接主节点时使用。当一个Redis实例作为从节点时,它需要这个密码来认证主节点,从节点使用这个密码向主节点证明自己有权限进行数据同步。主节点设置了访问密码后,从节点必须提供正确的密码才能连接。
requirepass “123456”,设置Redis服务器的访问密码。用于客户端连接Redis服务器时的认证。任何客户端(包括redis-cli)连接到这个Redis实例时,都需要提供这个密码,未提供正确密码的连接将被拒绝。
客户端登录未加密码登录,会显示权限拒绝。
使用-a选项,登录数据库,即不会出现权限拒绝。主从复制配置完成。
哨兵配置文件
sentinel配置
Sentinel实际上是一个特殊的redis服务器,有些redis指令支持,但很多指令并不支持。默认监听在26379/tcp端口。
哨兵可以不和Redis服务器部署在一起,但一般部署在一起以节约成本。
所有redis节点使用相同的配置文件。
如果是编译安装,在源码包目录下有sentinel.conf的配置文件,复制在安装目录即可。
哨兵配置文件
bind 0.0.0.0
修改监听的IP地址
port 26379
默认的端口
daemonize no
Sentinel将在前台运行,不会成为守护进程。适合与systemd等进程管理工具一起使用。no则相反。
pidfile /apps/resdis/run/redis-sentinel.pid
指定进程ID文件的位置。即使在非守护进程模式下,也会创建此文件。
logfile /apps/redis/log/sentinel_26379.log
指定日志文件的位置。所有Sentinel的日志将写入此文件。
dir /tmp
设置Sentinel的工作目录。用于存储临时文件。
sentinel monitor mymaster 192.168.232.10 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 3000
(SDOWN)判断mymaster集群中所有节点的主观下线的时间, 单位:毫秒
sentinel parallel-syncs mymaster 1
发生故障转移后,可以同时向新master同步数据的slave的数量,数字越小总同步时间越长,但可以减轻新master的负载压力
sentinel failover-timeout mymaster 180000
所有slaves指向新的master所需的超时时间,单位:毫秒
sentinel deny-scripts-reconfig yes
禁止修改脚本
准备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
systemctl daemon-reload
systemctl start redis-sentinel.service
注意要更改配置文件的属主属组。
关闭主验证实验效果
发现只有sdwon,排查后端从的配置文件。
配置文件中的节点一致,起不来。
更改完myid后,配置成功。
配置成功。
三、Redis cluster架构
工作原理
在哨兵sentinel机制中,可以解决redis高可用问题,即当master故障后可以自动将slave提升为master,从而可以保证redis服务的正常使用,但是无法解决redis单机写入的瓶颈问题,即单机redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素。为了解决单机性能的瓶颈,提高Redis 性能,可以使用分布式集群的解决方案。
早期Redis 分布式集群部署方案:
- 客户端分区:由客户端程序决定key写分配和写入的redis node,但是需要客户端自己实现写入分配、高可用管理和故障转移等。
- 代理方案:基于三方软件实现redis proxy,客户端先连接之代理层,由代理层实现key的写入分配,对客户端来说是有比较简单,但是对于集群管节点增减相对比较麻烦,而且代理本身也是单点和性能瓶颈。
redis 3.0版本之后推出了无中心架构的redis cluster机制,在无中心的redis集群当中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连接。
Redis Cluster特点:
- 所有Redis节点使用(PING机制)互联。
- 集群中某个节点的是否失效,是由整个集群中超过半数的节点监测都失效,才能算真正的失效。
- 客户端不需要proxy即可直接连接redis,应用程序中需要配置有全部的redis服务器IP。
- redis cluster把所有的redis node 平均映射到 0-16383个槽位(slot)上,读写需要到指定的redis node上进行操作,因此有多少个redis node相当于redis 并发扩展了多少倍,每个redis node 承担16384/N个槽位。
- Redis cluster预先分配16384个(slot)槽位,当需要在redis集群中写入一个key -value的时候,会使用CRC16(key) mod 16384之后的值,决定将key写入值哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈。
Redis cluster架构
Redis cluster基本架构
假如三个主节点分别是:A, B, C 三个节点,采用哈希槽 (hash slot)的方式来分配16384个slot 的话它们三个节点分别承担的slot 区间可以是:
节点A覆盖 0-5460
节点B覆盖 5461-10922
节点C覆盖 10923-16383
Redis cluster主从架构
Redis cluster的架构虽然解决了并发的问题,但是又引入了一个新的问题,每个Redis master的高可用。如何解决?那就是对每个master 节点都实现主从复制,从而实现 redis 高可用性。
部署架构
6台服务器,分别是三组master/slave,适用于生产环境。
实现集群
架构:开启多实例来实现redis。
redis集群一般需要3个节点,3主3从。我们在同一台服务器上进行模拟:以端口号进行区分。
3个主节点的端口号:6001、6002、6003
对应的从节点的端口号:6004、6005、6006
端口号可能随机分配。
新建集群文件目录
cd /apps/redis/
mkdir -p redis-cluster/redis600{1..6}
准备配置文件到每个文件夹
for i in {1..6}
do
cp /data/redis-5.0.7/redis.conf /apps/redis/redis-cluster/redis600$i
cp /data/redis-5.0.7/src/redis-cli /data/redis-5.0.7/src/redis-server /apps/redis/redis-cluster/redis600$i
done
开启集群功能
protected-mode no #88行,修改,关闭保护模式
port 6001 #92行,修改,redis监听端口,
daemonize yes #136行,开启守护进程,以独立进程启动 如果是 systemd 启动不需要修改
cluster-enabled yes #832行,取消注释,开启群集功能
cluster-config-file nodes-6001.conf #840行,取消注释,群集名称文件设置
cluster-node-timeout 15000 #846行,取消注释群集超时时间设置
appendonly yes #700行,修改,开启AOF持久化
sed -i.bak 's/bind 127.0.0.1/bind 0.0.0.0/' redis.conf
sed -i.bak 's/protected-mode yes/protected-mode no/' redis.conf
sed -i.bak 's/^port .*/port 6001/' redis.conf
sed -i.bak 's/^daemonize .*/daemonize yes/' redis.conf
sed -i.bak 's/^# cluster-enabled .*/cluster-enabled yes/' redis.conf
sed -i.bak 's/^# cluster-config-file .*/cluster-config-file nodes-6001.conf/' redis.conf
sed -i.bak 's/^# cluster-node-timeout .*/cluster-node-timeout 15000/' redis.conf
sed -i.bak 's/appendonly no/appendonly yes/' redis.conf
复制配置文件
for i in {2..6}
do
\cp -f ./redis.conf /apps/redis/redis-cluster/redis600${i}
done
并修改监听端口
脚本启动
for d in {1..6}
do
cd /apps/redis/redis-cluster/redis600$d
redis-server redis.conf
done
启动集群
redis-cli --cluster create 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:6004 127.0.0.1:6005 127.0.0.1:6006 --cluster-replicas 1
六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点。
--replicas 1 表示每个主节点有1个从节点。
测试集群
redis-cli -p 6001 -c
加上-c参数,节点之间就可以互相跳转
cluster slots 查看节点的哈希槽编号范围
查看节点信息。