Redis 群集详解

目录

一,Redis群集概念

二,Redis主从复制

1,Redis主从复制的概念

2,Redis主从复制的搭建

三,哨兵模式

1,哨兵模式的原理

2,哨兵模式的作用和组成

3,哨兵模式的故障转移机制

4,哨兵模式的搭建

四,Redis集群

1,Redis集群基础

2,Redis Cluster的工作原理

3,Redis集群的基本架构

4,搭建Redis集群


一,Redis群集概念

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

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

  2. 哨兵:在主从复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡:存储能力受到单机的限制;哨兵无法对从节点进行自动故障转移,在读写分离场景下,从节点故障会导致读服务不可用,需要对从节点做额外的监控、切换操作。

  3. 集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。

二,Redis主从复制

1,Redis主从复制的概念

主从复制,是指将一台redis服务器的数据,复制到其他的redis服务器。前者称为主节点(master),后者称为从节点(slave);数据复制是单向的,只能由主节点到从节点。

默认情况下,每台redis服务器都是主节点;且一个主节点可以有多个从节点(或者没有从节点),但是每一个从节点只能有一个主节点。

Redis只从复制的作用

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

  • 负载均衡:在主从复制的基础.上,配合读写分离,可以让主节点提供写服务,由从节点提供读服务〈即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

  • 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

Redis只从复制的流程

  1. 若启动一个Slave机器,则它会向Master机器发送一个"sync command"命令,请求同步连接。从发给主

  2. 无论是第一次连接还是重新连接,Master机器都会启动一个后台进程,将数据快照保存到数据文件中(执行rdb操作),同时Master还会记录修改数据的所有命令并缓存在数据文件中。

  3. 后台进程完成缓存操作之后,Master机器就会向Slave机器发送数据文件存储,接着Master机器就会将修改数据的所有操作一并发送给Slave端机器。若slave出现故障导致宕机,则恢复正常后会自动重新连接。

  4. Master机器收到Slave端机器的连接后,将其完整的数据文件发送给slave端机器,如果Master同时收到多个slave发来的同步请求,则Master会在后台启动一个进程以保存数据文件,然后将其发送给所有的Slave端机器,确保所有的Slave端机器都正常。

2,Redis主从复制的搭建

1,环境设定

master节点:192.168.18.100     安装Redis

slaves1节点:192.168.18.109    安装Redis

slaves1节点:192.168.18.90       安装Redis

2,安装Redis(三台服务器操作一致)

关闭防火墙和selinux

[root@localhost ~]# systemctl stop firewalld.service 
[root@localhost ~]# setenforce 0

安装环境依赖包

[root@localhost ~]# yum install -y gcc gcc-c++ make
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
................
正在尝试其它镜像。
软件包 gcc-4.8.5-44.el7.x86_64 已安装并且是最新版本
软件包 gcc-c++-4.8.5-44.el7.x86_64 已安装并且是最新版本
软件包 1:make-3.82-24.el7.x86_64 已安装并且是最新版本
无须任何处理

将安装包上传到/opt目录下解压

[root@localhost opt]# rz -E
rz waiting to receive.
[root@localhost opt]# tar zxf redis-5.0.7.tar.gz -C /opt/
[root@localhost opt]# ls
mysql-5.7.20               redis-5.0.7         rh
mysql-boost-5.7.20.tar.gz  redis-5.0.7.tar.gz

由于Redis源码包中直接提供了Makefile 文件,所以在解压完软件包后,不用先执行./configure 进行配置,可直接执行make与make install命令进行安装

切换目录安装

[root@localhost opt]# cd redis-5.0.7/
[root@localhost redis-5.0.7]# make
cd src && make all
make[1]: 进入目录“/opt/redis-5.0.7/src”
    CC Makefile.dep
make[1]: 离开目录“/opt/redis-5.0.7/src”
...........
  CC lolwut.o
    CC lolwut5.o
    LINK redis-server
    INSTALL redis-sentinel
    CC redis-cli.o
    LINK redis-cli
    CC redis-benchmark.o
    LINK redis-benchmark
    INSTALL redis-check-rdb
    INSTALL redis-check-aof

Hint: It's a good idea to run 'make test' ;)

make[1]: 离开目录“/opt/redis-5.0.7/src”

指定目录安装

[root@localhost redis-5.0.7]# make PREFIX=/usr/local/redis install
cd src && make install
make[1]: 进入目录“/opt/redis-5.0.7/src”
    CC Makefile.dep
..............

    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
make[1]: 离开目录“/opt/redis-5.0.7/src”

