一、Redis集群原理
Redis集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现:一个Redis集群包含16384个哈希槽(hash slot),数据库中的每个键都属于这个16384个哈希槽的其中一个,集群使用公式CRC16(key) % 16384来计算键key属于哪个槽,其中CRC16(key)语句用于计算键key的CRC16校验和。集群中的每个节点负责处理一部分哈希槽。举个例子,一个集群有三个哈希槽,其中:节点 A 负责处理0号至于5500号哈希槽。节点 B 负责处理5501号至11号哈希槽。节点 C 负责处理11001号至16384号哈希槽。
这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。比如说:
如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。与此类似, 如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C ,然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞,所以无论是添加新节点还是移除已经存在的节点,又或者改变某个节点包含的哈希数量,都不会造成集群下线。
二、Redis集群中的主从
为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下, 仍然可以正常运作,Redis 集群对节点使用了主从功能: 集群中的每个节点都有 1 个至 N 个品(replica), 其中一个品为主节点(master), 而其余的 N-1 个品为从节点(slave)。
在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理 5501 号至 11 号的哈希槽。另一方面, 假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5501 号至 11 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。不过如果节点 B 和 B1 都下线的话,Redis 集群还是会停止运作。
三,redis集群架构:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
集群选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉。
什么时候整个集群不可用(cluster_state:fail)?
a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成 时进入fail状态。 (redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败。)
b:如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态。(当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误)
四,redis集群部署:
环境:(要让集群正常工作至少需要3个主节点,在这里我们要创建6个redis节点,其中三个为主节点,三个为从节点)
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
127.0.0.1:7003
127.0.0.1:7004
127.0.0.1:7005
1 安装redis:
[root@master src]# yum install ruby rubygems -y
[root@master src]# gem install redis --version 3.0.0
[root@redhat ~]# tar zxvf redis-3.2.9.tar.gz
[root@redhat ~]# cp -r redis-3.2.9.tar.gz /usr/local/redis
[root@redhat ~]# cd /usr/local/redis
[root@redhat ~]# make && make install
[root@redhat ~]# mkdir /usr/local/cluster/data
[root@redhat ~]# mkdir /usr/local/cluster
[root@redhat ~]# mkdir /usr/local/cluster/7000
[root@redhat ~]# mkdir /usr/local/cluster/7001
........
[root@redhat ~]# cp /usr/local/redis/redis.conf /usr/local/cluster/7000/redis_7000.conf
[root@redhat ~]# vi redis_7000.conf
port 7000
daemonize yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
依次编辑每个目录下的redis.conf文件,只需要修改端口即可
启动所有的redis服务:
[root@redhat ~]# redis-server /usr/local/cluster/7000/redis_7000.conf &
........
[root@redhat ~]# redis-server /usr/local/cluster/7005/redis_7005.conf &
2 创建集群:
[root@redhat ~]# cd /usr/local/redis/src
[root@redhat ~]# ./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384
//--replicas 指定了为集群中的每个Master节点配备几个Slave节点,节点角色由顺序决定,先master之后是slave
3 集群状态检查:
[root@redhat ~]# ./redis-trib.rb check 127.0.0.1:6379 //可以检查任意一个子节点,最后输出如下信息,没有任何警告或错误,表示集群启动成功并处于ok状态
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
4 进入集群环境:
[root@redhat ~]# redis-cli -c -p 6379 //随意指定一个redis的端口即可,因为使用了-c,表示连接的是集群
集群(redis-cli -c -p port)
cluster info :打印集群的信息
cluster nodes :列出集群当前已知的所有节点( node),以及这些节点的相关信息。
节点
cluster meet <ip> <port> :将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
cluster forget <node_id> :从集群中移除 node_id 指定的节点。
cluster replicate <node_id> :将当前节点设置为 node_id 指定的节点的从节点。
cluster saveconfig :将节点的配置文件保存到硬盘里面。
槽(slot)
cluster addslots <slot> [slot ...] :将一个或多个槽( slot)指派( assign)给当前节点。
cluster delslots <slot> [slot ...] :移除一个或多个槽对当前节点的指派。
cluster flushslots :移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
cluster setslot <slot> node <node_id> :将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给
另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
cluster setslot <slot> migrating <node_id> :将本节点的槽 slot 迁移到 node_id 指定的节点中。
cluster setslot <slot> importing <node_id> :从 node_id 指定的节点中导入槽 slot 到本节点。
cluster setslot <slot> stable :取消对槽 slot 的导入( import)或者迁移( migrate)。
键
cluster keyslot <key> :计算键 key 应该被放置在哪个槽上。
cluster countkeysinslot <slot> :返回槽 slot 目前包含的键值对数量。
cluster getkeysinslot <slot> <count> :返回 count 个 slot 槽中的键
5 动态添加新节点:
[root@redhat ~]# redis-server /usr/local/cluster/7006/redis_7006.conf & //安装一个新的redis并启动
[root@redhat ~]# cd /usr/local/redis/src
[root@redhat ~]# ./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000 //增加新节点到集群
[root@redhat ~]# redis-cli -c -p 7000 cluster nodes //查看刚才新增的节点
新增的节点可以是主也可以是从,如果要变为主节点,用redis-trib程序把集群中的部分哈希槽移动到新节点,即变为主
[root@redhat ~]# ./redis-trib.rb reshard 127.0.0.1:7000
How many slots do you want to move (from 1 to 16384)? 2000
what is the receiving node ID? f32dc088c881a6b930474fc5b52832ba2ff71899 //在这里输入刚才新增加节点的ID
下一步输入all表示从所有节点中随机转移,凑够2000个hash solts,到这里一个新节点就添加完成了。执行命令查看:
[root@redhat ~]# redis-cli -c -p 7000 cluster nodes
把这个节点变成从节点:
将7006节点变为7001的从节点,命令如下:
[root@redhat ~]# redis-cli -c -p 7006 cluster replicate 0b00721a509444db793d28448d8f02168b94bd38 //后面的ID是7001主节点的ID
[root@redhat ~]# redis-cli -p 7000 cluster nodes //查看是否添加成功
6 删除节点
删除主节点(删除7006主节点):
[root@redhat ~]# ./redis-trib.rb reshard 127.0.0.1:7000 //127.0.0.1:7000是集群的主节点
How many slots do you want to move (from 1 to 16384)?16384 //输入一个大于或等于7006节点所拥有的slots数的数即可.
What is the receiving node ID? 8ab3d14eba181c06dc8826bea0db1becdead2533 //接收这些slots的目标节点,这里是7002节点
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:a2eee0ea546f2c3701b08981737c07938039857c //因为我们要删除7006这个节点,所以源节点的id就是7006的节点ID
Source node #2:done //输入done,回车,就会开始从7006这个节点迁移16384个slot(没有这么多就迁移拥有的全部)到7002节点中去.
[root@redhat ~]# ./redis-trib.rb del-node 127.0.0.1:7006 a2eee0ea546f2c3701b08981737c07938039857c //这个node id要填写7006节点本身的id
注意:经过观察,这个主节点被删除之后,它之前拥有的从节点会自动成为其他主节点的从节点.
删除从节点:
[root@redhat ~]# ./redis-trib.rb del-node 127.0.0.1:7006 b77cdd45dd18cea0e29da87deaa9c6291c62774c //node id填写要7006这个要删除节点的id