博文大纲:
一、Redis群集原理
二、Redis群集架构细节
三、redis-cluster选举
四、部署Redis群集环境

关于Redis的性能调优参数的说明,可以参考博文:centos 7之Redis数据库详解及参数调优
一、Redis群集原理:

1)Redis集群架构:

  • Redis Cluster采用虚拟槽分区,将所有的数据根据算法映射到0~16384整数槽内
  • Redis Cluster是一个无中心的结构
  • 每个节点都保存数据和整个集群的状态
    2)集群角色
  • Master:Master之间分配slots
  • Slave:Slave向它指定的Master同步数据
    3)集群节点使用的TCP端口
  • 6379端口用于客户端的连接
  • 16379端口用于群集总线

Redis3.0版本以上开始支持群集,采用的是hash slot(哈希槽),可以将多个Redis实例整合在一起,形成一个群集,也就是将数据分散到群集的多台服务器上。

Redis cluster(Redis 群集)是一个无中心的结构,如下图所示,每个节点都会保存数据和整个群集的状态。每个节点都会保存其他节点的信息,知道其他节点所负责的槽,并且会与其他节点定时发送心跳信息,能够及时感知群集中异常的节点。

基于centos 7的Redis群集原理及配置

当客户端向群集中任一节点发送与数据库键有关的命令时,接受命令的节点会计算出命令要处理的数据属于哪个槽,并检查这个槽是否指派给了自己,如果键所在的槽正好指派给了当前节点,那么节点直接执这个命令;如果键值所在的槽并没有指派给当前节点,那么节点会向客户端返回一个MOVED错误,指引客户端转向(redirect)正确的节点,并再次发送之前想要执行的命令。

群集角色有master和slave。master之间分配slots,一共16384个slot。slave向它指定的master同步数据,实现备份。当其中一个master无法提供服务时,该master的slave将提升为master,以保证群集间slot的完整性。当其中的某一个master和它的slave都失效,导致了slot不完整,群集失效,这时就需要运维人员去处理了。

群集搭建好后,群集中的每个节点都会定期地向其他节点发送PING消息,如果接收PING消息的节点没有在规定的时间内返回PONG消息,那么发送PING消息的节点就会将其标记为疑似下线(PFAIL)。各个节点会通过互相发送消息的方式来交换群集中各个节点的状态信息。如果已经在一个群集里面,半数以上的主节点都将某个主节点x报告为疑似下线,那么这个主节点x将被标记为已下线(FAIL),同时会向群集广播一条关于主节点x的FAIL消息,所有收到这条FAIL消息的节点都会立即将主节点x标记为已下线。

当需要减少或者增加群集中的服务器时,我们需要将已经指派给某个节点(源节点)的槽改为指派给另一个节点(目标节点),并且将相关槽所包含的键值对从源节点移动到目标节点。

Redis群集的重新分片操作时由Redis的群集管理软件redis-trib负责执行的,不支持自动分片,而且需要自己计算从哪些节点迁移多少Slot。在重新分片的过程中,群集无需下线,并且源节点和目标节点都可以继续处理命令请求。

二、Redis群集架构细节:

1、所有的Redis节点彼此互联(PING-PONG机制)内部使用二进制协议优先传输速度和带宽。

2、节点的失效(fail)在群集中超过半数的主(master)节点检测失效时才会生效。

3、客户端与redis节点直连,不需要中间代理(proxy)层,客户端不需要连接群集所有节点,连接群集中任何一个可用节点即可。

4、redis-cluster把所有的物理节点映射到 [ 0-1638 ] slot 上,cluster负责维护node< - >slot< - > key。

三、redis-cluster选举:

选举过程是群集中所有master参与,如果半数以上master节点与当前master节点通信超时(cluster-node-timeout),认为当前master节点挂掉。以下两种情况为整个群集不可用(cluster_state:fail),当群集不可用时,所有对群集的操作都不可用,收到((error)CLUSTERDOWN Thecluster is down)错误:

错误1:如果群集中任意master挂掉,且当前master没有slave,则群集进入fail状态,也可以理解成群集的slot映射 [ 0-16383 ]不完整时进入fail状态。