执行软件包提供的 install_server.sh 脚本文件设置Redis服务所需要的相关配置文件

[root@localhost utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379]      ##回车
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] ##回车
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] ##回车
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] ##回车
Selected default - /var/lib/redis/6379
Please select the redis executable path [] /usr/local/redis/bin/redis-server
                                            #####输入路径
..........
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!    ###安装完成

添加软链接把redis的可执行程序文件放入路径环境变量的目录中便于系统识别

[root@localhost utils]# ln -s /usr/local/redis/bin/* /usr/local/bin/

查看服务是否开启

[root@localhost utils]# ss -natp|grep 6379
LISTEN     0      128    127.0.0.1:6379                     *:*    
               users:(("redis-server",pid=7634,fd=6))  ##已开启

主服务配置(192.168.18.100)

[root@localhost redis-5.0.7]# vim /etc/redis/6379.conf
.....
 70 bind 0.0.0.0    ##70行监听任意端口
  71 
  72 # Protected mode is a layer of security protection, in order to avoid th     at
.....
137 daemonize yes  ##137行开启守护进程
 138 
 139 # If you run Redis from upstart or systemd, Redis can interact with your
 140 # supervision tree. Options:
700 appendonly yes    ##700行开启aof持久化
 701 
 702 # The name of the append only file (default: "appendonly.aof")

重启服务查看

[root@localhost utils]# /etc/init.d/redis_6379 restart
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
[root@localhost utils]# ss -natp |grep redis
LISTEN     0      128          *:6379                     *:*         
          users:(("redis-server",pid=59607,fd=6))

从节点配置(两台配置相同)

[root@localhost redis-5.0.7]# vim /etc/redis/6379.conf 
.........
70 bind 0.0.0.0   ##70行监听任意端口
  71 
  72 # Protected mode is a layer of security protection, in order to      avoid that
...........
137 daemonize yes ##开启守护进程
 138 
 139 # If you run Redis from upstart or systemd, Redis can interact w     ith your
.........
288  replicaof 192.168.18.100 6379   ###指定主节点ip和端口
........
700 appendonly yes    ##开启AOF持久化
 701 
 702 # The name of the append only file (default: "appendonly.aof")
 703 
 704 appendfilename "appendonly.aof"

重启服务查看

[root@localhost utils]# /etc/init.d/redis_6379 restart
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
[root@localhost utils]# ss -natp|grep redis
LISTEN     0      128          *:6379                     *:*               
    users:(("redis-server",pid=7748,fd=6))
ESTAB      0      0      192.168.18.90:34378              192.168.18.100:6379 
               users:(("redis-server",pid=7748,fd=8))

验证主从复制

在主服务器上查看

[root@localhost utils]# redis-cli info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.18.109,port=6379,state=online,offset=294,lag=1
slave1:ip=192.168.18.90,port=6379,state=online,offset=294,lag=1
master_replid:73751c89704f3befcc59f1709b45fd6e7c6adf3b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:294
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:294

在主服务器上创建文件

[root@localhost utils]# vim redis.sh   ##利用脚本多个创建
#!/bin/bash
num=100
for i in `seq $num`
do
redis-cli  set key${i}  k${i}
done
[root@localhost utils]# bash redis.sh 
OK
OK
OK
OK
OK
OK
OK
....
OK
OK
OK
OK
OK

查看数据

[root@localhost utils]# redis-cli 
127.0.0.1:6379> keys *
  1) "key89"
  2) "key87"
  3) "key48"
  4) "key46"
  5) "key57"
  6) "key93"
  7) "key62"
......

再从服务器上查看是否复制

[root@localhost opt]# redis-cli
127.0.0.1:6379> keys *
  1) "key54"
  2) "key94"
  3) "key25"
  4) "key98"
  5) "key56"
  6) "key68"
  7) "key16"
  8) "key36"
........

从服务器测试是否可以创建数据

127.0.0.1:6379> set 101 key101
(error) READONLY You can't write against a read only replica.
####从服务器上只读不可以创建

三,哨兵模式

哨兵的核心功能:在主从复制的基础上,哨兵引入了主节点的自动故障转移。

1,哨兵模式的原理

哨兵(sentinel):是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的Master并将所有Slave连接到新的 Master。所以整个运行哨兵的集群的数量不得少于3个节点。

2,哨兵模式的作用和组成

作用:

  • 监控:哨兵会不断地检查主节点和从节点是否运作正常。

  • 自动故障转移:当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。

  • 通知提醒:哨兵可以将故障转移的结果发送给客户端。

