Redis 集群(Cluster)

简介

https://redis.io/docs/reference/cluster-spec (opens in a new tab)

由于数据量过大,单个 Master 复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是 Redis 的集群,其作用是提供在多个 Redis 节点间共享数据的程序集。

  • Redis 集群是一个提供在多个 Redis 节点间共享数据的程序集
  • Redis 集群可以支持多个 Master

作用

  • Redis 集群支持多个 Master,每个 Master 又可以挂载多个 Slave
    • 读写分离
    • 支持数据的高可用
    • 支持海量数据的读写存储操作
  • 由于 Cluster 自带 Sentinel 的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能
  • 客户端与 Redis 的节点连接,不再需要连接集群中所有的节点,只需要任意连接集群中的一个可用节点即可
  • 槽位 slot 负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系

⭐️ 集群算法-分片-槽位 slot

官网

https://redis.io/docs/reference/cluster-spec (opens in a new tab)

The cluster's key space is split into 16384 slots, effectively setting an upper limit for the cluster size of 16384 master nodes (however, the suggested max size of nodes is on the order of ~ 1000 nodes).

Redis 集群的槽位 slot

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

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

Redis 集群

Redis 集群的分片

问题答案
分片是什么使用 Redis 集群时我们会将存储的数据分散到多台 redis 机器上,这称为分片。简言之,集群中的每个 Redis 实例都被认为是整个数据的一个分片。
如何找到给定 key 的分片为了找到给定 key 的分片,我们对 key 进行 CRC16(key) 算法处理并通过对总分片数量取模。然后,使用确定性哈希函数,这意味着给定的 key 将多次始终映射到同一个分片,我们可以推断将来读取特定 key 的位置。

槽位 slot 和分片的优势

方便扩容和数据分派查找

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

slot 槽位映射,一般业界有 3 种解决方案

哈希取余分区

Redis 集群算法 哈希取余分区

2 亿条记录就是 2 亿个 k,v,我们单机无法承载这样规模的数据量,必须要分布式多机,假设有 3 台机器构成一个集群,用户每次读写操作都是根据公式:hash(key) % N 个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。

优点: 简单粗暴,直接有效,只需要预估好数据,规划好节点,例如 3 台,8 台,10 台,就能保证一段时间的数据支持。使用 Hash 算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡和分而治之的作用。

缺点: 原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3 会变成 Hash(key)/? 。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。某个 redis 机器宕机了,由于台数数量变化,会导致 hash 取余全部数据重新洗牌。

一致性哈希算法分区

概述

一致性哈希算法在 1997 年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数就会出错。

作用

提出一致性 Hash 解决方案。目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系。

