Redis集群与高可用

虽然Redis可以实现单机的数据持久化,但无论是RDB也好或者AOF也好,都解决不了单点宕机问题,即一旦单台 redis服务器本身出现系统故障、硬件故障等问题后,就会直接造成数据的丢失。此外,单机的性能也是有极限的,因此需要使用另外的技术来解决单点故障和性能扩展的问题

一、Redis主从复制

主从模式(master/slave),可以实现Redis数据的跨主机备份。

主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力收到单机的限制。

主从复制特点

  • 一个master可以有多个slave

  • 一个slave只能有一个master

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

1.主从复制实现

当配置Rdeis复制功能时,强烈建议打开主服务的持久化功能。否则的话,由于延迟等问题,部署的主节点Redis服务应该要避免自动启动。

Redis Slave也要开启持久化并设置和master同样的;连接密码,因为后期Slave会有提升为master的可能,slave端切换master同步后会丢失之前的所有数据,而通过持久化可以恢复数据。

一旦某个slave成为一个master的slave,Redis Slave服务会清空当前redis服务器上的所有数据并将master的数据导入到自己的内存,但是如果只是断开同步关系后,则不会删除当前已经同步过的数据。

实际操作:

  • master 192.168.204.60
  • slave1 192.168.204.50
  • slave2 192.168.204.70

主服务器master:

点击查看代码
[root@node6 ~]#  systemctl stop firewalld
[root@node6 ~]#  setenforce 0
安装redis

[root@node6 ~]#  vim /apps/redis/etc/redis.conf  //修改配置文件
 70 bind 0.0.0.0                             //将监听端口改为任意端口
 172 logfile /apps/redis/log/redis6379.log   //指定日志文件目录
 264 dir /apps/redis/data/                   //指定工作目录
 700 appendonly yes                          //开启AOF持久化功能
[root@node6 ~]#  systemctl restart redis         //重启服务

从服务器slave1:

点击查看代码
[root@node5 ~]#  systemctl stop firewalld
[root@node5 ~]#  setenforce 0
安装redis

[root@node5 ~]#  vim /apps/redis/etc/redis.conf
 70 bind 0.0.0.0
 172 logfile /apps/redis/log/redis6379.log
 264 dir /apps/redis/data/
 288  replicaof 192.168.204.60 6379  //设置 主从配置
 700 appendonly yes
[root@node5 ~]#  systemctl restart redis

从服务器slave2:

点击查看代码
[root@node7 ~]#  systemctl stop firewalld
[root@node7 ~]#  setenforce 0
安装redis

[root@node7 ~]#  vim /apps/redis/etc/redis.conf
 70 bind 0.0.0.0
 172 logfile /apps/redis/log/redis6379.log
 264 dir /apps/redis/data/
 288  replicaof 192.168.204.60 6379  //设置 主从配置
 700 appendonly yes
[root@node7 ~]#  systemctl restart redis

2.实现redis的级联复制

master和slave1节点无需修改,只需要修改slave2指向slave1做为mater即可。

  • master 192.168.204.60
  • slave1 192.168.204.50
  • slave2 192.168.204.70

主服务器master:

点击查看代码
[root@node6 ~]#  systemctl stop firewalld
[root@node6 ~]#  setenforce 0
安装redis

[root@node6 ~]#  vim /apps/redis/etc/redis.conf  //修改配置文件
 70 bind 0.0.0.0                             //将监听端口改为任意端口
 172 logfile /apps/redis/log/redis6379.log   //指定日志文件目录
 264 dir /apps/redis/data/                   //指定工作目录
 700 appendonly yes                          //开启AOF持久化功能
[root@node6 ~]#  systemctl restart redis         //重启服务

从服务器slave1:

点击查看代码
[root@node5 ~]#  systemctl stop firewalld
[root@node5 ~]#  setenforce 0
安装redis

[root@node5 ~]#  vim /apps/redis/etc/redis.conf
 70 bind 0.0.0.0
 172 logfile /apps/redis/log/redis6379.log
 264 dir /apps/redis/data/
 288  replicaof 192.168.204.60 6379  //设置 主从配置
 700 appendonly yes
[root@node5 ~]#  systemctl restart redis

从服务器slave2:

点击查看代码
[root@node7 ~]#  systemctl stop firewalld
[root@node7 ~]#  setenforce 0
安装redis

[root@node7 ~]#  vim /apps/redis/etc/redis.conf
 70 bind 0.0.0.0
 172 logfile /apps/redis/log/redis6379.log
 264 dir /apps/redis/data/
 288  replicaof 192.168.204.50 6379  //设置 主从配置
 700 appendonly yes
[root@node7 ~]#  systemctl restart redis

3.主从复制过程

Redis主从复制分为全量同步和增量同步。