组成:

  • 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点就是特殊的redis节点,不存储数据

  • 数据节点:主节点和从节点都是数据节点。

哨兵的启动依赖于主从模式,所以须把主从模式安装好的情况下再去做哨兵模式,所有节点上.都需要部署哨兵模式,哨兵模式会监控所有的Redis工作节点是否正常,当Master出现问题的时候,因为其他节点与主节点失去联系,因此会投票,投票过半就认为这个Master的确出现问题,然后会通知哨兵间,然后从Slaves中选取一个作为新的 Master。

需要特别注意的是,客观下线是主节点才有的概念:如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作。

3,哨兵模式的故障转移机制

1.由哨兵节点定期监控发现主节点是否出现了故障,每个哨兵节点每隔1秒会向主节点、从节点及其它哨兵节点发送一次ping命令做一次心跳检测。如果主节点在一定时间范围内不回复或者是回复一个错误消息,那么这个哨兵就会认为这个主节点主观下线了(单方面的),当超过半数哨兵节点认为该主节点下线了,这样就客观下线了。

2.当主节点出现故障,此时哨兵节点会通过Raft算法〈选举算法)实现选举机制共同选举出一个哨兵节点为leader,来负责处理主节点的故障转移和通知。所以整个运行哨兵的集群的数量不得少于3个节点。

3.由leader哨兵节点执行故障转移,过程如下:

●将某一个从节点升级为新的主节点,让其它从节点指向新的主节点;

●若原主节点恢复也变成从节点,并指向新的主节点;

●通知客户端主节点已经更换。

需要特别注意的是,客观下线是主节点才有的概念:如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观线和故障转移操作

主节点的选举:

1过滤掉不健康的(已下线的),没有回复哨兵ping响应的从节点

2选择配置文件中从节点优先级最高的(replication-priority,默认值为100)

3选择复制偏移量最大的,也就是复制最完整的从节点。

sentinel中的三个定时任务

  1. 每10秒每个sentinel对master和slave执行info发现slave节点

  2. 每2秒确认主从关系:每2秒每个sentinel通过master节点的channel交换信息(pub/sub)通过sentinel__:hello频道交互交互对节点的“看法”和自身信息

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

Redis 群集详解_第1张图片

Redis 群集详解_第2张图片

Sentinel 进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用,此功能在redis2.6+的版本已引用,Redis的哨兵模式到了2.8版本之后就稳定了下来。一般在生产环境也建议使用Redis的2.8版本的以后版本。

