手动搭建高可用的Redis5.0分片集群,从理论到实践,超详细

前言

前一篇 高可用的Redis主从复制集群,从理论到实践 发布后,反响非常热烈。所以今天继续深入讲解redis集群的搭建和相关理论。
xmr
好吧,其实是因为上篇搭建的主从复制集群,还有一个实际问题不能解决,那就是容量问题。

一般来说,服务不会部署成单节点,主要是有三个原因

  • 容易出现单点故障,导致服务不可用
  • 单节点处理所有的请求,吞吐量有限
  • 单节点容量有限

前一篇搭建的主从复制集群可以解决前两个问题,但是无法解决第三个问题,因为主从复制集群中,三个节点中的数据都是一样的。

基于此,本篇就在前一篇的基础上,再来改进一下,搭建一个更吊的redis集群。只关心集群搭建,而不关心理论的同学可以直接跳到【实验】部分。

在阅读本篇之前,强烈建议先阅读前一篇,本文采用的实验环境和前一篇一致。并且本文是采用9个虚拟机节点搭建,而不是在一台虚拟机改了不同的端口号。

问题

在考虑集群容量的时候,前一篇所搭建的redis主从复制集群,可以抽象成一个可读可写的高可用redis单实例。

本篇所要搭建的集群,可以抽象成下图所示。
redis集群
这种分片(sharding)集群中,三个分片中的数据已经完全不一样。不同的数据存在了不同的分片,这样做的好处非常明显,可以完美的解决容量的问题。

但是随之而来的问题也很多,比如:如何确定一个key应该放入哪个分片、增加节点时数据移动、聚合操作怎么实现等等问题。

这些问题需要一个个去解决,可以说为了解决一个问题,引入了好几个新的问题,这也正是分布式系统的难点之一。

分片

如何决定一个key应该放入哪个分片,实际上就是将key的特征和分片的特征绑定。也就是同一个key无论什么时候通过分片算法来计算,都应该得到同样的结果。而放入redis,都应该是放在一个固定的分片中(前提是集群结构没有改变)。这样客户端在请求这个key的时候,就可以根据同样的分片算法,计算得到key所在的分片。

聪明的你肯定很快就想到了,Java集合框架中就有这样的场景,那就是HashMapHashMap中的数组默认有16个(slot),相当于16个分片,key是如何确定自己在哪个(slot)的呢。首先计算keyhash值,再把hash值对槽的个数取模,计算结果就是key所在的槽。大致就是这样hash(key) % length,当然HashMap采用了更高效的方式。

这种方式简单实用,但是有一个致命的缺点,那就是HashMap扩容的时候,因为数组长度length变了,原来在第3个槽的数据可能要转移到第19个槽,这样就需要移动大量的数据。如果redis分片也采用这种hash + 取模的方式,那么增加redis节点数的时候,就需要移动大量的数据,同样,减少redis节点数的时候,也需要移动大量的数据。动辄移动几个G的数据,对redis来说无疑是致命的。

所以还有一种更吊的分片算法,那就是一致性hash算法。一致性hash算法不仅仅适用于redis的分片,分布式系统中几乎所有的需要分片场景,都可以使用一致性hash算法

一致性hash算法

一致性hash算法的核心就是一个逻辑上的hash环,从02^32-1,一共有2^32个递增的数,现在把首尾相接,就像一条蛇咬住了自己的尾巴。
hash环
大费周章的构造一个逻辑上的hash环有什么用呢。

答案还是取模
只不过之前的方法是对redis分片数量取模,而有了hash环之后,是对整个hash环取模。也就是对2^32取模。以上文三个节点为例,对redis服务器的ip地址或者其他特征,进行一致性hash计算后,可能分布成如下的样子
一致性hahs算法
如果一个key经过同样的hash算法计算之后,肯定会落在环上的某个点。如果刚好落在某个redis分片所在的槽上,那自然不用说,直接就找到了对应的分片。

如果落在各个redis分片所在槽之间呢?

这个key会按照顺时针方向寻找(这也是hash环上2^32个数的递增顺序),直到找到第一个redis分片所在槽。比如hash(key1)落在B和C之间,那么就会顺时针找到C。如图所示,落在AB之间会找B,落在BC之间会找到C,落在CA之间会找到A。这样就保证每个key都能找到自己对应的那个分片。

