redis集群redis-cluster

redis的集群    redis-cluster
redis官方提供了redis-trib.rb工具,但是在使用之前 需要安装ruby,以及redis和ruby连接:
yum install -y ruby rubygems ruby-devel rpm-build

建立连接时报错


Centos默认支持ruby到2.0.0,可gem 安装redis需要最低是2.2.2, 解决办法是 先安装rvm,再把ruby版本提升至2.3.3
curl -sSL https://rvm.io/mpapis.asc | gpg2 --import -
curl -L get.rvm.io | bash -s stable

rvm install 2.3.3
  ruby -v
  gem -v
  gem install redis -v 3.3.3(默认安装4.0.1版本有问题)
   否则会出现添加主节点时迁移slot,有数据的slot迁移不成功出现报错:ERR       CALLING migrate ,try Client........
这里在同一台服务器用不同的端口表示不同的redis服务器,如下:
主节点:192.168.1.120:7001 192.168.1.120:7002 192.168.1.120:7003
从节点:192.168.1.120:7004 192.168.1.120:7005 192.168.1.120:7006

cp redis.conf /usr/local/redis-cluster/7001
修改7001下的redis.conf若干参数
绑定端口,port 7001
绑定IP,bind 192.168.1.120
指定数据存放路径,dir /usr/local/redis-cluster/7001
启动集群模式,cluster-enabled yes
指定集群节点配置文件,cluster-config-file nodes-7001.conf
后台启动,daemonize yes
指定集群节点超时时间,cluster-node-timeout 5000
指定持久化方式,appendonly yes
将剩余的700x目录下的redis.conf参数都修改

启动六台redis
for((i=1;i<=3;i++));do redis-server /usr/local/redis-cluster/700$i/redis.conf;done
redis集群redis-cluster_第1张图片

cd /usr/local/redis-4.0.2/src/
./redis-trib.rb create --replicas 1 192.168.1.120:7001 192.168.1.120:7002 192.168.1.120:7003 192.168.1.120:7004 192.168.1.120:7005 192.168.1.120:7006
create,表示创建一个新的集群。选项 –replicas 1 表示为集群中的每个主节点创建一个从节点。之后跟着的其他参数则是实例的地址列表, 指定使用这些地址所指示的实例来创建新集群。

集群中的 16384 个槽都有至少一个主节点在处理, 集群运作正常。
创建集群报错:
redis集群redis-cluster_第2张图片
解决:
删除append,nodes文件
客户端连接集群
redis集群redis-cluster_第3张图片


逐个关闭集群
for((i=1;i<=6;i++));do redis-cli -c -h 192.168.1.120 -p 700$i shutdown;done
添加脚本实现开启,创建启动,关闭集群
在/usr/bin下创建start_cluster.sh  create_cluster.sh shutdown_cluster.sh三个文件,将上述对应的命令写入后,即可执行./start_cluster.sh等

若重新启动时报错,需要清除杀掉redis实例,然后删除每个节点下的临时数据文件appendonly.aof,dump.rdb,nodes-700x.conf,然后再重新启动redis实例即可启动集群。
redis集群redis-cluster_第4张图片
for((i=1;i<=6;i++)); do cd 700$i; rm -rf appendonly.aof; rm -rf dump.rdb; rm -rf nodes-700$i.conf; cd ..; done
再进去7001  flushdb
dump.rdb是由Redis服务器自动生成的 默认情况下 每隔一段时间redis服务器程序会自动对数据库做一次遍历,把内存快照写在一个叫做“dump.rdb”的文件里,这个持久化机制叫做SNAPSHOT。有了SNAPSHOT后,如果服务器宕机,重新启动redis服务器程序时redis会自动加载dump.rdb,将数据库状态恢复到上一次做SNAPSHOT时的状态。

测试集群:

redis集群redis-cluster_第5张图片
客户端连接加 -c选项的时候,存储和提取key的时候不断在7031和7032之间跳转,这个称为 客户端重定向。之所以发生客户端重定向,是因为Redis Cluster中的每个Master节点都会负责一部分的槽(slot),存取的时候都会进行 键值空间计算定位key映射在哪个槽(slot)上,如果映射的槽(slot)正好是当前Master节点负责则直接存取,否则就跳转到其他Master节点负的槽(slot)中存取,这个过程对客户端是透明的。

redis的集群分区:
redis存取key的时候,都要定位相应的槽(slot)。
Redis 集群键分布算法使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 它们的编号为0-16383,这个槽是一个逻辑意义上的槽,实际上并不存在。redis中的每个key都属于这 16384 个哈希槽的其中一个,存取key时都要进行key->slot的映射计算。
创建集群的时候,哈希槽被分配到了三个主节点上,从节点是没有哈希槽的。7001负责编号为0-5460 共5461个 slots,7002负责编号为 5461-10922共5462 个 slots,7003负责编号为10923-16383 共5461个 slots。
redis也采用一定的算法进行键-槽(key->slot)之间的映射。memcached采用一致性哈希(consistency hashing)算法进行键-节点(key-node)之间的映射,而redis集群使用集群公式来计算键 key 属于哪个槽:  HASH_SLOT(key)= CRC16(key) % 16384
CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。key经过公式计算后得到所对应的哈希槽,而哈希槽被某个主节点管理,从而确定key在哪个主节点上存取,这也是redis将数据均匀分布到各个节点上的基础。
redis集群redis-cluster_第6张图片
如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。