哨兵(Sentinel) 是一个分布式系统,可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossip protocols)来接收关于Master主服务器是否下线的信息,并使用投票协议(Agreement Protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master

有主观宕机,对应的有客观宕机。当“哨兵群”中的多数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功能后,可以支持更大规模的生产环

4,哨兵模式的搭建

环境设定

环境设定:基于上面主从复制完成

master节点:192.168.18.100
slave1节点:192.168.18.109
slave2节点:192.168.18.90

修改哨兵模式配置文件(所有的服务器均需要操作)

[root@localhost utils]# cd /opt/redis-5.0.7/
[root@localhost redis-5.0.7]# vim sentinel.conf
 17 protected-mode no    ##17行取消注释关闭保护模式
 18 
.....
21 port 26379        ###21行端口号是26379
......
26 daemonize yes     ###26行开启后台运行
 27 
........
 36 logfile "/var/log/sentinel.log"    ##36行指定目录日志
 37 
.....
65 dir "/var/lib/redis/6379"      ###65行指定数据文件目录
...........
84 sentinel monitor mymaster 192.168.18.100 6379 2  ##84行指定master地址
.........
113 sentinel down-after-milliseconds mymaster 15000  ##113行可以修改时间
.......

 146 sentinel failover-timeout mymaster 180000       ###146行故障切换时间

可以将配置文件复制到从服务器上

[root@localhost redis-5.0.7]# scp sentinel.conf 192.168.18.109:/opt/redis-5.0.7 
                                             ##复制到192.168.18.109上指定目录
The authenticity of host '192.168.18.109 (192.168.18.109)' can't be established.
ECDSA key fingerprint is SHA256:pAh0FMORHcDG44nLort2bY+5/jywjUEI8IyTNfnxda4.
ECDSA key fingerprint is MD5:9d:c0:93:c2:3e:09:f3:0e:d1:82:5a:cd:20:15:bd:f1.
Are you sure you want to continue connecting (yes/no)? yes  ##确认
Warning: Permanently added '192.168.18.109' (ECDSA) to the list of known hosts.
[email protected]'s password:  ##输入密码
sentinel.conf                              100% 9752     8.4MB/s   00:00    
[root@localhost redis-5.0.7]# scp sentinel.conf 192.168.18.90:/opt/redis-5.0.7
                                              ##复制到192.168.18.90上指定目录
The authenticity of host '192.168.18.90 (192.168.18.90)' can't be established.
ECDSA key fingerprint is SHA256:+LNvGs5rkKmnfiaUupeBdhiblh+Po6z8SKrm4bvEMNo.
ECDSA key fingerprint is MD5:4b:c2:12:c0:92:1f:c3:77:70:02:92:27:10:2d:bc:57.
Are you sure you want to continue connecting (yes/no)? yea^Hs
Please type 'yes' or 'no': yes  ##确认
Warning: Permanently added '192.168.18.90' (ECDSA) to the list of known hosts.
[email protected]'s password:   ##输入密码
sentinel.conf                              100% 9752    16.4MB/s   00:00 

先启动master服务器在启动从服务器

主开启

[root@localhost redis-5.0.7]# redis-sentinel sentinel.conf &
[1] 59866
[root@localhost redis-5.0.7]# ss -ntap |grep 6379
LISTEN     0      128          *:26379                    *:*                   users:(("redis-sentinel",pid=59866,fd=7))
LISTEN     0      128          *:6379                     *:*                   users:(("redis-server",pid=59607,fd=6))
ESTAB      0      0      192.168.18.100:6379               192.168.18.90:34378               users:(("redis-server",pid=59607,fd=9))
ESTAB      0      0      192.168.18.100:6379               192.168.18.100:49224               users:(("redis-server",pid=59607,fd=11))
ESTAB      0      0      192.168.18.100:46204              192.168.18.109:6379                users:(("redis-sentinel",pid=59866,fd=13))
ESTAB      0      0      192.168.18.100:49224              192.168.18.100:6379                users:(("redis-sentinel",pid=59866,fd=9))
ESTAB      0      0      192.168.18.100:6379               192.168.18.109:34282               users:(("redis-server",pid=59607,fd=8))
ESTAB      0      0      192.168.18.100:49222              192.168.18.100:6379                users:(("redis-sentinel",pid=59866,fd=8))
ESTAB      0      0      192.168.18.100:40168              192.168.18.90:637                users:(("redis-sentinel",pid=59866,fd=10))
ESTAB      0      0      192.168.18.100:46202              192.168.18.109:6379                users:(("redis-sentinel",pid=59866,fd=12))
ESTAB      0      0      192.168.18.100:40170              192.168.18.90:637                users:(("redis-sentinel",pid=59866,fd=11))
ESTAB      0      0      192.168.18.100:6379               192.168.18.100:49222               users:(("redis-server",pid=59607,fd=10))
LISTEN     0      128         :::26379                   :::*                   users:(("redis-sentinel",pid=59866,fd=6))

从开启192.168.18.109

[root@localhost redis-5.0.7]# redis-sentinel sentinel.conf &
[1] 94301
[root@localhost redis-5.0.7]# ss -natp |grep 6379
LISTEN     0      128          *:26379                    *:*                   users:(("redis-sentinel",pid=94301,fd=7))
LISTEN     0      128          *:6379                     *:*                   users:(("redis-server",pid=94148,fd=6))
ESTAB      0      0      192.168.18.109:59882              192.168.18.100:6379                users:(("redis-sentinel",pid=94301,fd=9))
ESTAB      0      0      192.168.18.109:60450              192.168.18.90:6379                users:(("redis-sentinel",pid=94301,fd=13))
ESTAB      0      0      192.168.18.109:60184              192.168.18.109:6379                users:(("redis-sentinel",pid=94301,fd=10))
ESTAB      0      0      192.168.18.109:6379               192.168.18.109:60184               users:(("redis-server",pid=94148,fd=10))
ESTAB      0      0      192.168.18.109:37834              192.168.18.100:26379               users:(("redis-sentinel",pid=94301,fd=14))
ESTAB      0      0      192.168.18.109:60186              192.168.18.109:6379                users:(("redis-sentinel",pid=94301,fd=11))
ESTAB      0      0      192.168.18.109:6379               192.168.18.100:46202               users:(("redis-server",pid=94148,fd=7))
ESTAB      0      0      192.168.18.109:34282              192.168.18.100:6379                users:(("redis-server",pid=94148,fd=8))
ESTAB      0      0      192.168.18.109:60448              192.168.18.90:6379                users:(("redis-sentinel",pid=94301,fd=12))
ESTAB      0      0      192.168.18.109:6379               192.168.18.100:46204               users:(("redis-server",pid=94148,fd=9))
ESTAB      0      0      192.168.18.109:26379              192.168.18.100:49920               users:(("redis-sentinel",pid=94301,fd=15))
ESTAB      0      0      192.168.18.109:6379               192.168.18.109:60186               users:(("redis-server",pid=94148,fd=11))
ESTAB      0      0      192.168.18.109:59880              192.168.18.100:6379                users:(("redis-sentinel",pid=94301,fd=8))
LISTEN     0      128       [::]:26379                 [::]:*                   users:(("redis-sentinel",pid=94301,fd=6))

从服务器开启192.168.18.90

[root@localhost redis-5.0.7]# redis-sentinel sentinel.conf &
[1] 7890
[root@localhost redis-5.0.7]# ss -natp|grep 6379
LISTEN     0      128          *:26379                    *:*                   users:(("redis-sentinel",pid=7890,fd=7))
LISTEN     0      128          *:6379                     *:*                   users:(("redis-server",pid=7748,fd=6))
ESTAB      0      0      192.168.18.90:39722              192.168.18.100:6379                users:(("redis-sentinel",pid=7890,fd=8))
ESTAB      0      0      192.168.18.90:52944              192.168.18.100:26379               users:(("redis-sentinel",pid=7890,fd=15))
ESTAB      0      0      192.168.18.90:6379               192.168.18.90:52226               users:(("redis-server",pid=7748,fd=12))
ESTAB      0      0      192.168.18.90:57878              192.168.18.109:6379                users:(("redis-sentinel",pid=7890,fd=11))
ESTAB      0      0      192.168.18.90:52228              192.168.18.90:6379                users:(("redis-sentinel",pid=7890,fd=13))
ESTAB      0      0      192.168.18.90:6379               192.168.18.100:40170               users:(("redis-server",pid=7748,fd=9))
ESTAB      0      0      192.168.18.90:26379              192.168.18.100:52398               users:(("redis-sentinel",pid=7890,fd=17))
ESTAB      0      0      192.168.18.90:39724              192.168.18.100:6379                users:(("redis-sentinel",pid=7890,fd=9))
ESTAB      0      0      192.168.18.90:6379               192.168.18.100:40168               users:(("redis-server",pid=7748,fd=7))
ESTAB      0      0      192.168.18.90:26379              192.168.18.109:47672               users:(("redis-sentinel",pid=7890,fd=16))
ESTAB      0      0      192.168.18.90:6379               192.168.18.109:60450               users:(("redis-server",pid=7748,fd=11))
ESTAB      0      0      192.168.18.90:41506              192.168.18.109:26379               users:(("redis-sentinel",pid=7890,fd=14))
ESTAB      0      0      192.168.18.90:52226              192.168.18.90:6379                users:(("redis-sentinel",pid=7890,fd=12))
ESTAB      0      0      192.168.18.90:6379               192.168.18.90:52228               users:(("redis-server",pid=7748,fd=13))
ESTAB      0      0      192.168.18.90:34378              192.168.18.100:6379                users:(("redis-server",pid=7748,fd=8))
ESTAB      0      0      192.168.18.90:57876              192.168.18.109:6379                users:(("redis-sentinel",pid=7890,fd=10))
ESTAB      0      0      192.168.18.90:6379               192.168.18.109:60448               users:(("redis-server",pid=7748,fd=10))
LISTEN     0      128         :::26379                   :::*                   users:(("redis-sentinel",pid=7890,fd=6))

主从查看哨兵

主192.168.18.100

[root@localhost redis-5.0.7]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.18.100:6379,slaves=2,sentinels=3

从192.168.18.109

127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.18.100:6379,slaves=2,sentinels=3

从192.168.18.90

[root@localhost redis-5.0.7]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.18.100:6379,slaves=2,sentinels=3

验证哨兵模式功能:

在从192.168.18.90上开启日志实时查看

[root@localhost redis-5.0.7]# tail -f /var/log/sentinel.log
7890:X 12 Dec 2021 13:44:06.965 # Configuration loaded
7890:X 12 Dec 2021 13:44:06.965 * Increased maximum number of open files to 10032 (it was originally set to 1024).
7890:X 12 Dec 2021 13:44:06.966 * Running mode=sentinel, port=26379.
7890:X 12 Dec 2021 13:44:06.966 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

主服务关闭服务192.168.18.100

[root@localhost redis-5.0.7]# /etc/init.d/redis_6379 stop
Stopping ...
Redis stopped

在开启主服务

[root@localhost redis-5.0.7]# /etc/init.d/redis_6379 start
Starting Redis server...

查看从节点日志

2.168.18.100 6379
7890:X 12 Dec 2021 13:48:35.997 # +switch-master mymaster 192.168.18.100 6379 192.168.18.90 6379
7890:X 12 Dec 2021 13:48:35.997 * +slave slave 192.168.18.109:6379 192.168.18.109 6379 @ mymaster 192.168.18.90 6379
7890:X 12 Dec 2021 13:48:35.997 * +slave slave 192.168.18.100:6379 192.168.18.100 6379 @ mymaster 192.168.18.90 6379
7890:X 12 Dec 2021 13:49:07.691 * +convert-to-slave slave 192.168.18.100:6379 192.168.18.100 6379 @ mymaster 192.168.18.90 6379   ###master已经改变
[root@localhost redis-5.0.7]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.18.90:6379,slaves=2,sentinels=3

也可以在配置文件中查看  

[root@localhost redis-5.0.7]# vim sentinel.conf
121 sentinel monitor mymaster 192.168.18.90 6379 2  ##master节点变更192.168.18.90

注:原master节点出现故障,会有slaves节点顶替成为新的master。原master节点恢复也不会抢占成为master。

四,Redis集群

1,Redis集群基础

集群,即Redis Cluster,是Redis 3.0开始引入的分布式存储方案。

集群由多个节点(Node)组成,Redis的数据分布在这些节点中。集群中的节点分为主节点和从节点:只有主节点负责读写请求和集群信息的维护;从节点只进行主节点数据和状态信息的复制。

Redis集群的作用

(1)数据分区:数据分区(或称数据分片)是集群最核心的功能。集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。Redis单机内存大小受限问题,在介绍持久化和主从复制时都有提及:例如,如果单机内存太大,bgsave和bgrewriteaof 的:保存操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出。

(2)高可用:集群支持主从复制和主节点的自动故障转移〈与哨兵类似)﹔当任一节点发生故障时,集群仍然可以对外提供服务。