一致性hash算法相对于直接对分片数量取模的优势在于,增加节分片时,不需要移动大量的数据。
一致性hash算法
如图所示,当我们想集群中增加分片D时,只需要把CD直接的数据重新定位到分片D中,删除分片也是一样。这样一来集群就有了很好的扩展性和稳定性。

看似天衣无缝的方案,实际上也隐藏着许多问题。

在向集群中增加分片D之后,经过hash计算落在CD之间的key会在D分片中查找数据,而这部分数据是存在分片A中的,所以自然找不到。所以这种方案不适合将redis作为数据库来使用,而是适合将redis作为缓存使用。如果缓存数据取不到,会从数据库加载,然后存到缓存。

但是即使作为缓存服务器也并不是万无一失的,由于CD之间的缓存同时失效,大量请求直接落在数据库上,可能会压垮数据库。

这就是常说的缓存雪崩。缓存雪崩,是指在某一个时间段,大量的key集中失效。

为了解决这个问题,可以每次都取相邻两个分片的数据,也就是虽然key落在CD之间,但是同时取分片D和分片A的数据。但是这样也会无形增加redis的压力,所以是一个需要权衡的方案。
这个问题会随着分片数量的增加而减缓,因为分片数量越多,两个分片之间的距离就越短,理论上存入的key就越少。

除此之外,还有一个更严重的问题,那就是当分片数量很少的时候,可能会造成数据倾斜
redis集群
如图所示,集群中只有三个分片,明显BC之间的距离最短,CA之间的距离最长。redis中的大量key经过hash运算后,会均匀的分布在hash环上,这样就会导致大量的key存在分片A中,而只有很少的key落在分片C中。这就是数据分布不均匀,产生了倾斜。

为了解决数据倾斜的问题,一致性hash算法引入了虚拟节点
一致性hash算法
如图所示Va表示分片A的虚拟节点,原来的定位算法不需要改变,只是多了虚拟节点到真实节点的映射,当key经过计算后,需要存入分片Va时,实际上就会存入分片AVbVc类似。这样即使在节点数很少的情况下,也不会发生数据倾斜

集群选型

假设我们已经解决了集群扩展数据倾斜等问题,redis集群可以对外提供服务了。由于每一次客户端请求的key,都可能在不同的分片,所以每个客户端都必须能够连接上每个分片。这样一来必定会导致集群的连接数非常大,并且会有很多连接一直处于浪费的状态。
redis集群
有经验的同学可能立刻就想到了,利用第三方中间件来进行解耦
引入中间件之后,集群结构会变成这样
中间件
针对redis集群,可选的中间件有以下几种

感兴趣的同学可以自己去实践。

本篇主要讲解redis自带的分片集群搭建方式,redis cluster。不需要第三方中间件。

redis cluster

redis cluster不需要第三方中间件解决了集群扩展问题、数据倾斜问题和连接数问题。

Redis 集群没有使用一致性hash算法, 而是引入了哈希槽的概念.

Redis 集群总共有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

这种结构很容易添加或者删除节点,比如如果我想新添加个节点D,我需要从节点 A, B, C中把部分槽到分到D上。如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可。由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量,都不会造成集群不可用的状态。

除此之外redis集群通过内部转发的方式解决了连接数过多的问题。如图所示
redis集群
客户端可以连接任意一个分片,例如A。请求一个key时,如果经过hash取模运算,发现这个key在分片B上。于是就会把请求转发给分片B,由B来完成请求响应。其他的分片也具有同样的功能。这种转发机制实现的前提就是,每个分片都需要知道自己能处理哪些key,还要知道哪些key应该转发给哪个分片。也就是每个分片都维护了各个分片和槽的映射关系。

实验

接下来要搭建的就是含有三个分片的集群,每个分片都是一主两从的主从复制集群,整个架构图如下
redis集群
由于节点数比较多,所以操作的时候需要万分小心,搭建这个集群可以分为以下几步

  • 配置节点信息
  • 集群握手
  • 分配哈希槽
  • 设置主从
  • 启动哨兵

接下来开始集群搭建的详细过程,在搭建过程中遇到了问题,不妨先看看本文的【踩坑记录】这小节。

配置节点信息

9个节点的配置信息都一样,如下所示

bind 0.0.0.0

# 开启集群模式
cluster-enabled yes