点击查看代码
`具体主从同步过程如下:`
1)从服务器连接主服务器,发送PSYN(同步)C命令
2)主服务器接收到PSYNC命令后,开始执行BGSAVE命令生成RDB快照文件并使用缓冲区记录此后执行的所有写命令
3)主服务器BGSAVE执行完后,向所有从服务器发送RDB快照文件,并在发送期间继续记录被执行的写命令
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照至内存
5)主服务器快照发送完毕后,开始向从服务器发送缓冲区中的写命令
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
7)后期同步会先发送自己slave_repl_offset位置,只同步新增加的数据,不再全量同步

4.主从复制优化

复制缓冲区(环形队列)配置参数

点击查看代码
//复制缓冲区大小,建议要设置足够大
repl-backlog-size 1mb 

//Redis同时也提供了当没有slave需要同步的时候,多久可以释放环形队列:  
repl-backlog-ttl   3600   //最长保持时间  3600秒

避免全量复制

  • 第一次全量复制不可避免,后续的全量复制可以利用小主节点(内存小),业务低峰时进行全量

  • 节点运行ID不匹配:主节点重启会导致RUNID变化,可能会触发全量复制,可以利用故障转移,例如哨兵或集群,而从节点重启动,不会导致全量复制

  • 复制积压缓冲区不足: 当主节点生成的新数据大于缓冲区大小,从节点恢复和主节点连接后,会导致全量复制。解决方法将 repl-backlog-size 调大。

避免复制风暴

单主节点复制风暴

  • 当主节点重启,多从节点复制。解决方法:更换复制拓扑

单机器多实例复制风暴

  • 机器宕机后,大量全量复制。解决方法:主节点分散多机器

性能相关配置

点击查看代码
repl-diskless-sync no 
//是否使用无盘同步RDB文件,默认为no,no为不使用无盘,需要将RDB文件保存到磁盘后再发送给slave,yes为支持无盘,支持无盘就是RDB文件不需要保存至本地磁盘,而且直接通过socket文件发送给slave

repl-diskless-sync-delay 5 
//diskless时复制的服务器等待的延迟时间

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不接收写操作(拒绝写入)

5.常见主从复制故障

1.master密码不对

即配置的master密码不对,导致验证不通过而无法建立主从同步关系。

2.Redis版本不一致

不同的redis 大版本之间存在兼容性问题,比如:3和4,4和5之间,因此各master和slave之间必须保持版本一致。

3.无法远程连接

在开启了安全模式情况下,没有设置bind地址或者密码。

4.配置不一致

主从节点的maxmemory不一致,主节点内存大于从节点内存,主从复制可能丢失数据rename-command 命令不一致,如在主节点定义了fushall,flushdb,从节点没定义,结果执行flushdb,不同步。

二、哨兵模式(Sentinel)

Sentinel实际上是一个特殊的redis服务器,有些redis指令支持,但很多指令并不支持。默认监听在26379/tcp 端口。

1.哨兵工作原理

sentinel中的三个定时任务:

  • 每10秒每个sentinel对master和slave执行info

发现slave节点
确认主从关系

  • 每2秒每个sentinel通过master节点的channel交换信息(pub/sub)

通过sentinel__:hello频道交互
交互对节点的“看法”和自身信息

  • 每1秒每个sentinel对其他sentinel和redis执行ping

2.实现哨兵

哨兵的前提是已经实现了一个redis的主从复制的运行环境,从而实现一个一主两从基于哨兵的高可用

  • master 192.168.204.60
  • slave 192.168.204.50
  • slave 192.168.204.70