Redis集群的数据分片:

Redis集群引入了哈希槽的概念

Redis集群有16384个哈希槽(编号0-16383)集群的每个节点负责部分哈希槽

每个Key通过CRc16校验后对16384取余来决定放置哪个哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作

#以3个节点组成的集群为例:

节点A包含0到5460号哈希槽

节点B包含5461到10922号哈希槽

节点C包含10923到16383号哈希槽

Redis集群的主从复制模型

集群中具有A、B、C三个节点,如果节点B失败了,整个集群就会因缺少5461-10922这个范围的槽而不可以用。

为每个节点添加一个从节点A1、B1、C1整个集群便有三个Master节点和三个slave 节点组成,在节点B失败后,集群选举:一位为主节点继续服务。当B和B1都失败后,集群将不可用。

2,Redis Cluster的工作原理

在哨兵sentinel机制中,可以解决redis高可用问题,即当master故障后可以自动将slave提升为

master,从而可以保证redis服务的正常使用,但是无法解决redis单机写入的瓶颈问题,即单机redis写

入性能受限于单机的内存大小、并发数量、网卡速率等因素。

Redis集群的特点:

  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)取余16384之后的值,决定将key写入哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈。

3,Redis集群的基本架构

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

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

Redis 群集详解_第3张图片 

