redis高可用哨兵与集群cluster

一、redis集群介绍

在主从架构中,无法实现主从之间角色的切换问题,即当master出现故障时(如服务器异常、断点、磁盘损坏等问题)导致master无法正常使用了,而主从复制无法实现自动的故障转移(将slave自动提升为新的master),需要手动修改环境配置,才能切换到slave服务器中,另外当单台redis服务器性能服务满足业务写入需求的时候,也无法横向扩展redis服务的并行写入性能。

需要解决以上的两个核心问题:

1.master和slave角色的无缝切换问题,让业务无感知从而不影响业务使用

2.可横向动态扩展redis服务器,从而实现多台服务器并行写入以实现更高并发的目的。

redis集群实现方式:

1.客户端分片:由应用决定将不同的KEY发送到不同的redis服务器上

2.代理分片:由代理决定将不同的KEY发送到不同的redis服务器,代理程序如:codis,twemproxy等。

3.redis cluster

以下实验中,redis的安装不做重点,可以看我之前的安装redis

编译安装redis

环境概述:

Node1:192.168.114.10作为主

Node2:192.168.114.20作为从1

Node3:192.168.114.30作为从2

二、redis哨兵模式sentinel

2.1 sentinel故障转移

1.多个sentinel发现并确认master有问题。

2.选举出一个sentinel作为领导。

3.选出一个slave作为master。

4.通知其余slave成为新的master的slave。

5.通知客户端主从变化。

6.等待老的master复活成为新master的slave。

2.2 sentinel中的三个定时任务

每10秒每个sentinel对master和slave执行info,发现slave,确认主从关系

每2秒每个sentinel通过master节点的channel交换信息,通过sentinel_:hello频道交互,交互对节点的“看法”和自身信息

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

2.3 哨兵的准备实现主从复制架构

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

注意:master的配置文件中masterauth和slave都必须相同。

所有主节点的redis.conf中关键配置。

范例:准备主从环境配置

需要先实现主从复制。

2.4 实现哨兵

先做主从复制。在两个从上修改配合文件:

 两个从上指向一个主服务器。

[root@Node2 redis]#:vim etc/redis.conf
replicaof 192.168.114.10 6379

[root@Node3 redis]#:vim etc/redis.conf
replicaof 192.168.114.10 6379

重启服务:systemctl restart redis

可以查看主从关系:

进入数据库,redis-cli

查看主服务器:

做哨兵模式的配置文件:

把源码包的sentinel配置文件拷贝到配置文件下:修改以下配置项。前面是行号。

[root@Node1 redis]#:cp /data/redis-5.0.7/sentinel.conf etc/
[root@Node1 redis]#:chown redis:redis etc/sentinel.conf 
[root@Node1 redis]#:vim etc/sentinel.conf
15:bind 0.0.0.0
31:pidfile /data/redis/run/redis-sentinel.pid
36:logfile /apps/redis/log/sentinel.log
84:sentinel monitor mymaster 192.168.114.10 6379 2
86:sentinel auth-pass mymaster 123456
113:sentinel down-after-milliseconds mymaster 3000
146:sentinel failover-timeout mymaster 18000

查看修改: 

#1.指定所有主机
bind 0.0.0.0
#2.哨兵模式默认端口号26379
port 26379
#3.不用修改,是否以systemd模式启动
daemonize no
#4.指定pid文件位置
pidfile /apps/redis/run/redis-sentinel.pid
#5.指定日志文件位置
logfile /apps/redis/log/sentinel.log
#6.临时文件
dir /tmp
#7.集群的名字:mymaster,192.168.114.10主的IP和6379端口号,2法定人数限制,有几个sentinel认为master down了就进行故障转移。这个节点数一般为>=3的奇数个
sentinel monitor mymaster 192.168.114.10 6379 2
#8.集群名字的密码
sentinel auth-pass mymaster 123456
#9.判断mymaster集群中的所有结点的主观下线的时间,单位毫秒,建议3000(3秒),否则等待时间过长
sentinel down-after-milliseconds mymaster 3000
#10.发生故障转以后,可以同时向新master同步数据slave的数量,数字越小总同步时间越长,但可以减轻master的负载压力
sentinel parallel-syncs mymaster 1
#11.所有slave指向新的master所需的超时时间,单位:毫秒。超过18s返回超时
sentinel failover-timeout mymaster 18000
#12禁止修改脚本
sentinel deny-scripts-reconfig yes

systemctl 管理:

[root@Node1 redis]#: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

把Node1上的sentinel配置文件通过远程拷贝过去:

去从上修改:

两个从上的配置文件不需要修改,只需要修改一个权限,属主和属组即可:

systemd管理,service文件:

[root@Node2 etc]#:cat /lib/systemd/system/redis-sentinel.service 
[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 
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target

[root@Node3 etc]#:cat /lib/systemd/system/redis-sentinel.service
[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 
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target

重新加载systemd文件:

[root@Node1 redis]#:systemctl daemon-reload
[root@Node2 redis]#:systemctl daemon-reload
[root@Node3 redis]#:systemctl daemon-reload

开启服务,先开主服务器,再开从服务器,否则从认为主挂了。

[root@Node1 redis]#:systemctl start redis-sentinel.service
[root@Node2 redis]#:systemctl start redis-sentinel.service
[root@Node3 redis]#:systemctl start redis-sentinel.service

在三台服务器上观察日志:再开一个终端,实时观察日志变化。

此时,三台服务器上显示的主都是Node1:

从:

当我们把主redis服务器关闭时,观察日志变化。

[root@Node1 redis]#:systemctl stop redis

在主上能看到,先sdown,在odown,就是sentinel自己主观认为主down掉了,然后从上的sentinel也认为主服务器down了,三者达成共识,那么就客观的认为主服务器down了:odown。并且主服务器也切换成了Node2服务器。

可以验证,登录redis,查看Node2是否由slave变为了master,Node3是否指向了Node2。

Node3还是从,但是Node3的主不在是Node1了,关闭了Node1的redis之后,主就是Node2了,指向了Node2。

如果此时,再开启Node1,可能就会变成从。

这时Node1开启后,自己是从,主还是Node2.

三、cluster集群模式

3.1 redis cluster工作原理

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

为了解决单机性能的瓶颈,提高Redis 性能,可以使用分布式集群的解决方案

早期Redis 分布式集群部署方案:

1.客户端分区:由客户端程序决定key写分配和写入的redis node,但是需要客户端自己实现写入分配、高可用管理和故障转移等

2.代理方案:基于三方软件实现redis proxy,客户端先连接之代理层,由代理层实现key的写入分配,对客户端来说是有比较简单,但是对于集群管节点增减相对比较麻烦,而且代理本身也是单点和性能瓶颈。

redis 3.0版本之后推出了无中心架构的redis cluster机制,在无中心的redis集群当中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连接

Redis Cluster特点如下:

1.  所有Redis节点使用(PING机制)互联
2.  集群中某个节点的是否失效,是由整个集群中超过半数的节点监测都失效,才能算真正的失效
3.  客户端不需要proxy即可直接连接redis,应用程序中需要配置有全部的redis服务器IP
4.  redis cluster把所有的redis node 平均映射到 0-16383个槽位(slot)上,读写需要到指定的redis node上进行操作,因此有多少个redis node相当于redis 并发扩展了多少倍,每个redis node 承担16384/N个槽位
5.  Redis cluster预先分配16384个(slot)槽位,当需要在redis集群中写入一个key -value的时候,会使用CRC16(key) mod 16384之后的值,决定将key写入值哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈。

3.2 Redis cluster架构

3.2.1 Redis cluster基本架构

假如三个主节点分别是:A, B, C 三个节点,采用哈希槽 (hash slot)的方式来分配16384个slot 的话它们三个节点分别承担的slot 区间可以是:

节点A覆盖 0-5460
节点B覆盖 5461-10922
节点C覆盖 10923-16383

3.2.2 Redis cluster 主从架构

Redis cluster的架构虽然解决了并发的问题,但是又引入了一个新的问题,每个Redis master的高可用。

如何解决?那就是对每个master 节点都实现主从复制,从而实现 redis 高可用性

3.2.3 部署方式介绍

redis cluster 有多种部署方法

原生命令安装

理解Redis Cluster架构

生产环境不使用

官方工具安装

高效、准确

生产环境可以使用

自主研发

可以实现可视化的自动化部署

3.3 实现集群

由于是模拟一台服务器实现,就从刚一安装好redis开始。

开启多实例 来实现redis

redis的集群一般需要6个节点,3主3从。方便起见,这里所有节点在同一台服务器上模拟:

以端口号进行区分:3个主节点端口号:6001/6002/6003,对应的从节点端口号:6004/6005/6006

3.3.1 新建目录

[root@Node1 ~]#:cd /apps/redis/
[root@Node1 redis]#:mkdir -p redis-cluster/redis600{1..6}

3.3.2 准备可执行文件到每个文件夹下

[root@Node1 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

查看文件树型结构:每个实例文件下都有一个配置文件,启动文件,和登录文件。

[root@Node1 redis]#:cd redis-cluster/
[root@Node1 redis-cluster]#:tree
.
├── redis6001
│   ├── redis-cli
│   ├── redis.conf
│   └── redis-server
├── redis6002
│   ├── redis-cli
│   ├── redis.conf
│   └── redis-server
├── redis6003
│   ├── redis-cli
│   ├── redis.conf
│   └── redis-server
├── redis6004
│   ├── redis-cli
│   ├── redis.conf
│   └── redis-server
├── redis6005
│   ├── redis-cli
│   ├── redis.conf
│   └── redis-server
└── redis6006
    ├── redis-cli
    ├── redis.conf
    └── redis-server

6 directories, 18 files

3.3.3 开启群集功能

6001端口的配置。

[root@Node1 redis-cluster]#:pwd
/apps/redis/redis-cluster
[root@Node1 redis-cluster]#:ls
redis6001  redis6002  redis6003  redis6004  redis6005  redis6006
[root@Node1 redis-cluster]#:vim redis6001/redis.conf
#bind 127.0.0.1							#69行,注释掉bind 项,默认监听所有网卡
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持久化

其他5个文件夹的配置文件以此类推修改,注意6个端口都要不一样。

[root@Node1 redis-cluster]#:ls
redis6001  redis6002  redis6003  redis6004  redis6005  redis6006
[root@Node1 redis-cluster]#:sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/'   -e 's/protected-mode yes/protected-mode no/' -e  's/^port .*/port 6002/' -e 's/^daemonize .*/daemonize yes/' -e  's/^# cluster-enabled .*/cluster-enabled yes/'  -e 's/^# cluster-config-file .*/cluster-config-file nodes-6002.conf/' -e 's/^# cluster-node-timeout .*/cluster-node-timeout 15000/' -e 's/appendonly no/appendonly yes/' redis6002/redis.conf
[root@Node1 redis-cluster]#:
[root@Node1 redis-cluster]#:
[root@Node1 redis-cluster]#:sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/'   -e 's/protected-mode yes/protected-mode no/' -e  's/^port .*/port 6003/' -e 's/^daemonize .*/daemonize yes/' -e  's/^# cluster-enabled .*/cluster-enabled yes/'  -e 's/^# cluster-config-file .*/cluster-config-file nodes-6003.conf/' -e 's/^# cluster-node-timeout .*/cluster-node-timeout 15000/' -e 's/appendonly no/appendonly yes/' redis6003/redis.conf
[root@Node1 redis-cluster]#:
[root@Node1 redis-cluster]#:sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/'   -e 's/protected-mode yes/protected-mode no/' -e  's/^port .*/port 6004/' -e 's/^daemonize .*/daemonize yes/' -e  's/^# cluster-enabled .*/cluster-enabled yes/'  -e 's/^# cluster-config-file .*/cluster-config-file nodes-6004.conf/' -e 's/^# cluster-node-timeout .*/cluster-node-timeout 15000/' -e 's/appendonly no/appendonly yes/' redis6004/redis.conf
[root@Node1 redis-cluster]#:
[root@Node1 redis-cluster]#:sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/'   -e 's/protected-mode yes/protected-mode no/' -e  's/^port .*/port 6005/' -e 's/^daemonize .*/daemonize yes/' -e  's/^# cluster-enabled .*/cluster-enabled yes/'  -e 's/^# cluster-config-file .*/cluster-config-file nodes-6005.conf/' -e 's/^# cluster-node-timeout .*/cluster-node-timeout 15000/' -e 's/appendonly no/appendonly yes/' redis6005/redis.conf
[root@Node1 redis-cluster]#:
[root@Node1 redis-cluster]#:sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/'   -e 's/protected-mode yes/protected-mode no/' -e  's/^port .*/port 6006/' -e 's/^daemonize .*/daemonize yes/' -e  's/^# cluster-enabled .*/cluster-enabled yes/'  -e 's/^# cluster-config-file .*/cluster-config-file nodes-6006.conf/' -e 's/^# cluster-node-timeout .*/cluster-node-timeout 15000/' -e 's/appendonly no/appendonly yes/' redis6006/redis.conf

这里通过sed把所有的配置文件下的redis.conf文件统一修改了。

3.3.4 启动redis节点

这里先把原来的redis6379停止:

[root@Node1 redis-cluster]#:systemctl stop redis

分别进入六个文件夹,使用redis-server启动redis节点。使用脚本启动。

[root@Node1 redis6001]#:for r in {1..6}
> do
> cd /apps/redis/redis-cluster/redis600$r
> redis-server redis.conf
> done

3.3.5 查看时是否启动成功

[root@Node1 redis-cluster]#:ps -ef | grep redis
root       9201      1  0 22:55 ?        00:00:00 redis-server *:6001 [cluster]
root       9217      1  0 22:56 ?        00:00:00 redis-server 0.0.0.0:6002 [cluster]
root       9219      1  0 22:56 ?        00:00:00 redis-server 0.0.0.0:6003 [cluster]
root       9224      1  0 22:56 ?        00:00:00 redis-server 0.0.0.0:6004 [cluster]
root       9229      1  0 22:56 ?        00:00:00 redis-server 0.0.0.0:6005 [cluster]
root       9234      1  0 22:56 ?        00:00:00 redis-server 0.0.0.0:6006 [cluster]
root       9318   4182  0 23:00 pts/0    00:00:00 grep --color=auto redis

可以看到,六个端口都启动了。 

3.3.6 启动集群

六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点。下面交互的时候,需要输入yes才能创建。

--replicas 1表示每个主节点有1个从节点。

[root@Node1 redis-cluster]#: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
......
Can I set the above configuration? (type 'yes' to accept): yes        #这里输入yes
......
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

3.3.7 测试集群

加-c参数,节点之间就可以互相跳转了。

[root@Node1 redis-cluster]#:redis-cli -p 6001 -c
127.0.0.1:6001> ping
PONG
127.0.0.1:6001> cluster slots
1) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 6002
      3) "5fb86b2a4ae95c75cbb7cff1564f69075b9ad1c9"
   4) 1) "127.0.0.1"
      2) (integer) 6005
      3) "ffd44fa6827151b1b36c1762603c50eff97f2553"
2) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 6003
      3) "b0bc0de8f9c1f74624ec3f8d960be5f2e8a39f61"
   4) 1) "127.0.0.1"
      2) (integer) 6006
      3) "c89cb1188cb478943d7588f17a01ab654c649b50"
3) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 6001
      3) "50fc7bcb64ae4d64443b8de514af9fe722455398"
   4) 1) "127.0.0.1"
      2) (integer) 6004
      3) "1186fba78b73e87a8635e72463e253cfdb892e64"

127.0.0.1:6001> cluster slots                        #查看节点的哈希槽编号范围

1) 1) (integer) 5461
   2) (integer) 10922                #哈希槽编号范围
   3) 1) "127.0.0.1"                        #主节点端口
      2) (integer) 6002                #主节点IP地址
      3) "5fb86b2a4ae95c75cbb7cff1564f69075b9ad1c9"
   4) 1) "127.0.0.1"                        #从节点IP
      2) (integer) 6005                #从节点端口
      3) "ffd44fa6827151b1b36c1762603c50eff97f2553"

......

3.3.8 生成数据测试

对name键进行算法,得出值为5798,跳到对应的节点上存储

127.0.0.1:6001> set name zhangsan
-> Redirected to slot [5798] located at 127.0.0.1:6002
OK
127.0.0.1:6002>