# 打开集群内部配置文件,记录了集群的信息,内容不需要手动修改
# 按此方法配置,路径为:/var/lib/redis/6379/nodes-6379.conf
cluster-config-file nodes-6379.conf

# 超时时间,单位毫秒
cluster-node-timeout 15000

# 集群中所有的节点都可用,集群才能对外提供服务,一般改成no
cluster-require-full-coverage no

如果觉得一个个配置太麻烦,可以考虑scp命令,把已经改好的配置文件复制到各个节点。比如把192.168.1.101上的配置文件复制到192.168.1.102

scp -r /etc/redis/6379.conf [email protected]:/etc/redis

配置完成后启动9个节点。

redis-cli连接任意一个服务,可以查看集群中节点信息

192.168.1.101:6379> cluster nodes
ce59eb718555f91d34ae5afca4115737864ef202 :6379@16379 myself,master - 0 0 0 connected 935 4998 9057 9189 13120

可以看到现在集群中只有自己,是因为集群之间还没有进行握手,节点不能感知其他节点的存在。
cluster info命令可以查看自己的信息,可以看到cluster_known_nodes数量为1,也就是当前节点只知道自己这个节点。

192.168.1.101: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:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

集群握手

集群握手是为了让节点与节点之间相互感知,由命令cluster meet完成,先看下该命令的描述

192.168.1.107:6379> help cluster meet

  CLUSTER MEET ip port
  summary: Force a node cluster to handshake with another node
  since: 3.0.0
  group: cluster

redis-cli任意连接一个节点(我这里是192.168.1.101),用cluster meet命令和其他所有节点握手。只需要一个节点和其他所有节点握手即可,不需要节点之间两两握手。

cluster meet 192.168.1.102 6379
cluster meet 192.168.1.103 6379
cluster meet 192.168.1.104 6379
cluster meet 192.168.1.105 6379
cluster meet 192.168.1.106 6379
cluster meet 192.168.1.107 6379
cluster meet 192.168.1.108 6379
cluster meet 192.168.1.109 6379

执行完成后再次查看集群中节点信息

192.168.1.101:6379> cluster nodes
9ff23b983ce2a875989d171a963e577d22ff890a 192.168.1.105:6379@16379 master - 0 1587793590000 1 connected
21516ba2836947cbeffcc7a654c99158f18a83db 192.168.1.101:6379@16379 myself,master - 0 1587793587000 6 connected
02b488aa2f1b1b816aabcddfca1de2beef59310f 192.168.1.107:6379@16379 master - 0 1587793591000 5 connected
4457a54cc5a37d7b1cd3b2e46ffa6b322d3ffc1f 192.168.1.106:6379@16379 master - 0 1587793589000 4 connected
977ac53d051fbfc9409fbba47014a7beb2f75e9b 192.168.1.103:6379@16379 master - 0 1587793589984 2 connected
99d0b470713c992d8e6b4a3540defa3439f4ef11 192.168.1.102:6379@16379 master - 0 1587793591997 7 connected
7e629a54cf2e606d5b7bf5b716215b594d557c2d 192.168.1.108:6379@16379 master - 0 1587793590991 8 connected
fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 192.168.1.104:6379@16379 master - 0 1587793588976 0 connected
619b55b7cad969f4b2105a2056273c8ee1e21483 192.168.1.109:6379@16379 master - 0 1587793589000 3 connected

可以看到现在192.168.1.101已经感知到了其他节点的存在。即使在其他的节点上执行,也能看到集群中所有节点信息。

此时的集群依然是不能对外提供服务的

192.168.1.101:6379> set hello world
(error) CLUSTERDOWN Hash slot not served

从提示也可以看到哈希槽(Hash slot)尚未分配。此时查看集群信息

192.168.1.101:6379> cluster info
cluster_state:fail
cluster_slots_assigned:5
cluster_slots_ok:5
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:9
cluster_size:1
cluster_current_epoch:1
cluster_my_epoch:1
cluster_stats_messages_ping_sent:169
cluster_stats_messages_pong_sent:159
cluster_stats_messages_meet_sent:8
cluster_stats_messages_update_sent:42
cluster_stats_messages_sent:378
cluster_stats_messages_ping_received:159
cluster_stats_messages_pong_received:177
cluster_stats_messages_received:336

cluster_state 状态为fail

分配哈希槽

分配哈希槽由命令cluster addslots完成,该命令描述如下