Redis cluster 主从架构

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

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

Redis 群集详解_第4张图片 

4,搭建Redis集群

环境设定此处以多实例为例来做Redis集群

一台已经安装Redis的主机创建6台多实例,关闭防火墙和selinux

创建文件位置,复制配置文件

[root@localhost opt]# cd /etc/redis/
[root@localhost redis]# mkdir -p redis-cluster/redis600{1..6}  ##创建文件位置
[root@localhost redis]# ls
6379.conf  redis-cluster
[root@localhost redis]# tree redis-cluster
redis-cluster
├── redis6001
├── redis6002
├── redis6003
├── redis6004
├── redis6005
└── redis6006
[root@localhost redis]# cd /opt/redis-5.0.7/
[root@localhost redis-5.0.7]# for i in {1..6}; do cp redis.conf src/redis-cli 
src/redis-server /etc/redis/redis-cluster/redis600$i; done
###利用脚本将配置文件分别拷贝
[root@localhost redis-5.0.7]# tree /etc/redis/redis-cluster/  ##查看
/etc/redis/redis-cluster/
├── 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

修改配置文件

[root@localhost redis-5.0.7]# cd /etc/redis/redis-cluster/redis6001
[root@localhost redis6001]# vim redis.conf
 69 #bind 127.0.0.1   ##69行注释掉监听所有多有端口
  70 
