Redis集群工作原理:
Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念。 Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。集群的每个 节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么: 节点 A 包含 0 到 5460号哈希槽. 节点 B 包含5461到10922号哈希槽. 节点 C 包含10923到16383号哈希槽. 这种结构很容易添加或者删除节点,比如如果我想新添加个节点D,我需要从节点 A, B, C中得部分槽到 D上。如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除 即可。由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节 点的哈希槽的数量都不会造成集群不可用的状态。
Redis 集群的主从复制模型:
为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型, 每个节点都会有N-1个复制品。 在上面具有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就 会以为缺少5461到10922这个范围的槽而不可用。 然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,那么整个 集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选举B1为新的主节点 继续服务,整个集群便不会因为槽找不到而不可用了,不过当B和B1 都失败后,集群是不可用的。
#创建redis-cluster 存放目录: mkdir -p /usr/local/redis-cluster #用初始化脚本方式,快速创建实例配置文件,日志目录: cd /usr/src/redis-5.0.7 root@localhost redis-5.0.7]# ./utils/install_server.sh Welcome to the redis service installer This script will help you easily set up a running redis server Please select the redis port for this instance: [6379] 7001 Please select the redis config file name [/etc/redis/7001.conf] /usr/local/redis-cluster/7001.conf Please select the redis log file name [/var/log/redis_7001.log] /usr/local/redis-cluster/7001.log Please select the data directory for this instance [/var/lib/redis/7001] /usr/local/redis-cluster/7001 Please select the redis executable path [/usr/local/redis/bin/redis-server] /usr/local/redis/bin/redis-server Selected config: Port : 7001 Config file : /usr/local/redis-cluster/7001.conf Log file : /usr/local/redis-cluster/7001.log Data dir : /usr/local/redis-cluster/7001 Executable : /usr/local/redis/bin/redis-server Cli Executable : /usr/local/redis/bin/redis-cli Is this ok? Then press ENTER to go on or Ctrl-C to abort. Copied /tmp/7001.conf => /etc/init.d/redis_7001 Installing service... Successfully added to chkconfig! Successfully added to runlevels 345! Starting Redis server... Installation successful! #以上是创建7001实例: 用相同的方式创建剩余的5个redis cluster实例;
开启Redis集群模式:
#在每个redis 实例的配置文件中,开启如下参数; #将 cluster-enabled yes 前面的#去掉,意味着开启 redis-cluster cluster-enabled yes #将前面的#去掉,并且将配置文件改为 7001.conf,Redis Cluster 记录的启动信息文件, 文件由 cluster 自动生成,不需要用户编辑 cluster-config-file nodes-7001.conf #Redis 群集节点可以不可用的最长时间,而不会将其视为失败。 cluster-node-timeout 5000 #开启 AOF 持久化 appendonly yes
启动Redis实例:
#启动实例服务: /etc/init.d/redis_7001 restart /etc/init.d/redis_7002 restart /etc/init.d/redis_7003 restart /etc/init.d/redis_7004 restart /etc/init.d/redis_7005 restart /etc/init.d/redis_7006 restart #批量启动实例服务: for i in `seq 1 6`;do /etc/init.d/redis_700$i start;sleep 2;done #查看服务进程: netstat -nutlp ps -ef|grep redis-server
搭建集群:
#创建集群: redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1 --cluster-replicas 1 表示为集群中的每个主节点创建一个从节点。 其中指定了6个redis的ip:port,3个master3个slave。 以上命令回车后,当我们输入yes,redis-cli就会将这份配置应用到集群当中,让各个节点开始互相通讯, 最 后可以得到如下信息: ... [OK] All 16384 slots covered
系统就开始执行 cluster 的相关配置,最终 哈希槽均被配置完 毕,且配置好每个主节点和和从节点的对应关系。
执行完毕后,所有主机的 redis 实例数据目录下,都会自动生成 dump.rdb 和 nodes7000.conf 文件
#查看集群信息或状态: [root@localhost redis-5.0.7]# redis-cli -p 7001 cluster info
#查看集群节点: [root@localhost redis-5.0.7]# redis-cli -p 7001 cluster nodes
添加新的节点:
# 重新初始化一个节点: [root@localhost redis-5.0.7]# ./utils/install_server.sh Welcome to the redis service installer This script will help you easily set up a running redis server Please select the redis port for this instance: [6379] 7007 Please select the redis config file name [/etc/redis/7007.conf] /usr/local/redis-cluster/7007.conf Please select the redis log file name [/var/log/redis_7007.log] /usr/local/redis-cluster/7007.log Please select the data directory for this instance [/var/lib/redis/7007] /usr/local/redis/7007 Please select the redis executable path [/usr/local/redis/bin/redis-server] /usr/local/redis/bin/redis-server Selected config: Port : 7000 Config file : /usr/local/redis-cluster/7000.conf Log file : /usr/local/redis-cluster/7000.log Data dir : /usr/local/redis/7000 Executable : /usr/local/redis/bin/redis-server Cli Executable : /usr/local/redis/bin/redis-cli Is this ok? Then press ENTER to go on or Ctrl-C to abort. Copied /tmp/7000.conf => /etc/init.d/redis_7007 Installing service... Successfully added to chkconfig! Successfully added to runlevels 345! Starting Redis server... Installation successful! [root@localhost redis-5.0.7]# #修改配置文件添加如下或开启: cluster-enabled yes cluster-config-file nodes-7000.conf cluster-node-timeout 5000 appendonly ye #启动服务: /etc/init.d/redis_7000 restart
#添加新节点: redis-cli --cluster add-node 127.0.0.1:7000 127.0.0.1:7001
重新分片:
# 可以看到虽然7000新节点添加成功,但是没有分配散列槽: [root@localhost redis-5.0.7]# redis-cli --cluster check 127.0.0.1:7001 127.0.0.1:7001 (e8cf1e59...) -> 0 keys | 5461 slots | 1 slaves. 127.0.0.1:7000 (1186fbcb...) -> 0 keys | 0 slots | 0 slaves. 127.0.0.1:7002 (b02a78af...) -> 0 keys | 5462 slots | 1 slaves. 127.0.0.1:7003 (dd351704...) -> 0 keys | 5461 slots | 1 slaves. [OK] 0 keys in 4 masters. 0.00 keys per slot on average. >>> Performing Cluster Check (using node 127.0.0.1:7001) M: e8cf1e5955caba283e843a57b01f3d5bf04a3f77 127.0.0.1:7001 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 1186fbcb65016b5ce42fa95c77de872b4e9c7e6b 127.0.0.1:7000 slots: (0 slots) master M: b02a78af5e9106cb1100e5feff1d56146c911bb1 127.0.0.1:7002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: db67bfb7580ee7f6067f381e8ddd92ebb27044bc 127.0.0.1:7004 slots: (0 slots) slave replicates dd3517043af0ae6f936ae820036079101b61b2b4 S: a1e53727be8fdb39485427d5054c70e9964cddbc 127.0.0.1:7006 slots: (0 slots) slave replicates b02a78af5e9106cb1100e5feff1d56146c911bb1 M: dd3517043af0ae6f936ae820036079101b61b2b4 127.0.0.1:7003 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: fd471711e0d771b22e63dad5e4312aff0144b066 127.0.0.1:7005 slots: (0 slots) slave replicates e8cf1e5955caba283e843a57b01f3d5bf04a3f77 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
重新分配,只需指定一个节点,redis-cli将自动找到其他节点:
#重新分配 redis-cli --cluster reshard 127.0.0.1:7001 首先指定分配多少散列槽: # 重新分配多少个散列槽,这里尝试重新设置2048个散列槽: How many slots do you want to move (from 1 to 16384)? 2048 指定接收哈希槽的节点ID: # 指定接受的redis节点ID,注意不是指定ip地址: (7000实例的ID) What is the receiving node ID? 1186fbcb65016b5ce42fa95c77de872b4e9c7e6b 指定从哪些节点获取散列槽: 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: all # all: 表示自动在所有节点进行分配。 # done: 表示指定节点结束,一般用在移除节点时,指定完Source node #1: 节点ID,再输入done, 表示输入结束
是否确定分配:yes
# 可以看到散列槽已经分配了 [root@node5 ~]# redis-cli --cluster check 127.0.0.1:7000 127.0.0.1:7001 [root@localhost redis-5.0.7]# redis-cli -h 127.0.0.1 -p 7000 cluster nodes
免交互重新分片脚本:
redis-cli reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
# 通过重新分片,将散列槽移到其他节点: redis-cli --cluster reshard 127.0.0.1:7000 How many slots do you want to move (from 1 to 16384)? 2047 # 用来接受散列槽的节点,可以任意指定: What is the receiving node ID? b02a78af5e9106cb1100e5feff1d56146c911bb1 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. # 7000节点的id(意思是把该节点的散列槽分配给其他节点): Source node #1: 1186fbcb65016b5ce42fa95c77de872b4e9c7e6b Source node #2: done # 查看状态: [root@node5 ~]# redis-cli --cluster check 127.0.0.1:7000 127.0.0.1:7001 (aa04c256...) -> 0 keys | 4779 slots | 1 slaves. 127.0.0.1:7002 (f6838a0e...) -> 0 keys | 4779 slots | 1 slaves. # 已经没有了散列槽: 127.0.0.1:7006 (44124bd9...) -> 0 keys | 0 slots | 0 slaves. 127.0.0.1:7004 (e4f85202...) -> 1 keys | 6826 slots | 1 slaves.
以下删除节点:
# 确定没问题了,执行下面命令,可以实现删除节点: 127.0.0.1:7000 [root@node5 ~]# redis-cli --cluster del-node 127.0.0.1:7000 1186fbcb65016b5ce42fa95c77de872b4e9c7e6b >>> Removing node 1186fbcb65016b5ce42fa95c77de872b4e9c7e6b from cluster 127.0.0.1:7000 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node