192.168.1.107:6379> help cluster addslots

  CLUSTER ADDSLOTS slot [slot ...]
  summary: Assign new hash slots to receiving node
  since: 3.0.0
  group: cluster

因为集群中只有三个分片,分别是101、104、107,所以只需要给这三个节点分配哈希槽即可。

redis-cli -h 192.168.1.101 -p 6379 cluster addslots {0..5461}
redis-cli -h 192.168.1.104 -p 6379 cluster addslots {5462..10922}
redis-cli -h 192.168.1.107 -p 6379 cluster addslots {10923..16383}

分配完成后,再次查看集群信息

192.168.1.101: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:9
cluster_size:3
cluster_current_epoch:8
cluster_my_epoch:6
cluster_stats_messages_ping_sent:909
cluster_stats_messages_pong_sent:1124
cluster_stats_messages_meet_sent:18
cluster_stats_messages_update_sent:5
cluster_stats_messages_sent:2056
cluster_stats_messages_ping_received:1123
cluster_stats_messages_pong_received:927
cluster_stats_messages_meet_received:1
cluster_stats_messages_received:2051

可以看到现在的集群状态cluster_state变成了ok

设置主从

先看集群信息

192.168.1.101:6379> cluster nodes
9ff23b983ce2a875989d171a963e577d22ff890a 192.168.1.105:6379@16379 master - 0 1587793786061 1 connected
21516ba2836947cbeffcc7a654c99158f18a83db 192.168.1.101:6379@16379 myself,master - 0 1587793783000 6 connected 0-5461
02b488aa2f1b1b816aabcddfca1de2beef59310f 192.168.1.107:6379@16379 master - 0 1587793785556 5 connected 10923-16383
4457a54cc5a37d7b1cd3b2e46ffa6b322d3ffc1f 192.168.1.106:6379@16379 master - 0 1587793784044 4 connected
977ac53d051fbfc9409fbba47014a7beb2f75e9b 192.168.1.103:6379@16379 master - 0 1587793785000 2 connected
99d0b470713c992d8e6b4a3540defa3439f4ef11 192.168.1.102:6379@16379 master - 0 1587793785000 7 connected
7e629a54cf2e606d5b7bf5b716215b594d557c2d 192.168.1.108:6379@16379 master - 0 1587793782000 8 connected
fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 192.168.1.104:6379@16379 master - 0 1587793782000 0 connected 5462-10922
619b55b7cad969f4b2105a2056273c8ee1e21483 192.168.1.109:6379@16379 master - 0 1587793785052 3 connected

只有101、104、107三个节点分配了槽,所以要把其余的节点变成他们的slave节点,分配主从关系由命令cluster replicate完成,该命令描述如下

192.168.1.101:6379> help cluster replicate

  CLUSTER REPLICATE node-id
  summary: Reconfigure a node as a replica of the specified master node
  since: 3.0.0
  group: cluster

例如,要把192.168.1.102设置成192.168.1.101slave节点,只需要用redis-cli连上192.168.1.102,执行命令

## 后面的长字符串是192.168.1.101的node-id,也就是cluster nodes信息的第一列
cluster replicate 21516ba2836947cbeffcc7a654c99158f18a83db

其余的主从关系也依次配置,完成后整个集群节点信息如下

192.168.1.101:6379> cluster nodes
9ff23b983ce2a875989d171a963e577d22ff890a 192.168.1.105:6379@16379 slave fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 0 1587794070521 1 connected
21516ba2836947cbeffcc7a654c99158f18a83db 192.168.1.101:6379@16379 myself,master - 0 1587794069000 6 connected 0-5461
02b488aa2f1b1b816aabcddfca1de2beef59310f 192.168.1.107:6379@16379 master - 0 1587794071529 5 connected 10923-16383
4457a54cc5a37d7b1cd3b2e46ffa6b322d3ffc1f 192.168.1.106:6379@16379 slave fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 0 1587794070000 4 connected
977ac53d051fbfc9409fbba47014a7beb2f75e9b 192.168.1.103:6379@16379 slave 21516ba2836947cbeffcc7a654c99158f18a83db 0 1587794070000 6 connected
99d0b470713c992d8e6b4a3540defa3439f4ef11 192.168.1.102:6379@16379 slave 21516ba2836947cbeffcc7a654c99158f18a83db 0 1587794071000 7 connected
7e629a54cf2e606d5b7bf5b716215b594d557c2d 192.168.1.108:6379@16379 slave 02b488aa2f1b1b816aabcddfca1de2beef59310f 0 1587794070000 8 connected
fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 192.168.1.104:6379@16379 master - 0 1587794068502 0 connected 5462-10922
619b55b7cad969f4b2105a2056273c8ee1e21483 192.168.1.109:6379@16379 slave 02b488aa2f1b1b816aabcddfca1de2beef59310f 0 1587794068000 5 connected