错误2:如果群集中超过半数的master挂掉,无论是否有slave,群集都进入fail状态。

默认情况下,每个群集的节点都是用两个TCP端口,一个是6379,一个是16379;6379服务于客户端的连接,16379用于群集总线,就是使用二进制协议的节点到节点通信通道。节点使用群集总线进行故障检测、配置更新、故障转移授权等。

四、部署Redis群集环境:

1、环境准备:

1)六台服务器,三台为master、三台为slave,我这里均为centos 7,IP地址依次为192.168.1.1--6(参与群集的服务器数量最好为偶数,每个master会自动对应一个slave,若为奇数,群集无法实现冗余,因为必定有一个master没有对应的slave,一旦这个master宕机,整个群集就会丢失一部分数据);
2)准备所需源码包:下载链接,提取码:4kky,配置本地yum,需要系统映像安装ruby的运行环境。
3)自行配置网络及防火墙,放行TCP的6379和16379这两个端口的流量,我这里直接关闭了防火墙。
4)所有redis服务器必须保证无任何数据,最好是全新安装的,因为如果有数据存在,在后面进行群集时会报错,关于错误如何解决,我没有深究。

2、开始部署:

①192.168.1.1:

[root@localhost ~]# mount /root/redis-5.0.iso /media 
mount: /dev/loop1 写保护,将以只读方式挂载
[root@localhost ~]# cd /media
[root@localhost media]# cp * /usr/src/           #将iso中的文件都复制到指定目录
[root@localhost media]# cd /usr/src
[root@localhost src]# ls               #查看相关包有没有复制过来
debug  kernels  redis-3.2.0.gem  redis-5.0.5.tar.gz
[root@localhost src]# tar zxf redis-5.0.5.tar.gz       #解包
[root@localhost src]# cd redis-5.0.5/       #切换至解压后的目录
[root@localhost redis-5.0.5]# make && make install      #编译安装
[root@localhost redis-5.0.5]# cd utils/        #切换至子目录
[root@localhost utils]# ./install_server.sh       #生成服务相关配置文件
#接下来是在指定相关配置文件的存放位置,直接一路按回车键即可。
[root@localhost utils]# cd /etc/init.d/      #优化redis控制启停方式
[root@localhost init.d]# mv redis_6379 redis     
[root@localhost init.d]# chkconfig --add redis          #将redis添加为系统服务
[root@localhost init.d]# systemctl restart redis          #重启服务,以测试是否生效
[root@localhost init.d]# systemctl restart redis
[root@localhost init.d]# vim /etc/redis/6379.conf    #编辑主配置文件,改动以下几个配置项
bind 127.0.0.1 192.168.1.1   #添加本机IP。
appendonly yes  #改为“yes”,以便在每次更新操作后进行日志记录,进行数据同步写入
daemonize yes       #查看是否为“yes”
logfile /var/log/redis_6379.log           #指定日志文件位置,可以保持默认
cluster-enabled yes            #启动群集
cluster-config-file nodes-6379.conf          #群集配置文件
cluster-node-timeout 15000          #群集节点超时时间,单位为毫秒
cluster-require-full-coverage no          #将默认的“yes”改为“no”
port 6379                  #默认监听的端口号
[root@localhost init.d]# systemctl restart redis        #重启服务,使配置生效
[root@localhost init.d]# netstat -anpt | grep redis       #只要6379和16379在监听,就OK了。
tcp        0      0 192.168.1.1:6379        0.0.0.0:*       LISTEN      7139/redis-server 1 
tcp        0      0 192.168.1.1:16379       0.0.0.0:*       LISTEN      7139/redis-server 1 
[root@localhost ~]# yum -y install ruby rubygems            #安装ruby的运行环境及客户端
[root@localhost ~]# cd /usr/src/
[root@localhost src]# ls             #切换至包含redis-3.2.0.gem的目录下
debug  kernels  redis-3.2.0.gem  redis-5.0.5  redis-5.0.5.tar.gz
[root@localhost src]# gem install redis --version 3.2.0      #执行gem命令
Successfully installed redis-3.2.0
Parsing documentation for redis-3.2.0
Installing ri documentation for redis-3.2.0
1 gem installed