步骤
  • 算法构建一致性哈希环

    一致性哈希算法必然有个 hash 函数并按照算法产生 hash 值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个 hash 空间 [0,2321][0,2^{32}-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连 (0=2320 = 2^{32}),这样让它逻辑上形成了一个环形空间。

    它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)的数量进行取模。而一致性 Hash 算法是对 2322^{32} 取模,简单来说,一致性 Hash 算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为 023210 ~ 2^{32}-1(即哈希值是一个 32 位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表 0,0 点右侧的第一个点代表 1,以此类推,2、3、4、……直到 23212^{32}-1,也就是说 0 点左侧的第一个点代表 23212^{32}-1, 0 和 23212^{32}-1 在零点钟方向重合,我们把这个由 2322^{32} 个点组成的圆环称为 Hash 环。

    Redis-一致性哈希算法-一致性哈希环

  • Redis 服务器 IP 节点映射

    将集群中各个 IP 节点映射到环上的某一个位置。

    将各个服务器使用 Hash 进行一个哈希,具体可以选择服务器的 IP 或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如 4 个节点 NodeA、B、C、D,经过 IP 地址的哈希函数计算(Hash(IP)),使用 IP 地址哈希后在环空间的位置如下:

    Redis-一致性哈希算法-节点映射

  • Key 落到服务器的落键规则

    当我们需要存储一个 KV 键值对时,首先计算 Key 的 Hash 值,Hash(Key),将这个 Key 使用相同的函数 Hash 计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。

    如我们有 Object A、Object B、Object C、Object D 四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性 Hash 算法,数据 A 会被定为到 Node A 上,B 被定为到 Node B 上,C被定为到 Node C上,D 被定为到 Node D 上。

    Redis-一致性哈希算法-落键规则

优点
  • 一致性哈希算法的容错性

    假设 Node C 宕机,可以看到此时对象 A、B、D 不会受到影响。一般的,在一致性 Hash 算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是 C 挂了,受到影响的只是 B、C 之间的数据且这些数据会转移到 D 进行存储

    Redis-一致性哈希算法-容错性

  • 一致性哈希算法的扩展性

    数据量增加了,需要增加一台节点 NodeX,X 的位置在 A 和 B 之间,那收到影响的也就是 A 到 X 之间的数据,重新把 A 到 X 的数据录入到 X 上即可,不会导致 Hash 取余全部数据重新洗牌。

    Redis-一致性哈希算法-扩展性

缺点

一致性哈希算法的数据倾斜问题

一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器:

Redis-一致性哈希算法-数据倾斜

总结

为了在节点数目发生改变时尽可能少的迁移数据,将所有的存储节点排列在收尾相接的 Hash 环上,每个 key 在计算 Hash 后会顺时针找到临近的存储节点存放;而当有节点加入或退出时仅影响该节点在 Hash 环上顺时针相邻的后续节点。

优点:加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。

缺点:数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果。

哈希槽分区

概述

为解决一致性哈希算法的数据倾斜问题,提出哈希槽的思想。哈希槽实质就是一个数组,数组 [0,2141][0,2^{14} -1] 形成 hash slot 空间。

作用

哈希槽分区解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。

Redis-哈希槽层示意图

槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。哈希解决的是映射问题,使用 Key 的哈希值来计算所在的槽,便于数据分配。

哈希槽数量

HASH_SLOT = CRC16(key) mod 16384

一个集群只能有 16384 个槽,编号 0-16383 (0,2141)(0,2^{14}-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。

集群会记录节点和槽的对应关系,解决了节点和槽的关系后,接下来就需要对 key 求哈希值,然后对 16384 取模,余数是几 key 就落入对应的槽里。HASH_SLOT = CRC16(key) mod 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

哈希槽计算

Redis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 CRC16 算法算出一个结果然后用结果对 16384 求余数 [ CRC16(key) % 16384],这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key 之 A 、B 在 Node2, key 之 C 落在 Node3 上。

Redis-集群

@Test
public void test() {
    // import io.lettuce.core.cluster.SlotHash;
    System.out.println(SlotHash.getSlot("A")); // 6373
    System.out.println(SlotHash.getSlot("B")); // 10374
    System.out.println(SlotHash.getSlot("C")); // 14503
    System.out.println(SlotHash.getSlot("Hello")); // 866
}

⭐️ 为什么 redis 集群的最大槽数是 16384 个

Redis 集群并没有使用一致性哈希而是引入了哈希槽的概念。Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。但为什么哈希槽的数量是 16384(2^14)个呢?

CRC16 算法产生的 hash 值有 16bit ,该算法可以产生 2^16=65536 个值。

换句话说值是分布在 0~65535 之间,有更大的 65536 不用为什么只用 16384 就够?

作者在做 mod 运算的时候,为什么不 mod65536,而选择 mod16384? HASH_SLOT = CRC16(key) mod 65536 为什么没启用

https://github.com/redis/redis/issues/2576 (opens in a new tab)

  • 说明 1

    正常的心跳数据包带有节点的完整配置,可以用幂等方式用旧的节点替换旧节点,以便更新旧的配置。

    这意味着它们包含原始节点的插槽配置,该节点使用 2k 的空间和 16k 的插槽,但是会使用 8k 的空间(使用 65k 的插槽)。

    同时,由于其他设计折衷,Redis 集群不太可能扩展到 1000个以上的主节点。

    因此 16k 处于正确的范围内,以确保每个主机具有足够的插槽,最多可容纳 1000 个矩阵,但数量足够少,可以轻松地将插槽配置作为原始位图传播。请注意,在小型群集中,位图将难以压缩,因为当 N 较小时,位图将设置的 slot/N 位占设置位的很大百分比。

  • 说明 2

    • 如果槽位为 65536,发送心跳信息的消息头达 8k,发送的心跳包过于庞大。

      在消息头中最占空间的是 myslots[CLUSTER_SLOTS/8]。 当槽位为 65536 时,这块的大小是: 65536÷8÷1024=8kb

      在消息头中最占空间的是 myslots[CLUSTER_SLOTS/8]。 当槽位为 16384 时,这块的大小是: 16384÷8÷1024=2kb

      因为每秒钟,redis 节点需要发送一定数量的 ping 消息作为心跳包,如果槽位为 65536,这个ping消息的消息头太大了,浪费带宽。

    • redis 的集群主节点数量基本不可能超过 1000 个。

      集群节点越多,心跳包的消息体内携带的数据越多。如果节点过 1000 个,也会导致网络拥堵。因此 redis 作者不建议 redis cluster 节点数量超过 1000 个。 那么,对于节点数在 1000 以内的 redis cluster 集群,16384 个槽位够用了。没有必要拓展到 65536 个。

    • 槽位越小,节点少的情况下,压缩比高,容易传输。

      Redis 主节点的配置信息中它所负责的哈希槽是通过一张 bitmap 的形式来保存的,在传输过程中会对 bitmap 进行压缩,但是如果 bitmap 的填充率 slots/N 很高的话(N 表示节点数),bitmap 的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap 的压缩率就很低。

  • 总结

    • 消息大小考虑:尽管 CRC16 能得到 65535 个值,但 redis 选择 16384 个 slot,是因为 16384 的消息头只占用了 2k,而 65535 则需要 8k。
    • 集群规模设计考虑:集群设计最多支持 1000 个分片,16384 是相对比较好的选择,需要保证在最大集群规模下,slot 均匀分布式场景下,每个分片平均分到的 slot 不至于太小。

    需要注意 2 个问题:

    • 为什么要传全量的 slot 状态? 因为分布式场景,基于状态的设计更合理,状态的传播具有幂等性。
    • 为什么不考虑压缩? 集群规模较小的场景下,每个分片负责大量的 slot,很难压缩。

Redis 集群不保证强一致性

Redis 集群不保证强一致性,这意味着在特定的条件下,Redis 集群可能会丢掉一些被系统收到的写入请求命令。

Write safety

Redis Cluster uses asynchronous replication between nodes, and last failover wins implicit merge function. This means that the last elected master dataset eventually replaces all the other replicas. There is always a window of time when it is possible to lose writes during partitions. However these windows are very different in the case of a client that is connected to the majority of masters, and aclient that is connected to the minority of masters.

集群环境案例步骤

使用 3 台虚拟机,各自新建

mkdir -p /myredis/cluster

3 主 3 从 redis 集群配置

  • 新建 6 个独立的 redis 实例服务

    Redis-集群案例

    • 192.168.111.175:6381 | vim /myredis/cluster/redisCluster6381.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6381
      logfile "/myredis/cluster/cluster6381.log"
      pidfile /myredis/cluster6381.pid
      dir /myredis/cluster
      dbfilename dump6381.rdb
      appendonly yes
      appendfilename "appendonly6381.aof"
      requirepass 111111
      masterauth 111111
       
      cluster-enabled yes
      cluster-config-file nodes-6381.conf
      cluster-node-timeout 5000
    • 192.168.111.175:6382 | vim /myredis/cluster/redisCluster6382.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6382
      logfile "/myredis/cluster/cluster6382.log"
      pidfile /myredis/cluster6382.pid
      dir /myredis/cluster
      dbfilename dump6382.rdb
      appendonly yes
      appendfilename "appendonly6382.aof"
      requirepass 111111
      masterauth 111111
       
      cluster-enabled yes
      cluster-config-file nodes-6382.conf
      cluster-node-timeout 5000
    • 192.168.111.172:6383 | vim /myredis/cluster/redisCluster6383.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6383
      logfile "/myredis/cluster/cluster6383.log"
      pidfile /myredis/cluster6383.pid
      dir /myredis/cluster
      dbfilename dump6383.rdb
      appendonly yes
      appendfilename "appendonly6383.aof"
      requirepass 111111
      masterauth 111111
      
      cluster-enabled yes
      cluster-config-file nodes-6383.conf
      cluster-node-timeout 5000
    • 192.168.111.172:6384 | vim /myredis/cluster/redisCluster6384.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6384
      logfile "/myredis/cluster/cluster6384.log"
      pidfile /myredis/cluster6384.pid
      dir /myredis/cluster
      dbfilename dump6384.rdb
      appendonly yes
      appendfilename "appendonly6384.aof"
      requirepass 111111
      masterauth 111111
       
      cluster-enabled yes
      cluster-config-file nodes-6384.conf
      cluster-node-timeout 5000
    • 192.168.111.174:6385 | vim /myredis/cluster/redisCluster6385.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6385
      logfile "/myredis/cluster/cluster6385.log"
      pidfile /myredis/cluster6385.pid
      dir /myredis/cluster
      dbfilename dump6385.rdb
      appendonly yes
      appendfilename "appendonly6385.aof"
      requirepass 111111
      masterauth 111111
       
      cluster-enabled yes
      cluster-config-file nodes-6385.conf
      cluster-node-timeout 5000
    • 192.168.111.174:6386 | vim /myredis/cluster/redisCluster6386.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6386
      logfile "/myredis/cluster/cluster6386.log"
      pidfile /myredis/cluster6386.pid
      dir /myredis/cluster
      dbfilename dump6386.rdb
      appendonly yes
      appendfilename "appendonly6386.aof"
      requirepass 111111
      masterauth 111111
       
      cluster-enabled yes
      cluster-config-file nodes-6386.conf
      cluster-node-timeout 5000
    • 启动 6 台 redis 主机实例

      redis-cli /myredis/cluster/redisCluster6381.conf
      redis-cli /myredis/cluster/redisCluster6382.conf
      redis-cli /myredis/cluster/redisCluster6383.conf
      redis-cli /myredis/cluster/redisCluster6384.conf
      redis-cli /myredis/cluster/redisCluster6385.conf
      redis-cli /myredis/cluster/redisCluster6386.conf
  • 通过 reids-cli 命令为 6 台机器构建集群关系

    • 构建主从关系命令

      redis-cli -a 111111 --cluster create --cluster-replicas 1 192.168.111.175:6381 192.168.111.175:6382 192.168.111.172:6383 192.168.111.172:6384 192.168.111.174:6385 192.168.111.174:6386
      # --cluster-replicas 1 表示为每个 master 创建一个 slave 节点
       
      [OK] All nodes agree about slots configuration.
      >>> Check for open slots...
      >>> Check slots coverage...
      [OK] All 16384 slots covered.
  • 连接进入 6381 作为切入点,查看并检验集群状态

    info replication
    cluster info
    cluster nodes

3 主 3 从 redis 集群读写

  • 对 6381 新增两个 key

    127.0.0.1:6381> set k1 v1
    (error) MOVED 12706 192.168.111.174:6385
    127.0.0.1:6381>
    127.0.0.1:6381> get k1
    (error) MOVED 12706 192.168.111.174:6385
    127.0.0.1:6381> set k2 V2
    OK
    127.0.0.1:6381> get k2
    "V2"
    127.0.0.1:6381>
  • 为什么报错

    注意槽位的范围区间,需要路由到位

  • 解决方案

    redis-cli 连接 redis-server 时增加参数 -c ,优化路由

    redis-cli -a password -p 6381 -c
  • 查看集群信息

    cluster nodes
  • 查看某个 key 该属于对应的槽位值

    192.168.111.175:6381> cluster keyslot k1
    (integer) 12706
    192.168.111.175:6381> cluster keyslot k2
    (integer) 449

主从容错切换迁移案例

Redis-集群主从切换

  • 容错切换迁移

    • 主机 6381 和从机切换,先停止主机 6381(为主机 6381 分配的从机以实际情况为准)
    • 使用命令 cluster nodes 查看集群信息
    • 停止主机 6381,再次查看集群信息;6384 成功上位并正常使用
    • 当 6381 重新上线后,6381 不会上位并以从节点形式回归
  • 集群不保证数据一致性 100% ,一定会有数据丢失情况。

    Redis 集群不保证强一致性,这意味着再特定的条件下,Redis 集群可能会丢失掉一些被系统收到的写入请求命令。

  • 手动故障转移或者节点从属调整该如何处理

    登录 6381 机器,使用命令 cluster failover 切换主从关系(主从关系拓扑图和原先的设计图保持一致)。

主从扩容案例

Redis-集群主机扩容

  • 新建 6387,6388 两个服务实例配置文件以及启动

    • vim /myredis/cluster/redisCluster6387.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6387
      logfile "/myredis/cluster/cluster6387.log"
      pidfile /myredis/cluster6387.pid
      dir /myredis/cluster
      dbfilename dump6387.rdb
      appendonly yes
      appendfilename "appendonly6387.aof"
      requirepass 111111
      masterauth 111111
      
      cluster-enabled yes
      cluster-config-file nodes-6387.conf
      cluster-node-timeout 5000
    • vim /myredis/cluster/redisCluster6388.conf

      bind 0.0.0.0
      daemonize yes
      protected-mode no
      port 6388
      logfile "/myredis/cluster/cluster6388.log"
      pidfile /myredis/cluster6388.pid
      dir /myredis/cluster
      dbfilename dump6388.rdb
      appendonly yes
      appendfilename "appendonly6388.aof"
      requirepass 111111
      masterauth 111111
       
      cluster-enabled yes
      cluster-config-file nodes-6388.conf
      cluster-node-timeout 5000
  • 将新增的 6387 节点作为 master 加入原集群

    # 6387 就是将要作为 master 新增节点,6381 就是原来集群节点里面的领路人
    redis-cli -a 111111 --cluster add-node 192.168.111.174:6387 192.168.111.175:6381
    ...
    [OK] All nodes agree about slots configuration.
    >>> check for open slots...
    >>> check slots coverage...
    [OK] All 16384 slots covered.
    >>> Getting functions from cluster
    >>> Send FUNCTION LIST to 192.168.111.174:6387 to verify there is no functions in it
    >>> Send FUNCTION RESTORE to 192.168.111.174:6387
    >>> Send CLUSTER MEET to node 192.168.111.174:6387 to make it join the cluster.
    [OK] New node added correctly
  • 检查集群情况第一次

    redis-cli -a 111111 --cluster check 192.168.111.175:6381

    注意查看哈希槽分配情况。

  • 重新分派槽号(reshard

    redis-cli -a 111111 --cluster reshard 192.168.111.175:6381
  • 检查集群情况第二次

    redis-cli -a 111111 --cluster check 192.168.111.175:6381

    为什么 6387 是 3 个新的区间,以前的还是连续?

    重新分配成本太高,所以前 3 家各自匀出来一部分,从 6381/6383/6385 三个旧节点分别匀出 1364 个坑位给新节点 6387。

  • 为主节点 6387 分配从节点 6388

    redis-cli -a 111111 --cluster add-node 192.168.111.174:6388 192.168.111.174:6387 --cluster-slave --cluster-master-id 4feb6a7ee0ed2b39ff86474cf4189ab2a554a40f-------这个是6387的编号,按照自己实际情况
  • 检查集群情况第三次

    redis-cli -a 111111 --cluster check 192.168.111.175:6381

主从缩容案例

  • 目的:6387 和 6388 下线

  • 检查集群情况第一次,先获得从节点 6388 的节点 ID

    redis-cli -a 111111 --cluster check 192.168.111.174:6388
  • 从集群中将 4 号从节点 6388 删除

    redis-cli -a 111111 --cluster del-node 192.168.111.174:6388 218e7b8b4f81be54ff173e4776b4f4faaf7c13da
    
    redis-cli -a 111111 --cluster check 192.168.111.174:6385
  • 将 6387 的槽号清空,重新分配,本例将清出来的槽号都给了 6381

    redis-cli -a 111111 --cluster reshard 192.168.111.175:6381
  • 检查集群情况第二次

    redis-cli -a 111111 --cluster check 192.168.111.175:6381
    # 4096个槽位都指给6381,它变成了8192个槽位,相当于全部都给6381了,不然要输入3次
  • 将 6387 删除

    redis-cli -a 111111 --cluster del-node 192.168.111.174:6387 4feb6a7ee0ed2b39ff86474cf4189ab2a554a40f
  • 检查集群情况第三次,6387/6388 被彻底剔除

    redis-cli -a 111111 --cluster check 192.168.111.175:6381

集群常用操作命令和 CRC16 算法分析

  • 不在同一个 slot 槽位下的多键操作支持不好,通识占位符的提出

    127.0.0.1:6381> set k1 v1
    -> Redirected to slot [12706] located at 192.168.111.174:6385
    OK
    192.168.111.174:6385> set k2 v2
    -> Redirected to slot [449] located at 192.168.111.175:6381
    OK
    192.168.111.175:6381> set k3 v3
    OK
    192.168.111.175:6381> keys *
    1) "k3"
    2) "k2"
    192.168.111.175:6381> mget k1 k2 k3
    (error) CROSSSLOT Keys in request don't hash to the same slot
    192.168.111.175:6381> mset k1 11 k2 12 k3 13
    (error) CROSSSLOT Keys in request don't hash to the same slot
    192.168.111.175:6381> mset k1{x} 11 k2{x} 12 k3{x} 13
    -> Redirected to slot [16287] located at 192.168.111.174:6385
    OK
    192.168.111.174:6385> get k1{x} k2{x} k3{x}
    1) "11"
    2) "12"
    3) "13"
    192.168.111.174:6385>
    • 不在同一个 slot 槽位下的键值无法使用 mset、mget 等多键操作;

    • 可以通过 {} 来定义同一个组的概念,使 key 中 {} 内相同内容的键值对放到一个 slot 槽位去,对照下图类似 k1k2k3 都映射为 x,自然槽位一样。

  • Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽。集群的每个节点负责一部分 Hash 槽

    cluster.c 源码分析一下看看

  • 常用命令

    • 集群是否完整才能对外提供服务

      cluster-require-full-coverage yes

      默认 YES,现在集群架构是 3 主 3 从的 redis cluster 由 3 个 master 平分 16384 个 slot,每个 master 的小集群负责 1/3 的 slot,对应一部分数据。

      cluster-require-full-coverage: 默认值 yes,即需要集群完整性,方可对外提供服务 通常情况,如果这 3 个小集群中,任何一个(1主1从)挂了,你这个集群对外可提供的数据只有 2/3 了, 整个集群是不完整的, redis 默认在这种情况下,是不会对外提供服务的。

      如果你的诉求是,集群不完整的话也需要对外提供服务,需要将该参数设置为 no,这样的话你挂了的那个小集群是不行了,但是其他的小集群仍然可以对外提供服务。

    • CLUSTER COUNTKEYSINSLOT <SLOT-NUMBER>

      • 1,该槽位被占用
      • 0,该槽位没占用
    • CLUSTER KEYSLOT <KEY-NAME>

      该键应该存在哪个槽位上