启动哨兵

三个哨兵的配置文件一样,均配置如下信息。

# 三个集群的名字随意,只是下面几个参数需要和此处保持一致
sentinel monitor sicimike-master-1 192.168.1.101 6379 2
sentinel monitor sicimike-master-2 192.168.1.104 6379 2
sentinel monitor sicimike-master-3 192.168.1.107 6379 2

sentinel down-after-milliseconds sicimike-master-1 30000
sentinel down-after-milliseconds sicimike-master-2 30000
sentinel down-after-milliseconds sicimike-master-3 30000

sentinel parallel-syncs sicimike-master-1 1
sentinel parallel-syncs sicimike-master-2 1
sentinel parallel-syncs sicimike-master-3 1

sentinel failover-timeout sicimike-master-1 180000
sentinel failover-timeout sicimike-master-2 180000
sentinel failover-timeout sicimike-master-3 180000

启动哨兵,三个哨兵启动成功后可以看到如下日志

3074:X 25 Apr 2020 16:25:36.504 # Sentinel ID is c094922067b880e4f39abee8cd332df841203e52
3074:X 25 Apr 2020 16:25:36.504 # +monitor master sicimike-master-2 192.168.1.104 6379 quorum 2
3074:X 25 Apr 2020 16:25:36.504 # +monitor master sicimike-master-1 192.168.1.101 6379 quorum 2
3074:X 25 Apr 2020 16:25:36.504 # +monitor master sicimike-master-3 192.168.1.107 6379 quorum 2
3074:X 25 Apr 2020 16:25:36.509 * +slave slave 192.168.1.102:6379 192.168.1.102 6379 @ sicimike-master-1 192.168.1.101 6379
3074:X 25 Apr 2020 16:25:36.514 * +slave slave 192.168.1.103:6379 192.168.1.103 6379 @ sicimike-master-1 192.168.1.101 6379
3074:X 25 Apr 2020 16:25:36.517 * +slave slave 192.168.1.105:6379 192.168.1.105 6379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:36.520 * +slave slave 192.168.1.106:6379 192.168.1.106 6379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:36.522 * +slave slave 192.168.1.108:6379 192.168.1.108 6379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:36.523 * +slave slave 192.168.1.109:6379 192.168.1.109 6379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:37.882 * +sentinel sentinel 07703c8de60e1115552418a8b4305f85e1f4f20d 192.168.1.102 26379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:37.888 * +sentinel sentinel 07703c8de60e1115552418a8b4305f85e1f4f20d 192.168.1.102 26379 @ sicimike-master-1 192.168.1.101 6379
3074:X 25 Apr 2020 16:25:37.938 * +sentinel sentinel 72d596ea3882e763cd3df0a939234385a25409c3 192.168.1.101 26379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:37.949 * +sentinel sentinel 07703c8de60e1115552418a8b4305f85e1f4f20d 192.168.1.102 26379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:38.146 * +sentinel sentinel 72d596ea3882e763cd3df0a939234385a25409c3 192.168.1.101 26379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:38.219 * +sentinel sentinel 72d596ea3882e763cd3df0a939234385a25409c3 192.168.1.101 26379 @ sicimike-master-1 192.168.1.101 6379

可以看到哨兵监控了三套主从复制

至此,整个集群搭建完成。

操作

普通操作

[root@localhost bin]# redis-cli -h 192.168.1.101 -p 6379
192.168.1.101:6379> set hello world
OK
192.168.1.101:6379> set hello1 world
(error) MOVED 11613 192.168.1.107:6379
192.168.1.101:6379>

根据操作可以看到,有些命令可以写入成功,有些命令却提示了error
bqb
根据提示信息可以知道,是因为hello1这个key落到了分片192.168.1.107上,而连接方式采用的单节点连接,所以会返回错误。

集群环境下,需要以集群的方式连接