...........
88 protected-mode no  ##88行关闭保护模式
  89 
..........
 92 port 6001    ##92行修改端口号
  93 
..........
136 daemonize yes  ##136行守护进程后台运行打开
 137 
.......
699 appendonly yes  ##开启AOF持久化
 700 
..........
832  cluster-enabled yes  ##832行开启集群
 833 
......
840  cluster-config-file nodes-6001.conf  ###使用的配置文件
 841 
..........
846  cluster-node-timeout 15000   ###开启超时时间
 847 

将配置文件拷贝到其他实例位置

[root@localhost redis6001]# \cp -f redis.conf ../redis6002
[root@localhost redis6001]# \cp -f redis.conf ../redis6003
[root@localhost redis6001]# \cp -f redis.conf ../redis6004
[root@localhost redis6001]# \cp -f redis.conf ../redis6005
[root@localhost redis6001]# \cp -f redis.conf ../redis6006

修改端口号

[root@localhost redis6001]# vim ../redis6002/redis.conf 
[root@localhost redis6001]# vim ../redis6003/redis.conf 
[root@localhost redis6001]# vim ../redis6004/redis.conf 
[root@localhost redis6001]# vim ../redis6005/redis.conf 
[root@localhost redis6001]# vim ../redis6006/redis.conf 

使用命令:
:%s/6001/6002/g   ##更改端口号

使用脚本开启服务

[root@localhost redis6001]# for i in {1..6}
> do
> cd /etc/redis/redis-cluster/redis600$i
> ./redis-server redis.conf 
> done
84754:C 12 Dec 2021 22:07:39.538 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
84754:C 12 Dec 2021 22:07:39.538 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=84754, just started
84754:C 12 Dec 2021 22:07:39.538 # Configuration loaded
84756:C 12 Dec 2021 22:07:39.541 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
84756:C 12 Dec 2021 22:07:39.541 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=84756, just started
84756:C 12 Dec 2021 22:07:39.541 # Configuration loaded
84758:C 12 Dec 2021 22:07:39.545 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
84758:C 12 Dec 2021 22:07:39.545 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=84758, just started
84758:C 12 Dec 2021 22:07:39.545 # Configuration loaded
84766:C 12 Dec 2021 22:07:39.548 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
84766:C 12 Dec 2021 22:07:39.548 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=84766, just started
84766:C 12 Dec 2021 22:07:39.548 # Configuration loaded
84770:C 12 Dec 2021 22:07:39.551 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
84770:C 12 Dec 2021 22:07:39.551 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=84770, just started
84770:C 12 Dec 2021 22:07:39.551 # Configuration loaded
84776:C 12 Dec 2021 22:07:39.554 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
84776:C 12 Dec 2021 22:07:39.554 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=84776, just started
84776:C 12 Dec 2021 22:07:39.554 # Configuration loaded

查看端口是否开启

[root@localhost redis6006]# ps -elf |grep redis
4 S root      59866      1  0  80   0 - 38461 ep_pol 13:42 ?        00:00:59redis-sentinel *:26379 [sentinel]
5 S root      59936      1  0  80   0 - 40125 ep_pol 13:48 ?        00:00:47 /usr/local/redis/bin/redis-server 0.0.0.0:6379
5 S root      84755      1  0  80   0 - 38462 ep_pol 22:07 ?        00:00:00 ./redis-server *:6001 [cluster]
5 S root      84757      1  0  80   0 - 38462 ep_pol 22:07 ?        00:00:00 ./redis-server *:6002 [cluster]
5 S root      84765      1  0  80   0 - 38462 ep_pol 22:07 ?        00:00:00 ./redis-server *:6003 [cluster]
5 S root      84767      1  0  80   0 - 38462 ep_pol 22:07 ?        00:00:00 ./redis-server *:6004 [cluster]
5 S root      84772      1  0  80   0 - 38462 ep_pol 22:07 ?        00:00:00 ./redis-server *:6005 [cluster]
5 S root      84777      1  0  80   0 - 38462 ep_pol 22:07 ?        00:00:00 ./redis-server *:6006 [cluster]
0 S root      84793  84534  0  80   0 - 28170 pipe_w 22:07 pts/0    00:00:00 grep --color=auto redis

