分布式数据库需要解决数据分区问题,redis cluster采用虚拟槽分区来对数据进行划分。redis cluster的虚拟槽固定为16384个,编号为0~16383。槽(slot)是集群管理和迁移的基本单位,每个节点会负责一定数量的槽。一个key只对应一个槽。
有了槽之后,节点可以动态的变化管理槽的数量,这样集群的伸缩更加灵活。但是同时由于槽的存在,redis的一些操作也受到了限制。
1.key批量操作支持有限,例如mget,mset,目前只支持具有相同slot值的key执行批量操作,对于隐射不同slot值的key由于执行mget,mset等操作存在于多个不同的节点而不被支持
2.key事务操作支持有限。同样也只支持多key在同一节点上的操作,当多个key位于不同节点时无法使用事务功能。、
3.key作为数据分区的最小粒度,不能将一个大key,比如list,hash映射到不同节点上。
4.不支持多数据库空间,单机下redis支持16个库,集群下只支持一个库,即db0
5.复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构
redis节点数量一般至少6个(三主三从)才能保证完全高可用的集群
我这里选择六台不同的机器用作实验,条件不够的用一台机器设置不同的端口也可以做到
安装方法前面有介绍(传送门)
六台机器只需要做如下修改,其它保持默认即可,目前先不用考虑集群密码问题,关于集群密码的配置后面会介绍。
删除bing 127.0.0.1
将保护模式关闭 protected-mode no
开启后台模式启动 daemonize yes
dir "/opt/redis-5.0.3/data"
#开启集群模式
cluster-enabled yes
#集群内部配置文件
cluster-config-file nodes-6379.conf
#节点超时时间
cluster-node-timeout 15000
redis-server redis_cluster.conf
节点启动后data目录下会生成一个nodes-6379.conf,这个是集群内部配置文件,第一次启动时如果集群没有设置配置文件,节点会自动创建一个配置文件,如果存在,节点启动时会使用集群配置文件初始化集群信息。
[root@kafka31 data]# cat nodes-6379.conf
9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30 :0@0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0
其中9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30为节点ID,用来唯一标识节点。通过cluster nodes命令也可以获取节点ID。
127.0.0.1:6379> cluster nodes
9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30 :6379@16379 myself,master - 0 0 0 connected
所有节点启动后,节点并不能感知到其它节点的存在,需要通过Gossip协议彼此通信才能感知到其它节点的存在。
在某一个redis客户端执行cluster meet ip port 可以将两个redis建立通信,但是只需要在一个客户端执行该命令即可,集群内部节点是相互通信的。注意关闭防火墙,否则会出现handshake问题
127.0.0.1:6379> cluster meet 192.168.0.32 6379
OK
127.0.0.1:6379> cluster meet 192.168.0.33 6379
OK
127.0.0.1:6379> cluster meet 192.168.0.34 6379
OK
127.0.0.1:6379> cluster meet 192.168.0.35 6379
OK
127.0.0.1:6379> cluster meet 192.168.0.36 6379
OK
再次查看集群节点信息发现6个节点已经感知到彼此的存在
127.0.0.1:6379> cluster nodes
ec8850959ed4b93abcfb1a5db148912ae6c6677e 192.168.0.35:6379@16379 myself,master - 0 1550107218000 0 connected
9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30 192.168.0.31:6379@16379 master - 0 1550107216141 1 connected
d7b44c9cc0c3bab985d1ecf502ae9ab35c28538a 192.168.0.33:6379@16379 master - 0 1550107218149 5 connected
9238b6699706f9565fa74a39982d33a20ca4e7ad 192.168.0.36:6379@16379 master - 0 1550107216000 4 connected
b831a64f5c817c6eb5033f19cdf4eb8459a451d9 192.168.0.32:6379@16379 master - 0 1550107217000 2 connected
1926c9f0d7f197cef9579076ce8a27827aeab948 192.168.0.34:6379@16379 master - 0 1550107217145 3 connected
但是此时集群时不可用的
127.0.0.1:6379> set hello world
(error) CLUSTERDOWN Hash slot not served
因为集群槽未分配,可以通过cluster info查看集群状态
127.0.0.1:6379> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:416
cluster_stats_messages_pong_sent:406
cluster_stats_messages_meet_sent:6
cluster_stats_messages_sent:828
cluster_stats_messages_ping_received:406
cluster_stats_messages_pong_received:401
cluster_stats_messages_received:807
可以看到此时集群被分配的槽未0个。只有当16384个槽全部分配后,集群才进入在线状态。
通过cluster addslots给节点分配槽
[root@kafka31 data]# redis-cli -h 192.168.0.31 -p 6379 cluster addslots {0..5461}
OK
[root@kafka31 data]# redis-cli -h 192.168.0.32 -p 6379 cluster addslots {5462..10922}
OK
[root@kafka31 data]# redis-cli -h 192.168.0.33 -p 6379 cluster addslots {10923..16383}
OK
再次查看集群状态,槽已经分配完成
[root@kafka31 data]# redis-cli
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1350
cluster_stats_messages_pong_sent:1315
cluster_stats_messages_meet_sent:6
cluster_stats_messages_sent:2671
cluster_stats_messages_ping_received:1315
cluster_stats_messages_pong_received:1335
cluster_stats_messages_received:2650
查看节点和槽的关系
127.0.0.1:6379> cluster nodes
9238b6699706f9565fa74a39982d33a20ca4e7ad 192.168.0.36:6379@16379 master - 0 1550108447000 4 connected
b831a64f5c817c6eb5033f19cdf4eb8459a451d9 192.168.0.32:6379@16379 master - 0 1550108447910 2 connected 5462-10922
ec8850959ed4b93abcfb1a5db148912ae6c6677e 192.168.0.35:6379@16379 master - 0 1550108446908 0 connected
d7b44c9cc0c3bab985d1ecf502ae9ab35c28538a 192.168.0.33:6379@16379 master - 0 1550108445904 5 connected 10923-16383
1926c9f0d7f197cef9579076ce8a27827aeab948 192.168.02.34:6379@16379 master - 0 1550108444000 3 connected
9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30 192.168.0.31:6379@16379 myself,master - 0 1550108445000 1 connected 0-5461
到目前为止,集群还有三个节点未使用,这三个节点用来做拥有槽节点的从节点,这样当集群发生故障时就拥有故障转移能力,集群更加可靠。
使用cluster replicate nodeID 将一个节点称为nodeID的从节点,该命令必须在对应的从节点上执行。
192.168.0.34上执行
127.0.0.1:6379> cluster replicate 9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30
OK
192.168.0.35上执行
127.0.0.1:6379> cluster replicate b831a64f5c817c6eb5033f19cdf4eb8459a451d9
OK
192.168.0.36上执行
127.0.0.1:6379> cluster replicate d7b44c9cc0c3bab985d1ecf502ae9ab35c28538a
OK
查看节点状态,34,35,36分别是31,32,33的从节点
127.0.0.1:6379> cluster nodes
9238b6699706f9565fa74a39982d33a20ca4e7ad 192.168.0.36:6379@16379 slave d7b44c9cc0c3bab985d1ecf502ae9ab35c28538a 0 1550109569078 5 connected
b831a64f5c817c6eb5033f19cdf4eb8459a451d9 192.168.0.32:6379@16379 master - 0 1550109568077 2 connected 5462-10922
ec8850959ed4b93abcfb1a5db148912ae6c6677e 192.168.0.35:6379@16379 slave b831a64f5c817c6eb5033f19cdf4eb8459a451d9 0 1550109567000 2 connected
d7b44c9cc0c3bab985d1ecf502ae9ab35c28538a 192.168.0.33:6379@16379 master - 0 1550109568000 5 connected 10923-16383
1926c9f0d7f197cef9579076ce8a27827aeab948 192.168.0.34:6379@16379 slave 9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30 0 1550109566072 3 connected
9af81cb6a9a2ced8d809d649f5bcf48ea9c26b30 192.168.0.31:6379@16379 myself,master - 0 1550109565000 1 connected 0-5461
31上执行
127.0.0.1:6379> set hello world
OK
在32上执行,key所对应的槽不在32上,会有重定向
127.0.0.1:6379> get hello
(error) MOVED 866 192.168.0.31:6379 这是重定向,后面会介绍
查看从节点34是否成功复制31上的数据
34上执行
127.0.0.1:6379> get hello
(error) MOVED 866 192.168.0.31:6379 从节点也是重定向,因为从节点目前是集群模式,所以会重定向
要想读取34上从节点的数据,需要先发送readonly
需要先发送readonly再读取
127.0.0.1:6379> readonly
OK
127.0.0.1:6379> get hello
"world"