[root@localhost bin]> redis-cli -c -h 192.168.1.101 -p 6379
192.168.1.101:6379> set hello world
OK
192.168.1.101:6379> set hello1 world
-> Redirected to slot [11613] located at 192.168.1.107:6379
OK
192.168.1.107:6379> 

连接的时候加上参数-c,表示以操作集群的方式连接,当hello1经过计算落到192.168.1.107分片上时,redis-cli会自动跳转到192.168.1.107上,注意观察命令提示符中的ip变化。

聚合操作

根据常识可以知道,数据一旦被分片之后,聚合操作就难以实现。因为需要聚合的数据可能会分布在不同的分片,为了解决这个问题,redis集群实现了Hashtag机制。可以把含有固定字符的key放入同一个分片中。这个用{}表示的固定字符就是Hashtag

[root@localhost bin]# redis-cli -c -h 192.168.1.101 -p 6379
192.168.1.101:6379> set {sicimike}hello world
OK
192.168.1.101:6379> set {sicimike}hello1 world
OK
192.168.1.101:6379> set {sicimike}hello2 world
OK
192.168.1.101:6379> set {sicimike}hello3 world
OK
192.168.1.101:6379> set {sicimike}hello4 world
OK
192.168.1.101:6379> keys *
1) "{sicimike}hello"
2) "{sicimike}hello1"
3) "{sicimike}hello3"
4) "{sicimike}hello2"
5) "{sicimike}hello4"

根据操作可以看到,含有相同tagkey,都放到了同一个分片中。即使切换到其他分片

[root@localhost bin]# redis-cli -c -h 192.168.1.104 -p
192.168.1.104:6379> set {sicimike}hello5 world
-> Redirected to slot [3722] located at 192.168.1.101:6379
OK
192.168.1.101:6379>

可以看到,含有{sicimike}这个tagkey依然被放到了192.168.1.101

可以说redis集群并不是解决了这个问题,而是规避了这个问题。

reshard

因为单点故障的问题,通过引入主从复制模型加哨兵就可以解决。所以对于分片集群,更应该关注的是伸缩性。本集群中含有三个分片。如果要新增一个分片,应该是怎样操作呢?

redis-cli --cluster help命令可以查看redis集群相关的操作命令,其中有一个叫reshard。可以在不重启redis服务的情况下动态迁移哈希槽。

首先连接一个存活的节点,执行reshard

redis-cli --cluster reshard 192.168.1.101 6379

执行后会有如下提示
redis集群reshard
执行过程中,会让你填写如下信息

  • 要移动多少个槽
  • 移动给哪个分片
  • 从哪(几)个节点上移动,可以配置多个

执行完成后再次查看集群信息
redis集群
可以看到分片101上确实有200个槽移动到了分片107。如果分片107是新增的分片,就可以对外提供服务了。

分片数量减少时也是同样的操作,先把要移除的分片上的槽reshard给其他分片,再移除即可。

这样无论是集群的扩展还是收缩,都变得很容易,真正满足了实际生产中的要求。

踩坑记录

  • 部分输出信息和我不同也不要紧,因为我搭建失败了很多次,所以可能会有上一次搭建残留的信息
  • 不要过早启动sentinel,如果集群不能一次性配置成功,可能需要重启,如果重启了master可能会导致故障自动转移
  • 分配哈希槽的过程中可能会遇到(error) ERR Slot xxx is already busy错误,这是因为上一次的配置没有清理干净。用redis-cli连接到redis-server执行flushallcluster reset即可,执行失败就交换顺序执行
  • 设置主从的时候可能会遇到(error) ERR To set a master the node must be empty and without assigned slots.,意思是master想要变成slave,不能含有槽。产生的原因可能是上一次的配置没有清理干净,或者不该分配槽的节点被分配了槽。用redis-cli连接到redis-server执行flushallcluster reset即可,执行失败就交换顺序执行

自动安装

redis解压目录下/root/redis-5.0.8/utils/create-cluster有一个自动搭建集群的脚本create-cluster。感兴趣的同学自己去研究下。

总结

手动搭建集群可以让我们更好的理解redis集群的工作原理。是一个磨炼性子的活,一次不能成功很正常。搭建成功后,晚餐记得给自己加个鸡腿。

参考

  • 《Redis开发与运维》
  • http://redis.cn/topics/cluster-tutorial.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章