3.3.9 查看name键的槽编号

查看name键的槽编号

127.0.0.1:6002> cluster keyslot name
(integer) 5798

3.3.10 查看节点信息

127.0.0.1:6002> cluster nodes
c89cb1188cb478943d7588f17a01ab654c649b50 127.0.0.1:6006@16006 slave b0bc0de8f9c1f74624ec3f8d960be5f2e8a39f61 0 1721488988969 6 connected
ffd44fa6827151b1b36c1762603c50eff97f2553 127.0.0.1:6005@16005 slave 5fb86b2a4ae95c75cbb7cff1564f69075b9ad1c9 0 1721488989977 5 connected
b0bc0de8f9c1f74624ec3f8d960be5f2e8a39f61 127.0.0.1:6003@16003 master - 0 1721488987000 3 connected 10923-16383
5fb86b2a4ae95c75cbb7cff1564f69075b9ad1c9 127.0.0.1:6002@16002 myself,master - 0 1721488989000 2 connected 5461-10922
1186fba78b73e87a8635e72463e253cfdb892e64 127.0.0.1:6004@16004 slave 50fc7bcb64ae4d64443b8de514af9fe722455398 0 1721488987000 4 connected
50fc7bcb64ae4d64443b8de514af9fe722455398 127.0.0.1:6001@16001 master - 0 1721488988000 1 connected 0-5460

节点信息记录了主从端口,以及唯一编号。

---end---

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值