启动集群(会自动分配主从)

[root@localhost 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
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:6005 to 127.0.0.1:6001
Adding replica 127.0.0.1:6006 to 127.0.0.1:6002
Adding replica 127.0.0.1:6004 to 127.0.0.1:6003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: dacc140adfe8b43b947c84e04c18a53e12ee6ce2 127.0.0.1:6001
   slots:[0-5460] (5461 slots) master
M: 38c3cb816cc20bb8015e56867f5e892f8188221e 127.0.0.1:6002
   slots:[5461-10922] (5462 slots) master
M: e6d004d894faec0adc603235d60c33fae7bd5987 127.0.0.1:6003
   slots:[10923-16383] (5461 slots) master
S: eac8c84c70a6547fe8ba0ac6a1c093b063856636 127.0.0.1:6004
   replicates dacc140adfe8b43b947c84e04c18a53e12ee6ce2
S: 3dd4777d963e7af793a714ae7c199f027ffe9bc4 127.0.0.1:6005
   replicates 38c3cb816cc20bb8015e56867f5e892f8188221e
S: 9e42c404cb4cf96d5fe447f21c541edc1972cc8f 127.0.0.1:6006
   replicates e6d004d894faec0adc603235d60c33fae7bd5987
Can I set the above configuration? (type 'yes' to accept): yes  ##输入yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.....
>>> Performing Cluster Check (using node 127.0.0.1:6001)
M: dacc140adfe8b43b947c84e04c18a53e12ee6ce2 127.0.0.1:6001
   slots:[0-5460] (5461 slots) master       ##分配为master
   1 additional replica(s)
S: 9e42c404cb4cf96d5fe447f21c541edc1972cc8f 127.0.0.1:6006
   slots: (0 slots) slave                   ##分配为slave
   replicates e6d004d894faec0adc603235d60c33fae7bd5987
M: e6d004d894faec0adc603235d60c33fae7bd5987 127.0.0.1:6003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: 38c3cb816cc20bb8015e56867f5e892f8188221e 127.0.0.1:6002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 3dd4777d963e7af793a714ae7c199f027ffe9bc4 127.0.0.1:6005
   slots: (0 slots) slave
   replicates 38c3cb816cc20bb8015e56867f5e892f8188221e
S: eac8c84c70a6547fe8ba0ac6a1c093b063856636 127.0.0.1:6004
   slots: (0 slots) slave
   replicates dacc140adfe8b43b947c84e04c18a53e12ee6ce2
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

测试:

[root@localhost redis6006]# redis-cli -p 6001 -c   ##允许集群之间跳转
127.0.0.1:6001> CLUSTER SLOTS  ##查看哈希槽分配
1) 1) (integer) 10923
   2) (integer) 16383  ##哈希槽范围
   3) 1) "127.0.0.1"
      2) (integer) 6003
      3) "e6d004d894faec0adc603235d60c33fae7bd5987"
   4) 1) "127.0.0.1"
      2) (integer) 6006
      3) "9e42c404cb4cf96d5fe447f21c541edc1972cc8f"
2) 1) (integer) 5461
   2) (integer) 10922  ##哈希槽范围
   3) 1) "127.0.0.1"
      2) (integer) 6002
      3) "38c3cb816cc20bb8015e56867f5e892f8188221e"
   4) 1) "127.0.0.1"
      2) (integer) 6005
      3) "3dd4777d963e7af793a714ae7c199f027ffe9bc4"
3) 1) (integer) 0
   2) (integer) 5460   ##哈希槽范围
   3) 1) "127.0.0.1"
      2) (integer) 6001
      3) "dacc140adfe8b43b947c84e04c18a53e12ee6ce2"
   4) 1) "127.0.0.1"
      2) (integer) 6004
      3) "eac8c84c70a6547fe8ba0ac6a1c093b063856636"

创建数据测试

127.0.0.1:6001> set key1 name   ##创建数据
-> Redirected to slot [9189] located at 127.0.0.1:6002  ##分配到6002主机哈希槽值9189
OK
127.0.0.1:6002> CLUSTER KEYSLOT key1  ###自动跳转到6002上,查看哈希值
(integer) 9189
127.0.0.1:6002> get key1
"name"
127.0.0.1:6002> quit
[root@localhost redis6006]# redis-cli -p 6002  ##进入6002查看
127.0.0.1:6002> get key1  ##查看数据有数据
"name"

你可能感兴趣的:(redis,缓存,数据库,分布式,运维)