新增节点:
mkdir /usr/local/redis-cluster/7004 && cp /usr/local/redis-cluster/7001/redis.conf /usr/local/redis-cluster/7004/ && sed -i "s/7001/7004/g" /usr/local/redis-cluster/7004/redis.conf
./redis-server /usr/local/redis-cluster/7004/redis.conf 
./redis-trib.rb add-node 192.168.1.120:7008 192.168.1.120:7001
redis集群redis-cluster_第7张图片
从添加主节点输出信息和查看集群信息中可以看出,我们已经成功的向集群中添加了一个主节点,但是这个主节还没有成为真正的主节点,因为还没有分配槽(slot),也没有从节点,现在要给它分配槽(slot)
./redis-trib.rb reshard 192.168.1.120:7001
redis集群redis-cluster_第8张图片
Source node #1: all
表示从所有的主节点中随机转移,凑够1024个哈希槽,然后就开始从新分配槽(slot)了。从新分配完后再次查看集群节点信息
redis集群redis-cluster_第9张图片
分slot失败:

redis集群redis-cluster_第10张图片

处理方法:修复
./redis-trib.rb fix 192.168.1.120:7007/7002
./redis-cli -c -h 192.168.1.120 -p 7007/7002
cluster setslot 5798 stable
再重新执行reshard


指定从节点:
7006的主节点是7003,将7006变为7008的从节点

若让7008成为某个主节点的从节点
./redis-cli -c -p 7003 cluster replicate nodeID(主节点)

删除节点:
redis集群redis-cluster_第11张图片
删除节点报is not empty! Reshard data away and try again.异常的意思就是因为当前节点不为空(有slots槽),需要重新分区(即把当前节点的槽分出去)才可以删除节点。
具体措施:重复执行上面分配槽点步骤
redis集群redis-cluster_第12张图片
How many slots do you want to move (from 1 to 16384)? ,指要移动多少个配槽,输入要删除节点现有槽数量;
What is the receiving node ID?,指分配给谁,输入节点id,需要删除的节点除外;
在Source node #1:,指从哪几个节点中移除512个槽,此时输入需要删除节点的id。
redis集群redis-cluster_第13张图片
当有增减节点时,可以使用rebalance来重新平衡各master的slot分配
redis集群redis-cluster_第14张图片
有关集群的操作命令
cluster info :打印集群的信息
cluster nodes :列出集群当前已知的所有节点( node),以及这些节点的相关信息。
节点:
cluster meet :将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
cluster forget :从集群中移除 node_id 指定的节点。
cluster replicate :将当前节点设置为 node_id 指定的节点的从节点。
cluster saveconfig :将节点的配置文件保存到硬盘里面。
槽 slot:
cluster addslots [slot ...] :将一个或多个槽( slot)指派( assign)给当前节点
cluster delslots [slot ...] :移除一个或多个槽对当前节点的指派
cluster flushslots :移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点
cluster setslot node :将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
cluster setslot migrating :将本节点的槽 slot 迁移到 nodeid 指定的节点中
cluster setslot importing :从 node_id 指定的节点中导入槽 slot 到本节点
cluster setslot stable :取消对槽 slot 的导入( import)或者迁移( migrate)

键key:
cluster keyslot :计算键 key 应该被放置在哪个槽上
cluster countkeysinslot :返回槽 slot 目前包含的键值对数量
cluster getkeysinslot :返回 count 个 slot 槽中的键 


Redis集群三种常见的解决方案
1、客户端分片 :这种方案将分片工作放在业务程序端,程序代码根据预先设置的路由规则,直接对多个Redis实例进行分布式访问。这样的好处是,不依赖于第三方分布式中间件,实现方法和代码都自己掌控,可随时调整,不用担心踩到坑。这实际上是一种静态分片技术。Redis实例的增减,都得手工调整分片程序。基于此分片机制的开源产品,现在仍不多见。这种分片机制的性能比代理式更好(少了一个中间分发环节)。但缺点是升级麻烦,对研发人员的个人依赖性强——需要有较强的程序开发能力做后盾。如果主力程序员离职,可能新的负责人,会选择重写一遍。所以,这种方式下,可运维性较差。出现故障,定位和解决都得研发和运维配合着解决,故障时间变长。因此这种方案,难以进行标准化运维,不太适合中小公司(除非有足够的DevOPS)。
2、代理分片 :这种方案,将分片工作交给专门的代理程序来做。代理程序接收到来自业务程序的数据请求,根据路由规则,将这些请求分发给正确的Redis实例并返回给业务程序。这种机制下,一般会选用第三方代理程序(而不是自己研发),因为后端有多个Redis实例,所以这类程序又称为分布式中间件。这样的好处是,业务程序不用关心后端Redis实例,运维起来也方便。虽然会因此带来些性能损耗,但对于Redis这种内存读写型应用,相对而言是能容忍的。这是推荐的集群实现方案。像基于该机制的开源产品 Twemproxy,Codis 便是其中代表,应用非常广泛。
3、服务器端分片 :建立在基于无中心分布式架构之上(没有代理节点性能瓶颈问题)。Redis-Cluster即为官方基于该架构的解决方案。 Redis Cluster 将所有Key映射到16384个Slot中,集群中每个Redis实例负责一部分,业务程序通过集成的Redis Cluster客户端进行操作。客户端可以向任一实例发出请求,如果所需数据不在该实例中,则该实例引导客户端自动去对应实例读写数据。Redis Cluster的成员管理(节点名称、IP、端口、状态、角色)等,都通过节点之间两两通讯,定期交换并更新。
 