②192.168.1.2:

[root@localhost ~]# scp root@192.168.1.1:/usr/src/redis-5.0.5.tar.gz /usr/src
#将主机1.1的redis源码包复制过来
The authenticity of host  192.168.1.1 (192.168.1.1) can t be established.
ECDSA key fingerprint is SHA256:3U5q5gBxEOkHLFZZueGnEXGV/LZA9M4+1rM1lLvkD1g.
ECDSA key fingerprint is MD5:ad:a1:9b:f7:e3:41:bf:5f:da:cd:5e:3f:74:e0:8a:b9.
Are you sure you want to continue connecting (yes/no)? yes #输入yes
Warning: Permanently added '192.168.1.1' (ECDSA) to the list of known hosts.
root@192.168.1.1 s password:         #输入主机1.1的用户密码
redis-5.0.5.tar.gz                              100% 1929KB  68.5MB/s   00:00   
[root@localhost ~]# cd /usr/src                 
[root@localhost src]# tar zxf redis-5.0.5.tar.gz         #解包
[root@localhost src]# cd redis-5.0.5/          #进入解压后的目录
[root@localhost redis-5.0.5]# make && make install       #编译安装
[root@localhost redis-5.0.5]# cd utils/        #切换至子目录
[root@localhost utils]# ./install_server.sh       #生成服务相关配置文件
#接下来是在指定相关配置文件的存放位置,直接一路按回车键即可。
[root@localhost utils]# cd /etc/init.d/      #优化redis控制启停方式
[root@localhost init.d]# mv redis_6379 redis     
[root@localhost init.d]# chkconfig --add redis          #将redis添加为系统服务
[root@localhost init.d]# systemctl restart redis          #重启服务,以测试是否生效
[root@localhost init.d]# scp root@192.168.1.1:/etc/redis/6379.conf /etc/redis/ 
#将主机1.1的redis配置文件复制过来
root@192.168.1.1 s password: 
6379.conf                                       100%   60KB  34.5MB/s   00:00    
[root@localhost init.d]# scp root@192.168.1.1:/etc/redis/6379.conf /etc/redis/    #编辑配置redis配置文件
bind 127.0.0.1 192.168.1.2         #将原有的1.1改为1.2即可
[root@localhost init.d]# systemctl restart redis          #重启服务,使配置文件生效
[root@localhost init.d]# netstat -natp | grep redis      #查看6379和16379是否在监听
tcp        0      0 192.168.1.2:6379        0.0.0.0:*       LISTEN      7479/redis-server 1 
tcp        0      0 192.168.1.2:16379       0.0.0.0:*     LISTEN      7479/redis-server 1 

现在192.168.1.2也配置完成了,现在去192.168.1.3-6重复执行一下192.168.1.2这台主机的配置即可。需要注意的是,更改从1.1复制过来的主配置文件时,将对应的IP地址换成本机的IP地址即可,其他配置命令都一样。

剩下的所有服务器都配置完成后,回过头接着配置主机192.168.1.1:

[root@localhost src]# redis-cli --cluster create 192.168.1.1:6379 \
192.168.1.2:6379  \
192.168.1.3:6379  \
192.168.1.4:6379  \
192.168.1.5:6379  \
192.168.1.6:6379  \
--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 192.168.1.5:6379 to 192.168.1.1:6379
Adding replica 192.168.1.6:6379 to 192.168.1.2:6379
Adding replica 192.168.1.4:6379 to 192.168.1.3:6379
M: 758dc679fc1d46df195b4c16abcfde1d743b8008 192.168.1.1:6379
   slots:[0-5460] (5461 slots) master
M: 4b1d119d0a8179afcc10bf5891e5c04e6a7054ba 192.168.1.2:6379
   slots:[5461-10922] (5462 slots) master
M: 58d342b59e98c9f9f469332b08c36b6ddd456bf6 192.168.1.3:6379
   slots:[10923-16383] (5461 slots) master
