RedisCluster是redis的分布式解决方案,在3.0版本后推出的方案,有效地解决了Redis分布式的需求,当遇到单机内存、并发等瓶颈时,可以使用此方案来解决这些问题node
1,分布式数据库把整个数据按分区规则映射到多个节点,即把数据划分到多个节点上,每一个节点负责总体数据的一个子集,好比咱们库有900条用户数据,有3个redis节点,将900条分红3份,分别存入到3个redis节点redis
2,分区规则:数据库
常见的分区规则哈希分区和顺序分区,redis集群使用了哈希分区,顺序分区暂用不到,不作具体说明;rediscluster采用了哈希分区的“虚拟槽分区”方式(哈希分区分节点取余、一致性哈希分区和虚拟槽分区),其它两种也不作介绍,有兴趣能够百度了解一下。ruby
3,虚拟槽分区(槽:slot)并发
RedisCluster采用此分区,全部的键根据哈希函数(CRC16[key]&16383)映射到0-16383槽内,共16384个槽位,每一个节点维护部分槽及槽所映射的键值数据,哈希函数: Hash()=CRC16[key]&16383 按位与分布式
槽与节点的关系以下函数
redis用虚拟槽分区缘由:1,解耦数据与节点关系,节点自身维护槽映射关系,分布式存储工具
4,redisCluster的缺陷:ui
a,键的批量操做支持有限,好比mset, mget,若是多个键映射在不一样的槽,就不支持了spa
b,键事务支持有限,当多个key分布在不一样节点时没法使用事务,同一节点是支持事务
c,键是数据分区的最小粒度,不能将一个很大的键值对映射到不一样的节点
d,不支持多数据库,只有0,select 0
e,复制结构只支持单层结构,不支持树型结构。
1,在/usr/local/bin/clusterconf目录,
6389为6379的从节点,6390为6380的从节点,6391为6381的从节点
2,分别修改637九、 6380、 738一、 638九、 6390、 6391配置文件
port 6379 //节点端口
cluster-enabled yes //开启集群模式
cluster-node-timeout 15000 //节点超时时间(接收pong消息回复的时间)
cluster-config-file /usrlocalbin/cluster/data/nodes-6379.conf 集群内部配置文件
其它节点的配置和这个一致,改端口便可
3,配置完后,启动6个redis服务
命令:cd /usr/local/bin/clusterconf/data
cat nodes-6379.conf //查看6379节点ID值
也能够这样查看 6379>cluster nodes
4,各节点启动后,使用cluster meet ip port与各节点握手,是集群通讯的第一步
5,握手成功后,使用cluster nodes能够看到各节点均可以互相查询到
6,节点握手成功后,此时集群处理下线状态,全部读写都被禁止
7,使用cluster info命令获取集群当前状态
8,redis集群有16384个哈希槽,要把全部数据映射到16384槽,须要批量设置槽
redis-cli -h 127.0.0.1 -p 6379 cluster addslots {0...5461}
但个人虚拟机按范围分配有问题,同窗们回去试一下看有没有问题
错误为: (error) ERR Invalid or out of range slot
批量不行,单个是能够的
redis-cli -h 127.0.0.1 -p 6379 cluster addslots 1 2 3 4
所以,我写一个脚本/usr/local/bin/addSlots.sh, 详情可见些脚本……
执行这个脚本可分配好槽位……
9,分配完槽后,可查看集群状态
10,而后再查看cluster nodes,查看每一个节点的ID
11,将6389,6390,6391与 6379,6380,6381作主从映射
127.0.0.1:6389> cluster replicate af2c99b58aa8a0a8fd82ba594654ce9264ffb9bc
127.0.0.1:6390> cluster replicate 2d6e6deb9512324336754b7b3fdf86032445c77c
127.0.0.1:6391> cluster replicate 61bd9fbbd3c154da318b502b86b1ee6516b82c17
12,注:这是手动模式,在生产环境咱们通常采用如下自动模式安装
1,在/usr/local新建目录:ruby
下载连接:https://pan.baidu.com/s/1kWsf3Rh 密码:n3pc
从这个连接下载 ruby-2.3.1.tar.gz 和 redis-3.3.0.gem
解压 tar -zxvf ruby-2.3.1.tar.gz
a, cd ruby-2.3.1
b, ./configure -prefix=/usr/local/ruby
c, make && make install //过程会有点慢,大概5-10分钟
d, 而后gem install -l redis-3.3.0.gem //没有gem须要安装yum install gem
e,准备好6个节点,(注意不要设置requirepass),将/usr/local/bin/clusterconf/data的config-file删除;依次启动6个节点:./redis-server clusterconf/redis6379.conf
若是以前redis有数据存在,flushall清空;(坑:不须要cluster meet ..)
f, 进入cd /usr/local/bin, 执行如下:1表明从节点的个数
./redis-trib.rb create --replicas 1 192.168.1.111:6379 192.168.1.111:6380 192.168.1.111:6381 192.168.1.111:6389 192.168.1.111:6390 192.168.1.111:6391
主从分配,6379是6389的从节点
貌似只有主节点可读写,从节点不能够
主节点死后,从节点变成主节点
集群健康检测
redis-trib.rb check 192.168.1.111:6379 (注:redis先去注释掉requirepass,否则连不上)
如此出现了这个问题,6379的5798槽位号被打开了
解决以下:
6379,6380,6381的有部分槽位被打开了,分别进入这几个节点,执行
6380:>cluster setslot 1180 stable
cluster setslot 2998 stable
cluster setslot 11212 stable
其它也同样,分别执行修复完后:
此时修复后的健康正常;
当停掉6379后,过会6389变成主节点
注意:使用客户端工具查询时要加-c
./redis-cli -h 192.168.1.111 -p 6379 -c
mset aa bb cc dd,批设置对应在不一样的solt上,缺点
集群正常启动后,在每一个redis.conf里加上
masterauth “12345678”
requiredpass “12345678”
当主节点下线时,从节点会变成主节点,用户和密码是颇有必要的,设置成一致
这上面是一主一从,那能不能一主多从呢?
./redis-trib.rb create --replicas 2
192.168.1.111:6379 192.168.1.111:6380 192.168.1.111:6381
192.168.1.111:6479 192.168.1.111:6480 192.168.1.111:6481
192.168.1.111:6579 192.168.1.111:6580 192.168.1.111:6581
节点之间采用Gossip协议进行通讯,Gossip协议就是指节点彼此之间不断通讯交换信息
当主从角色变化或新增节点,彼此经过ping/pong进行通讯知道所有节点的最新状态并达到集群同步
Gossip协议
Gossip协议的主要职责就是信息交换,信息交换的载体就是节点之间彼此发送的Gossip消息,经常使用的Gossip消息有ping消息、pong消息、meet消息、fail消息
meet消息:用于通知新节点加入,消息发送者通知接收者加入到当前集群,meet消息通讯完后,接收节点会加入到集群中,并进行周期性ping pong交换
ping消息:集群内交换最频繁的消息,集群内每一个节点每秒向其它节点发ping消息,用于检测节点是在在线和状态信息,ping消息发送封装自身节点和其余节点的状态数据;
pong消息,当接收到ping meet消息时,做为响应消息返回给发送方,用来确认正常通讯,pong消息也封闭了自身状态数据;
fail消息:当节点断定集群内的另外一节点下线时,会向集群内广播一个fail消息,后面会讲到。……
消息解析流程
全部消息格式为:消息头、消息体,消息头包含发送节点自身状态数据(好比节点ID、槽映射、节点角色、是否下线等),接收节点根据消息头能够获取到发送节点的相关数据。
选择节点并发送ping消息:
Gossip协议信息的交换机制具备自然的分布式特性,但ping pong发送的频率很高,能够实时获得其它节点的状态数据,但频率高会加剧带宽和计算能力,所以每次都会有目的性地选择一些节点; 可是节点选择过少又会影响故障判断的速度,redis集群的Gossip协议兼顾了这二者的优缺点,看下图:
不难看出:节点选择的流程能够看出消息交换成本主要体如今发送消息的节点数量和每一个消息携带的数据量
流程说明:
集群扩容
这也是分布式存储最多见的需求,当咱们存储不够用时,要考虑扩容
扩容步骤以下:
1.准备好新节点
2.加入集群,迁移槽和数据
1),同目录下新增redis6382.conf、redis6392.conf两
启动两个新redis节点
./redis-server clusterconf/redis6382.conf & (新主节点)
./redis-server clusterconf/redis6392.conf & (新从节点)
2),新增主节点
./redis-trib.rb add-node 192.168.1.111:6382 192.168.1.111:6379
6379是原存在的主节点,6382是新的主节点
3),添加从节点
redis-trib.rb add-node --slave --master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2 192.168.1.111:6392 192.168.1.111:6379
--slave,表示添加的是从节点
--master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2表示主节点6382的master_id
192.168.1.111:6392,新从节点
192.168.1.111:6379集群原存在的旧节点
4),redis-trib.rb reshard 192.168.1.111:6382 //为新主节点从新分配solt
How many slots do you want to move (from 1 to 16384)? 1000 //设置slot数1000
What is the receiving node ID? 464bc7590400441fafb63f2 //新节点node id
Source node #1:all //表示所有节点从新洗牌
新增完毕!
集群减缩节点:
集群同时也支持节点下线掉
下线的流程以下:
流程说明:
删除节点也分两种:
一种是主节点6382,一种是从节点6392。
在从节点6392中,没有分配哈希槽,执行
./redis-trib.rb del-node 192.168.1.111:6392 7668541151b4c37d2d9 有两个参数ip:port 和节点的id。 从节点6392从集群中删除了。
主节点6382删除步骤:
1,./redis-trib.rb reshard 192.168.1.111:6382
问咱们有多少个哈希槽要移走,由于咱们这个节点上刚分配了1000 个因此咱们这里输入1000
2,最后
./redis-trib.rb del-node 192.168.1.111:6382 3e50c6398c75e0088a41f908071c2c2eda1dc900
此时节点下线完成……
咱们知道,在redis集群模式下,redis接收的任何键相关命令首先是计算这个键CRC值,经过CRC找到对应的槽位,再根据槽找到所对应的redis节点,若是该节点是自己,则直接处理键命令;若是不是,则回复键重定向到其它节点,这个过程叫作MOVED重定向
故障转移:
redis集群实现了高可用,当集群内少许节点出现故障时,经过故障转移能够保证集群正常对外提供服务。
当集群里某个节点出现了问题,redis集群内的节点经过ping pong消息发现节点是否健康,是否有故障,其实主要环节也包括了 主观下线和客观下线;
主观下线:指某个节点认为另外一个节点不可用,即下线状态,固然这个状态不是最终的故障断定,只能表明这个节点自身的意见,也有可能存在误判;
下线流程:
客观下线:指真正的下线,集群内多个节点都认为该节点不可用,达成共识,将它下线,若是下线的节点为主节点,还要对它进行故障转移
假如节点a标记节点b为主观下线,一段时间后节点a经过消息把节点b的状态发到其它节点,当节点c接受到消息并解析出消息体时,会发现节点b的pfail状态时,会触发客观下线流程;
当下线为主节点时,此时redis集群为统计持有槽的主节点投票数是否达到一半,当下线报告统计数大于一半时,被标记为客观下线状态。
故障恢复:
故障主节点下线后,若是下线节点的是主节点,则须要在它的从节点中选一个替换它,保证集群的高可用;转移过程以下:
当从节点收集到足够的选票(大于N/2+1)后,触发替换主节点操做,撤销原故障主节点的槽,委派给本身,并广播本身的委派消息,通知集群内全部节点。