一、Redis-Cluster集群概述
(1)Cluster集群概述
在Redis5.0版本发布时,推出了各种新特性,其中一点就是放弃Ruby的集群方式,改为使用C语言编写的redis-cli的方式,使集群的构建方式的复杂度降低,在Redis3.0以前的版本要实现集群一般都是借助哨兵sentinel工具来监控Master节点的状态,如果Master出现故障则会进行故障转移,主从切换,选择一台数据较完整的Slave来做Master,哨兵的配置略微复杂,并且性能和高可用方面表现一般,特别是在主从进行切换时,会有访问瞬断的情况,而且哨兵模式只有一个Master对外提供写服务,没办法支持很高的并发,并且单个主节点的内存也不能设置的太大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率
哨兵模式的缺陷:
- 哨兵的配置略微复杂,并且性能和高可用方面表现一般,特别是在主从进行切换时,会有访问瞬断的情况
- 哨兵模式只有一个Master对外提供写服务,没办法支持很高的并发
- 单个主节点的内存也不能设置的太大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率
- 之前没有Cluster之前使用的是Codis(豌豆荚)+redis
(2)Redis数据分区
Redis-Cluster采用虚拟槽进行分区,所有的键根据hash哈希函数映射到0—16383个整数槽内,总共有16384个整数槽
计算公式为:Slot=CRC16(key)&16384
每个节点负责维护一部分虚拟槽以及虚拟槽所映射的键值数据
Redis集群中的每个节点都负责虚拟槽的子集,例如:
一个集群有三个节点,那么
节点A包含从0到5500的散列槽。
节点B包含从5501到11000的散列槽。
节点C包含从11001到16383的散列槽。
当用户创建键时,比如set aaa bbb,Redis会根据上面的算法计算出这个键的值,这个值不超过16383,假如说算出的值为5700,那么这个键就会保存在节点B中。当用户访问某个键时,这个键肯定也会有一个值,例如3500,那么就会从节点A上面去读取。但是用户连接的数据库时节点A,但是访问的数据在节点B怎么办,那么节点A会直接转发请求到节点B上去读取数据
(3)Redis-Cluster集群搭建
Redis集群至少需要3个节点,因为Cluster集群的投票容错机制要求至少半数节点认为某个节点挂了,该节点才算是挂了,当只有两个节点时是无法进行投票的,所以说至少需要3个节点
要保证集群的高可用,需要每个Master主节点都有一个Slave从节点,也就是用来备份的节点,在这个基础上,Redis-Cluster至少需要6台服务器,最终组成的集群架构是三主三从
(4)集群选举原理分析(ping-pong机制)
选举流程:(PING-PONG机制)
当Slave发现自己的Master变成Fail(失败)状态时,会尝试发起选举,以成为新的Master,由于挂掉的Master可能会有多个Slave,从而会存在多个Slave去竞争Master节点的过程:
- Slave发现自己的Master变成Fail(失败)状态
- Slave会将自己记录的集群currentEpoch(选举轮次标记)加1,并广播信息到集群中的其他节点
- 集群中的其他节点接收到Slave广播的消息,只有Master主节点会进行响应,判断请求者的合法性(就是确认选举Slave的Master确实是挂了),并且发送结果
- 尝试选举Master的Slave会收集其他节点的Master返回的结果,收到超过半数节点的Master的同意后,这个Slave就会变成新的Master
- 广播Pong消息通知其他集群的节点
这是成功选举的过程,前四步就是Ping的机制,而第五步就是Pong的机制,但是如果选举不成功怎么办:
如果这次Slave的选举没有成功,例如,三个节点组成的集群,三个节点分别是节点A、B、C,每个节点都有两个从服务器,当A节点的Master挂了之后,A节点的两个从服务器都会进行选举,最后的结果是B投给了第一个从服务器,C投给了第二个从服务器,这个时候会发生第二次选举,选举轮次加1继续上面的选举流程,直到选举成功
当集群中其中一台主机挂掉后,是不会影响客户端的查询和写入的,但是不能挂掉多于集群半数的主机数量
(5)跳转重定位
当客户端想获取指定的A键,但是它访问的节点中没有A键,被访问的节点会发现客户端想要获取的键自己这里没有,这个时候被访问的节点会向客户端发送一个特殊的跳转指令,这个指令会携带带有A键的节点的地址,告诉客户端去连接这个节点获取A键,客户端收到跳转指令后除了会跳转到正确的节点上去操作外,还会同步更新自己的槽位映射表缓存,后续的所有键都会使用新的槽位映射表,下次访问A键的时候会直接访问正确的节点
二、部署Redis-Cluster集群
(1)实验环境
此次实验使用的Redis版本均为Redis-5.0.4版本,三个服务器上部署双实例
系统 | 主机名 | ip | 端口 |
Centos7.4 | Centos1 | 192.168.100.202 | 6379 |
Centos7.4 | Centos1 | 192.168.100.202 | 6380 |
Centos7.4 | Centos2 | 192.168.100.203 | 6379 |
Centos7.4 | Centos2 | 192.168.100.203 | 6380 |
Centos7.4 | Centos3 | 192.168.100.204 | 6379 |
Centos7.4 | Centos3 | 192.168.100.204 | 6380 |
(2)实验步骤
-配置hosts文件
******(1)修改centos1,并编写hosts文件 [root@Centos7 ~]# hostnamectl set-hostname centos1 [root@Centos7 ~]# su [root@centos1 ~]# echo ""' 192.168.100.202 centos1 192.168.100.203 centos2 192.168.100.204 centos3 ''' >> /etc/hosts [root@centos1 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.100.202 centos1 192.168.100.203 centos2 192.168.100.204 centos3 [root@centos1 ~]# scp /etc/hosts root@192.168.100.203:/etc/hosts [root@centos1 ~]# scp /etc/hosts root@192.168.100.204:/etc/hosts ******(2)修改centos2 [root@Centos7 ~]# hostnamectl set-hostname centos2 [root@Centos7 ~]# su [root@centos2 ~]# ******(3)修改centos3 [root@Centos7 ~]# hostnamectl set-hostname centos3 [root@Centos7 ~]# su [root@centos3 ~]#
-在centos1上,上传redis软件包,并且编译
[root@centos1 ~]# ll 总用量 1928 -rw-------. 1 root root 1264 1月 12 18:27 anaconda-ks.cfg -rw-r--r-- 1 root root 1966337 6月 9 23:49 redis-5.0.4.tar.gz [root@centos1 ~]# tar xf redis-5.0.4.tar.gz [root@centos1 ~]# cd redis-5.0.4 [root@centos1 redis-5.0.4]# make [root@centos1 redis-5.0.4]# cd
-centos1的配置
******(1)创建工作目录 [root@centos1 ~]# mkdir -p /etc/redis/cluster/{6379,6380} [root@centos1 ~]# ll /etc/redis/cluster/ 总用量 0 drwxr-xr-x 2 root root 6 6月 9 23:47 6379 drwxr-xr-x 2 root root 6 6月 9 23:47 6380 ******(2)创建数据存储目录 [root@centos1 ~]# mkdir -p /data/redis/data/{6379,6380} [root@centos1 ~]# ll /data/redis/data/ 总用量 0 drwxr-xr-x 2 root root 6 6月 9 23:48 6379 drwxr-xr-x 2 root root 6 6月 9 23:48 6380 ******(3)为centos1部署双实例 [root@centos1 ~]# cp redis-5.0.4/redis.conf /etc/redis/cluster/6379/ [root@centos1 ~]# cp redis-5.0.4/redis.conf /etc/redis/cluster/6380/ ******(4)修改配置文件 [root@centos1 ~]# vim /etc/redis/cluster/6379/redis.conf 。。。。。。 68 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 69 bind 192.168.100.202 #指定此实例的ip 70 。。。。。。 88 protected-mode no #关闭安全模式 89 90 # Accept connections on the specified port, default is 6379 (IANA #815344). 91 # If port 0 is specified Redis will not listen on a TCP socket. 92 port 6379 #指定此实例的端口 93 。。。。。。 135 # Note that Redis will write a pid file in /var/run/redis.pid when daemonized. 136 daemonize yes 137 。。。。。。 170 # output for logging but daemonize, logs will be sent to /dev/null 171 logfile "/var/log/redis/redis_6379.log" #指定日志存放路径 172 。。。。。。 262 # Note that you must specify a directory here, not a file name. 263 dir /data/redis/data/6379 #指定RDB文件存放路径 264 。。。。。。 837 # 838 cluster-enabled yes #去掉注释,开启集群 839 。。。。。。 845 # 846 cluster-config-file nodes-6379.conf 847 。。。。。。 851 # 852 cluster-node-timeout 15000 #请求超时,单位为毫秒,15000为15秒 853 。。。。。。 #保存退出 ———————————————————————————————————————— #可以直接这样,因为配置都相同,只需要修改一下端口号就行 [root@centos1 ~]# cp /etc/redis/cluster/6379/redis.conf /etc/redis/cluster/6380/redis.conf cp:是否覆盖"/etc/redis/cluster/6380/redis.conf"? yes [root@centos1 ~]# sed -i 's/6379/6380/g' /etc/redis/cluster/6380/redis.conf ———————————————————————————————————————— [root@centos1 ~]# vim /etc/redis/cluster/6380/redis.conf 。。。。。。 68 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 69 bind 192.168.100.202 70 。。。。。。 88 protected-mode no 89 90 # Accept connections on the specified port, default is 6379 (IANA #815344). 91 # If port 0 is specified Redis will not listen on a TCP socket. 92 port 6380 #修改端口 93 。。。。。。 135 # Note that Redis will write a pid file in /var/run/redis.pid when daemonized. 136 daemonize yes #放到后台运行 137 。。。。。。 157 # nothing bad happens, the server will start and run normally. 158 pidfile /var/run/redis_6380.pid #修改一下pid文件 159 。。。。。。 170 # output for logging but daemonize, logs will be sent to /dev/null 171 logfile "/var/log/redis/redis_6380.log" #指定日志存放路径 172 。。。。。。 262 # Note that you must specify a directory here, not a file name. 263 dir /data/redis/data/6380 #指定RDB文件存放路径 264 。。。。。。 838 cluster-enabled yes 839 840 # Every cluster node has a cluster configuration file. This file is not 841 # intended to be edited by hand. It is created and updated by Redis nodes. 842 # Every Redis Cluster node requires a different cluster configuration file. 843 # Make sure that instances running in the same system do not have 844 # overlapping cluster configuration file names. 845 # 846 cluster-config-file nodes-6380.conf 847 848 # Cluster node timeout is the amount of milliseconds a node must be unreachable 849 # for it to be considered in failure state. 850 # Most other internal time limits are multiple of the node timeout. 851 # 852 cluster-node-timeout 15000 。。。。。。 #保存退出 [root@centos1 ~]# mkdir -p /usr/local/redis [root@centos1 ~]# mkdir -p /var/log/redis [root@centos1 ~]# cp redis-5.0.4/src/redis-server /usr/local/redis/ [root@centos1 ~]# cp redis-5.0.4/src/redis-cli /usr/local/redis/ [root@centos1 ~]# ln -s /usr/local/redis/* /usr/local/bin/ ******(5)启动两台redis [root@centos1 ~]# redis-server /etc/redis/cluster/6379/redis.conf #指定配置文件启动redis [root@centos1 ~]# redis-server /etc/redis/cluster/6380/redis.conf [root@centos1 ~]# netstat -anpt | grep redis tcp 0 0 192.168.100.202:6379 0.0.0.0:* LISTEN 5231/redis-server 1 tcp 0 0 192.168.100.202:6380 0.0.0.0:* LISTEN 5236/redis-server 1 tcp 0 0 192.168.100.202:16379 0.0.0.0:* LISTEN 5231/redis-server 1 tcp 0 0 192.168.100.202:16380 0.0.0.0:* LISTEN 5236/redis-server 1 [root@centos1 ~]# ps -ef | grep redis #查看进程,发现后面是cluster root 5231 1 0 00:13 ? 00:00:04 redis-server 192.168.100.202:6379 [cluster] root 5236 1 0 00:13 ? 00:00:04 redis-server 192.168.100.202:6380 [cluster] root 19035 1062 0 02:19 pts/0 00:00:00 grep --color=auto redis ******(6)添加开机启动项 [root@centos1 ~]# echo "redis-server /etc/redis/cluster/6379/redis.conf" >> /etc/rc.local [root@centos1 ~]# echo "redis-server /etc/redis/cluster/6380/redis.conf" >> /etc/rc.local ******(7)传输文件到另外两台服务器 [root@centos1 ~]# scp -r /etc/redis/ 192.168.100.203:/etc root@192.168.100.203's password: redis.conf 100% 61KB 2.5MB/s 00:00 redis.conf 100% 61KB 34.3MB/s 00:00 [root@centos1 ~]# scp -r /etc/redis/ 192.168.100.204:/etc root@192.168.100.204's password: redis.conf 100% 61KB 33.3MB/s 00:00 redis.conf 100% 61KB 28.8MB/s 00:00 [root@centos1 ~]# scp -r /usr/local/redis/ 192.168.100.203:/usr/local/ root@192.168.100.203's password: redis-server 100% 7912KB 35.5MB/s 00:00 redis-cli 0% 0 0.0KB/s --:-- ETA^redis-cli 100% 4694KB 34.5MB/s 00:00 [root@centos1 ~]# scp -r /usr/local/redis/ 192.168.100.204:/usr/local/ root@192.168.100.204's password: redis-server 100% 7912KB 44.6MB/s 00:00 redis-cli