S: bb95619aff3d613137733eeb55ff2d303a8720a1 192.168.1.4:6379
   replicates 58d342b59e98c9f9f469332b08c36b6ddd456bf6
S: 22d77a79272847f29e5db381b98ef6ccc4a169a7 192.168.1.5:6379
   replicates 758dc679fc1d46df195b4c16abcfde1d743b8008
S: ebc138bbea070c6496ae266b1a84936754603ad2 192.168.1.6:6379
   replicates 4b1d119d0a8179afcc10bf5891e5c04e6a7054ba
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 192.168.1.1:6379)
M: 758dc679fc1d46df195b4c16abcfde1d743b8008 192.168.1.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: ebc138bbea070c6496ae266b1a84936754603ad2 192.168.1.6:6379
   slots: (0 slots) slave
   replicates 4b1d119d0a8179afcc10bf5891e5c04e6a7054ba
M: 4b1d119d0a8179afcc10bf5891e5c04e6a7054ba 192.168.1.2:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 58d342b59e98c9f9f469332b08c36b6ddd456bf6 192.168.1.3:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: bb95619aff3d613137733eeb55ff2d303a8720a1 192.168.1.4:6379
   slots: (0 slots) slave
   replicates 58d342b59e98c9f9f469332b08c36b6ddd456bf6
S: 22d77a79272847f29e5db381b98ef6ccc4a169a7 192.168.1.5:6379
   slots: (0 slots) slave
   replicates 758dc679fc1d46df195b4c16abcfde1d743b8008
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost src]# redis-cli --cluster check 192.168.1.1:6379   
#查看群集状态
192.168.1.1:6379 (758dc679...) -> 0 keys | 5461 slots | 1 slaves.
192.168.1.2:6379 (4b1d119d...) -> 0 keys | 5462 slots | 1 slaves.
192.168.1.3:6379 (58d342b5...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.1.1:6379)
M: 758dc679fc1d46df195b4c16abcfde1d743b8008 192.168.1.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: ebc138bbea070c6496ae266b1a84936754603ad2 192.168.1.6:6379
   slots: (0 slots) slave
   replicates 4b1d119d0a8179afcc10bf5891e5c04e6a7054ba
M: 4b1d119d0a8179afcc10bf5891e5c04e6a7054ba 192.168.1.2:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 58d342b59e98c9f9f469332b08c36b6ddd456bf6 192.168.1.3:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: bb95619aff3d613137733eeb55ff2d303a8720a1 192.168.1.4:6379
   slots: (0 slots) slave
   replicates 58d342b59e98c9f9f469332b08c36b6ddd456bf6
S: 22d77a79272847f29e5db381b98ef6ccc4a169a7 192.168.1.5:6379
   slots: (0 slots) slave
   replicates 758dc679fc1d46df195b4c16abcfde1d743b8008
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost src]# redis-cli -h 192.168.1.1 -p 6379 -c          #登录到群集需加“-c”选项
192.168.1.1:6379> set lv 11         #插入数据
OK
192.168.1.1:6379> get lv         
"11"
192.168.1.1:6379> exit
[root@localhost src]# redis-cli -h 192.168.1.3 -p 6379 -c          #登录到其他master
192.168.1.3:6379> get lv           #查看在1.1插入的数据,照样可以查询到,说明群集生效
-> Redirected to slot [4118] located at 192.168.1.1:6379
"11"

redis-3.x.x和redis-5.x.x创建群集的区别:

使用命令不一样,redis-3.x.x使用redis-trib.rb命令,语法如下:

[root@localhost ~]#redis-trib.rb create --replicas 1 192.168.1.1:6379 ..192.168.1.6:6379
#redis-3.x.x创建群集。
[root@localhost src]# redis-trib.rb check 192.168.1.1:6379
#查看群集状态
# redis-trib.rb不可以直接使用,需要执行以下操作才可直接使用
[root@localhost src]# cd /usr/src/redis-5.0.5/src/           
[root@localhost src]# cp redis-trib.rb /usr/local/bin/  
#将该脚本复制到本地../bin下,以便直接使用。若不然,需要在目录下使用“./”执行该文件