一、Redis集群简介
Redis Cluster 是 redis 的分布式解决方案,在 3.0 版本正式推出当遇到单机、内存、并发、流量等瓶颈时,可以采用 Cluster 架构方案达到负载均衡目的。 Redis Cluster 之前的分布式方案有两种: 1)客户端分区方案,优点分区逻辑可控,缺点是需要自己处理数据路由,高可用和故障转移等。 2) 代理方案,优点是简化客户端分布式逻辑和升级维护便利,缺点加重架构部署和性能消耗。 官方提供的 Redis Cluster集群方案,很好的解决了集群方面的问题。
二、数据分布
分布式数据库首先要解决把整个数据库集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整体数据的一个子集,需要关注的是数据分片规则,Redis Cluster采用哈希分片规则,即将插入到Redis数据库的key通过哈希分片,分片到不同的数据节点上,要求足够平均,足够随机,并且所有子集都是Redis集群的一份子,当有一个自己出现问题时,这时整个集群都会存在问题,如图:
说明:针对集群中任意子集出现问题导致整个集群故障问题的解决方法为,需要提前为所有子集设置主从,因此证明Redis集群管理依然依附于主从复制,并且采用交叉主从的形式,保证主节点与从节点,不在一台服务器上,使其具有冗余特性。如图:
三、集群中的哈希槽的概念
1.概念
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value
时,Redis先对key使用crc16算法算出一个结果,然后把结果对16384求余数,
这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,Redis 会根据节点数量大
致均等的将哈希槽映射到不同的节点,形成哈希槽位。而这16384个槽位根据集群节点的数量进行平分。
2.优势
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分哈希槽。虽然槽位的数量是固定16384个,但是根据数据量级的不同,长度也有所不同,因此这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。使用哈希槽的好处就在于可以方便的添加或移除节点,当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点即可;当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点即可;至此我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。但是当有一个槽位出现故障,或者有一个槽位没有平均分配key-value,则导致真个集群故障,无法正常读写
3.注意项
- 哈希槽位一个共又16384个,从0开始16383结束,每一个槽位都有自己的编号;
- 槽最重要的数量,不可多不可少;
- 槽位的编号不必是连续的,可以分散打乱;
- 平均分配到每个槽位的概率是大致一样的;
四、Redis集群搭建部署
环境:
- Redis集群最少三台服务器,每台服务器一主节点、一从节点
- 软件包目录:/server/tools
- 安装目录:/opt/redis_*
- 数据目录:/data/redis_*
- 端口规划:主节点_6380、从节点_6381
- 三台服务器主机名称和IP地址:10.0.0.51:db01、10.0.0.52:db02、10.0.0.53:db03
第一里程:所有主机创建相关规划目录
mkdir -p /server/tools
mkdir -p /data/redis_{6380,6381}
mkdir -p /opt/redis_{6380,6381}/{conf,logs,pid}
第二里程:所有主机安装Redis主节点
yum install gcc -y
make distclean && make
cd /server/tools
wget http://download.redis.io/releases/redis-3.2.9.tar.gz
tar zxf redis-3.2.9.tar.gz -C /opt/
ln -s /opt/redis-3.2.9/ /opt/redis
cd /opt/redis
make && make install
cat >/opt/redis_6380/conf/redis_6380.conf<<EOF
bind 10.0.0.51
port 6380
daemonize yes
pidfile "/opt/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_6380/"
###开启Redis数据库集群功能
cluster-enabled yes
###指定记录集群文件信息文件,存放在指定的数据目录下
cluster-config-file nodes_6380.conf
###设定集群断开连接超时时间,默认毫秒,即主节点超过设定时间,则认为主节点发生故障
cluster-node-timeout 15000
EOF
PS:Redis数据库搭建安装请参考:https://www.jianshu.com/p/204dcfc4d0ab
第三里程:db01从节点配置并启动
cd /opt/
cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.conf
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
第四里程:发送配置文件至其余服务器
rsync -avz /opt/redis_638* db02:/opt/
rsync -avz /opt/redis_638* db03:/opt/
第五里程:db02修改配置文件参数并启动
find /opt/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#52#g"
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
第六里程:db03修改配置文件参数并启动
find /opt/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#51#53#g"
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
第七里程:集群内所有节点相互发现
语句:CLUSTER MEET IP 端口号
redis-cli -h db01 -p 6380 CLUSTER MEET 10.0.0.51 6381
redis-cli -h db01 -p 6380 CLUSTER MEET 10.0.0.52 6380
redis-cli -h db01 -p 6380 CLUSTER MEET 10.0.0.52 6381
redis-cli -h db01 -p 6380 CLUSTER MEET 10.0.0.53 6380
redis-cli -h db01 -p 6380 CLUSTER MEET 10.0.0.53 6381
说明:因为集群特性,在集群内所有节点的信息都是具有同时性的,因此在任意节点上相互发现,即可达到整个集群所有成员相互发现
第八里程:检查节点成员信息,是否发现成功
方法一:
redis-cli -h db01 -p 6380 CLUSTER NODES
方法二:
cat /data/redis_6380/nodes_6380.conf
注意:千万不要修改此文件,此文件为集群再次启动时读取文件,保证集群内所有节点的数据信息都是最新的数据信息,当集群内节点 信息发生变化,如添加节点,节点下线,故障转移等.节点会自动保存集群状态到配置文件. 需要注意的是,Redis 自动维护集群配置文件,不需要手动修改,防止节点重启时产生错乱
第九里程:手动分配槽位
槽位规划:根据主节点个数平均分配,做除法运算
例子:三个主节点,共16384个槽位,因此每节点个槽位个数为:16384/3约等于5461
db01:6380 0-5460
db02:6380 5461-10921
db03:6380 10922-16383分配槽位
redis-cli -h db01 -p 6380 CLUSTER ADDSLOTS {0..5460}
redis-cli -h db02 -p 6380 CLUSTER ADDSLOTS {5461..10922}
redis-cli -h db03 -p 6380 CLUSTER ADDSLOTS {10923..16383}
- 查看集群状态
redis-cli -h db01 -p 6380 CLUSTER info
正常状态如下:
补充:若在手动分配槽位的过程中,出现误操作需要删除手动的槽位,命令如下:cluster delslots {对应的槽位范围},如果全部主节点都需要从新分配,可采用命令:CLUSTER RESET(所有节点都需操作,包括从节点)。
第十里程:手动部署复制关系
redis-cli -h 10.0.0.51 -p 6381 CLUSTER REPLICATE #db02的6380的ID
redis-cli -h 10.0.0.52 -p 6381 CLUSTER REPLICATE #db03的6380的ID
redis-cli -h 10.0.0.53 -p 6381 CLUSTER REPLICATE #db01的6380的ID
说明:采取交叉复制的原则,保证主节点和从节点不在同一个服务器即可,看好对应关系
五、生产环境注意项
一般在测试环境搭建Redis集群时按照上述过程,一切搭建正常,但上生产后再搭建Redis集群的过程中,就会出现集群发现不了或者启动失败的现象,大概率是因为启动Redis集群时,Redis数据库在启动设定的端口号的同时,会自动再启动另一个集群的特殊端口,而这个端口是,10000+原先设定的端口,以上述为例即16380和16381,所以再安全组策略或者防火墙权限设置时,必须提前开放集群特殊端口号。报错信息一般为:“Waiting for the cluster to join卡住”
六、集群登陆模式
在集群模式下,Redis 接受任何键相关命令时首先会计算键对应的槽,再根据槽找出所对应的节点如果节点是自身,则处理键命令; 否则回复 MOVED 重定向错误,通知客户端请求正确的节点,这个过程称为 Mover 重定向,为了避免Mover重定向的错误提示,我们可以采用Redis集群的登陆模式,为:“redis-cli -c -h ip -p 端口”,以该模式启动Redis数据库时,任意节点插入数据,通过哈希算法找到不同节点的槽位,此时如果判断不是自身本节点槽位,则自动向目标节点发送插入数据的key,再有集群内的目标节点完成插入数据操作,并返回信息告知目标节点信息。
七、Redis Cluster 通讯流程
在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否出现故障灯状态信息,redis 集群采用 Gossip(流言)协议,Gossip 协议工作原理就是节点彼此不断交换信息,一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播。
通信过程:
1)集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信, 通信端口在基础端口上家 10000.
2)每个节点在固定周期内通过特定规则选择结构节点发送 ping 消息
3)接收到 ping 消息的节点用 pong 消息作为响应。集群中每个节点通过一定规则挑选要通信的节点,每个节点可 能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会打成一致的状态,当节点 出现故障,新节点加入,主从角色变化等,它能够给不断的 ping/pong 消息,从而达到同步目的。
通讯消息类型:
- Gossip:Gossip 协议职责就是信息交换,信息交换的载体就是节点间彼此发送 Gossip 消息。 常见 Gossip 消息分为:ping、 pong、 meet、 fail 等;
- Meet消息:用于通知新节点加入,消息发送者通知接受者加入到当前集群,meet 消息通信正常完成后,接收节点 会加入到集群中并进行 ping、 pong 消息交换;
- Ping消息:集群内交换最频繁的消息,集群内每个节点每秒想多个其他节点发送 ping 消息,用于检测节点是否 在线和交换彼此信息;
- Pong消息:当接收到 ping,meet 消息时,作为相应消息回复给发送方确认消息正常通信,节点也可以向集群内 广播自身的 pong 消息来通知整个集群对自身状态进行更新;
-
Fail消息:当节点判定集群内另一个节点下线时,回向集群内广播一个 fail 消息,其他节点收到 fail 消息之后 把对应节点更新为下线状态。
八、故障模拟检验
- 模拟一台服务器db02故障
kill `ps -ef |grep 6380 |awk '{print $2}'|head -1`
- 查看db02从节点是否自动升级为主节点即当前集群状态
redis -c -h 10.0.0.51 -p 6380 cluster nodes
- 故障节点恢复启动
redis-server /opt/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_6381/conf/redis_6381.conf
此时,我们可以通过日志或者集群成员状态信息,发现从新启动的db02的主节点自动变更为从节点
- 故障节点恢复主节点
redis-cli -c -h 10.0.0.52 -p 6380 CLUSTER FAILOVER
注意:需要哪个节点从从节点变更为主节点,就在该从节点操作此命令,手动发起主从切换