1.先实现主从复制 (见一、1.主从复制实现

点击查看代码
`在所有主从节点执行`
vim /etc/redis.conf
bind 0.0.0.0
masterauth "123456"    //设置 Redis 主节点的密码
requirepass "123456"   //设置 Redis 从节点的密码

systemctl start redis  //注意!先开启主节点redis!再开启从

redis-cli -a 123456    //由于上面在配置文件中添加了密码,所有此处需要-a输入密码登录
127.0.0.1:6379> info replication  //查看主从状态

2.编辑哨兵的配置文件

点击查看代码
[root@node6 ~]#  cd /data/redis-5.0.7/
[root@node6 redis-5.0.7]#  ls
00-RELEASENOTES  CONTRIBUTING  deps     Makefile   README.md   runtest          runtest-moduleapi  sentinel.conf  tests
BUGS             COPYING       INSTALL  MANIFESTO  redis.conf  runtest-cluster  runtest-sentinel   src            utils
[root@node6 redis-5.0.7]#  cp sentinel.conf /apps/redis/etc/
[root@node6 redis-5.0.7]#  cd /apps/redis/etc/
[root@node6 etc]#  ls
redis.conf  sentinel.conf
[root@node6 etc]#  chown -R redis.redis /apps/redis/etc/

[root@node6 etc]#  vim sentinel.conf  //编辑配置文件
 16 bind 0.0.0.0   //修改监听端口
 22 port 26379     //默认监听端口,不用修改
 27 daemonize no   //不用修改
 32 pidfile /apps/redis/run/redis-sentinel.pid  //指定pid文件位置
 37 logfile /apps/redis/log/sentinel.log        //指定日志文件位置  
 66 dir /tmp       //工作目录不用修改
 85 sentinel monitor mymaster 192.168.204.60 6379 2
//mymaster是集群的名称,此行指定当前mymaster集群中master服务器的地址和端口。2为法定人数限制(quorum),即有几个sentinel认为master down了就进行故障转移
 88 sentinel auth-pass mymaster 123456  
//mymaster集群中master的密码
115 sentinel down-after-milliseconds mymaster 3000 
//(SDOWN)判断mymaster集群中所有节点的主观下线的时间。单位:毫秒
123 sentinel parallel-syncs mymaster 1
//发生故障转移后,可以同时向新master同步数据的slave的数量,数字越小总同步时间越长,但可以减轻新master的负载压力
148 sentinel failover-timeout mymaster 1800
//所有slaves指向新的master所需的超时时间,单位:毫秒


[root@node6 etc]#  scp sentinel.conf 192.168.204.50:/apps/redis/etc/  //拷贝配置文件
[root@node6 etc]#  scp sentinel.conf 192.168.204.70:/apps/redis/etc/

[root@node5 ~]# cd /apps/redis/etc/
[root@node5 etc]#  chown redis.redis sentinel.conf  
[root@node7 ~]# cd /apps/redis/etc/
[root@node7 etc]#  chown redis.redis sentinel.conf

3.准备service文件,全部节点都需要

点击查看代码
[root@node6 etc]#  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@node6 etc]#  systemctl daemon-reload
[root@node6 etc]#  systemctl start redis-sentinel.service

[root@node6 etc]#  ss -natp |grep 26379

4.关掉主服务器进行验证

点击查看代码
[root@node6 ~]#  systemctl stop redis

主在恢复后会变成从

点击查看代码
[root@node6 ~]#  systemctl restart redis

三、Redis Cluster

1.Redis Cluster工作原理

在哨兵sentinel机制中,可以解决redis高可用问题,即当master故障后可以自动将slave提升为master,从而可以保证redis服务的正常使用,但是无法解决redis单机写入的瓶颈问题,即单机redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素。
为了解决单机性能的瓶颈,提高Redis 性能,可以使用分布式集群的解决方案。

Redis Cluster 特点如下:

  • 所有Redis节点使用(PING机制)互联

  • 集群中某个节点的是否失效,是由整个集群中超过半数的节点监测都失效,才能算真正的失效

  • 客户端不需要proxy即可直接连接redis,应用程序中需要配置有全部的redis服务器IP

  • redis cluster把所有的redis node 平均映射到 0-16383 槽位 上,读写需要到指定的redis node上进行操作,因此有多少个redis node相当于redis 并发扩展了多少倍,每个redis node 承担16384/N个槽位

  • Redis cluster预先分配16384个(slot)槽位,当需要在redis集群中写入一个key -value的时候,会使用CRC16(key) mod 16384之后的值,决定将key写入值哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈

2.实现集群

redis的集群一般需要6个节点,3主3从。方便起见,开启多实例,所有节点在同一台服务器上模拟。 以端口号进行区分:3个主节点端口号:6001/6002/6003,对应的从节点端口号:6004/6005/6006 (可能随机搭配)

1.新建集群文件目录

点击查看代码
[root@node5 ~]#  cd  /apps/redis/
[root@node5 redis]#  mkdir -p redis-cluster/redis600{1..6}

2.准备可执行文件到每个文件夹

点击查看代码
[root@node5 redis]#  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

3.开启集群功能

点击查看代码
[root@node5 redis]#  cd /apps/redis/redis-cluster/redis6001/
[root@node5 redis6001]#  vim redis.conf
  70 bind 0.0.0.0         //监听所有网卡
  89 protected-mode no    //关闭保护模式
  93 port 6001            //修改redis监听端口
 137 daemonize yes        //开启守护进程
 701 appendonly yes       //开启AOF持久化
 834 cluster-enabled yes  //开启群集功能
 842 cluster-config-file nodes-6001.conf  //群集名称文件设置
 848 cluster-node-timeout 15000           //群集超时时间设置

[root@node5 redis6001]#  for i in {2..6}  //复制配置文件,注意要切换到redis6001目录下执行
> do
> \cp -f  ./redis.conf   /apps/redis/redis-cluster/redis600${i}
> done

//其他5个文件夹的配置文件以此类推修改,注意6个端口都要不一样
[root@node5 redis6001]#  sed  -i   's/6001/6002/'   /apps/redis/redis-cluster/redis6002/redis.conf
[root@node5 redis6001]#  sed  -i   's/6001/6003/'   /apps/redis/redis-cluster/redis6003/redis.conf
[root@node5 redis6001]#  sed  -i   's/6001/6004/'   /apps/redis/redis-cluster/redis6004/redis.conf
[root@node5 redis6001]#  sed  -i   's/6001/6005/'   /apps/redis/redis-cluster/redis6005/redis.conf
[root@node5 redis6001]#  sed  -i   's/6001/6006/'   /apps/redis/redis-cluster/redis6006/redis.conf

[root@node5 redis-cluster]#  chown -R redis.redis /apps/redis/  

4.启动redis节点

点击查看代码
[root@node5 redis-cluster]#  cd /apps/redis/redis-cluster/redis6001  //切换目录
[root@node5 redis6001]#  for d in {1..6}   //用脚本启动
> do
> cd /apps/redis/redis-cluster/redis600$d
> redis-server redis.conf
> done

5.查看是否成功启动

点击查看代码
[root@node5 redis6006]#  ss -natp |grep "\b600[1-6]\b"
LISTEN     0      511          *:6001                     *:*                   users:(("redis-server",pid=59124,fd=6))
LISTEN     0      511          *:6002                     *:*                   users:(("redis-server",pid=59126,fd=6))
LISTEN     0      511          *:6003                     *:*                   users:(("redis-server",pid=59131,fd=6))
LISTEN     0      511          *:6004                     *:*                   users:(("redis-server",pid=59136,fd=6))
LISTEN     0      511          *:6005                     *:*                   users:(("redis-server",pid=59141,fd=6))
LISTEN     0      511          *:6006                     *:*                   users:(("redis-server",pid=59146,fd=6))

6.启动集群

点击查看代码
[root@node5 redis6006]# 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
//六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点。下面交互的时候 需要输入yes才可以创建。
//--replicas 1 表示每个主节点有1个从节点

7.测试集群

点击查看代码
[root@node5 redis6006]#  redis-cli -p 6001  -c  //加-c参数,节点之间就可以互相跳转
127.0.0.1:6001> cluster slots   //查看节点的哈希槽编号范围
1) 1) (integer) 0
   2) (integer) 5460        //哈希槽编号范围
   3) 1) "127.0.0.1"   
      2) (integer) 6001     //主节点IP和端口号
      3) "b4ebafd25670e4bf6f3e9fa16bad9d1a0441d981"
   4) 1) "127.0.0.1"
      2) (integer) 6005     //从节点IP和端口号
      3) "043eac265825debc6efe592a25f4e388b89a3560"
2) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 6003
      3) "a925a46cbe6808a38b4b93cf4d7a86990a405d49"
   4) 1) "127.0.0.1"
      2) (integer) 6004
      3) "1de8699171fd789095fc7eb54de556f6da68cf17"
3) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 6002
      3) "8b332121f676674bd4beb3ef2bfa6cc8220c2873"
   4) 1) "127.0.0.1"
      2) (integer) 6006
      3) "629aefcf46649f419a824f44117ce9ccae658fac"

8.生成数据测试

点击查看代码
127.0.0.1:6001> keys * 
(empty list or set)
127.0.0.1:6001> set name zwy  //对name键进行算法,得出值为5789,跳到对应的节点存储
-> Redirected to slot [5798] located at 127.0.0.1:6002
OK
127.0.0.1:6002> keys *  //此处可以看到跳转到6002
1) "name"

9.查看节点信息

点击查看代码
127.0.0.1:6002> CLUSTER NODES  //查看节点信息,注意大写
043eac265825debc6efe592a25f4e388b89a3560 127.0.0.1:6005@16005 slave b4ebafd25670e4bf6f3e9fa16bad9d1a0441d981 0 1720616594403 1 connected
b4ebafd25670e4bf6f3e9fa16bad9d1a0441d981 127.0.0.1:6001@16001 master - 0 1720616594000 1 connected 0-5460
629aefcf46649f419a824f44117ce9ccae658fac 127.0.0.1:6006@16006 slave 8b332121f676674bd4beb3ef2bfa6cc8220c2873 0 1720616594000 2 connected
a925a46cbe6808a38b4b93cf4d7a86990a405d49 127.0.0.1:6003@16003 master - 0 1720616594000 3 connected 10923-16383
8b332121f676674bd4beb3ef2bfa6cc8220c2873 127.0.0.1:6002@16002 myself,master - 0 1720616593000 2 connected 5461-10922
1de8699171fd789095fc7eb54de556f6da68cf17 127.0.0.1:6004@16004 slave a925a46cbe6808a38b4b93cf4d7a86990a405d49 0 1720616595410 3 connected

posted @   leikj  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek “源神”启动!「GitHub 热点速览」
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示