各解决方案代表产品实现方式优缺点:
Twemproxy:
Twemproxy是一种代理分片机制,由 Twitter开源。 Twemproxy作为代理,可接受来自多个程序的访问,按照路由规则,转发给后台的各个Redis服务器,再原路返回。这个方案顺理成章地解决了单个Redis实例承载能力的问题。当然,Twemproxy本身也是单点,需要用Keepalived做高可用方案。这么些年来,Twemproxy是应用范围最广、稳定性最高、最久经考验的分布式中间件。只是,他还有诸多不方便之处。Twemproxy最大的痛点在于,无法平滑地扩容/缩容。这样增加了运维难度:业务量突增,需增加Redis服务器;业务量萎缩,需要减少Redis服务器。但对Twemproxy而言,基本上都很难操作。或者说,Twemproxy更加像服务器端静态sharding。有时为了规避业务量突增导致的扩容需求,甚至被迫新开一个基于Twemproxy的Redis集群。Twemproxy另一个痛点是,运维不友好,甚至没有控制面板
 
Codis:
Codis由 豌豆荚 于2014年11月开源,基于Go和C开发,是近期涌现的、国人开发的优秀开源软件之一。现已广泛用于豌豆荚的各种Redis业务场景,从各种压力测试来看,稳定性符合高效运维的要求。性能更是改善很多,最初比Twemproxy慢20%;现在比Twemproxy快近100%(条件:多实例,一般Value长度)。Codis具有可视化运维管理界面。Codis无疑是为解决Twemproxy缺点而出的新解决方案。因此综合方面会由于Twemproxy很多。目前也越来越多公司选择Codis。Codis引入了Group的概念,每个Group包括1个Redis Master及至少1个Redis Slave,这是和Twemproxy的区别之一。这样做的好处是,如果当前Master有问题,则运维人员可通过Dashboard“自助式”切换到Slave,而不需要小心翼翼地修改程序配置文件。为支持数据热迁移(Auto Rebalance),出品方修改了Redis Server源码,并称之为Codis Server。Codis采用预先分片(Pre-Sharding)机制,事先规定好了,分成1024个slots(也就是说,最多能支持后端1024个Codis Server),这些路由信息保存在ZooKeeper中。
 
Redis-cluster:
reids-cluster在redis3.0中推出,支持Redis分布式集群部署模式。采用无中心分布式架构。所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.节点的fail是通过集群中超过半数的节点检测失效时才生效.客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可,减少了代理层,大大提高了性能。redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key之间的关系。目前Jedis已经支持Redis-cluster。从计算架构或者性能方面无疑Redis-cluster是最佳的选择方案。(PS:虽然Redis-cluster从方案选型上面比较占据优势,但是由于Redis-cluster刚推出不久,虽然官方宣传已经发布的是文档版本,但稳定性方面还有待验证)
redis存储数据时,根据hash算法随机把数据存在slot
在某个节点下set的值不一定分配给自己节点的槽,可能分配给其他节点的槽,在这个集群的任何一个节点都可以get到任意节点set的值。
redis集群redis-cluster_第15张图片
删除主节点时,若节点有数据,则必须把数据迁移走,否则无法删除节点;数据迁移需要重新reshard  slot,将删除节点的slot移到指定节点上,则原有数据也将随slot迁移到指定节点上;
 新增主节点时,重新分配slot的时候,原有各个node的slot上的数据是随机分配迁移到新主节点;

如果一个master挂了,那么会根据选举算法从slave选出一个master;
如果一个集群中每个master只有一个slave,当master和slave都挂掉的时候这个集群就崩溃了。因为此时有一些哈希槽无法找到了。虽然网络分裂会把一堆节点从集群中孤立出来,但是其他的更常见的硬件或者软件的问题并不会在多台机器上同时发生,所以很 可能在你的这个集群(平均每个master只有一个slave)有一个slave在早上4点挂掉,然后他的master在随后的早上6点挂掉。这样依然会 导致集群崩溃。



你可能感兴趣的:(redis)