go-redis hash slot 之旅

搭建redis 集群

  1. 创建一个网桥
docker network create -d bridge --subnet=192.168.148.0/24 --gateway=192.168.148.1 -o parent=eno1 redis-net
  1. 通过docker 文件创建redis 集群, 这里注意要不要使用redis 7以上的版本,不然会出问题
version: "3"
 
services:
  redis7001:
    image: redis:6.2.14 # 指定redis镜像,可以是name:tag/id
    container_name: redis7001 # 启动后的镜像名称,可有可无
    ports:
      - "7001:7001" # 指定对外端口
      - "17001:17001" # 指定集群端口,根据官网一般为对外端口+10000
    volumes:
      # 挂载主机中的配置文件
      - /home/duron/docker/redis_cluster/redis.conf:/conf/redis.conf
      # 将数据保存在主机上, 防止丢失
      - /home/duron/docker/redis_cluster/7001:/data
    command:
      # 默认的redis启动命令
      - "redis-server"
      # 加载指定的配置文件,这里是镜像内的路径
      - "/conf/redis.conf"
      # 对外端口号,也可以在redistribution.conf中配置
      - "--port 7001"
      # 开启redis集群模式,也可以在redistribution.conf中配置
      - "--cluster-enabled yes"
      # 集群节点配置文件名,也可以在redistribution.conf中配置
      - "--cluster-config-file nodes-7001.conf"
    networks:
      extnetwork:
        ipv4_address: 192.168.148.71 # 向桥接网络申请ip地址
 
  redis7002:
    image: redis:6.2.14
    container_name: redis7002
    ports:
      - "7002:7002"
      - "17002:17002"
    volumes:
      - /home/duron/docker/redis_cluster/redis.conf:/conf/redis.conf
      - /home/duron/docker/redis_cluster/7002:/data
    command:
      - "redis-server"
      - "/conf/redis.conf"
      - "--port 7002"
      - "--cluster-enabled yes"
      - "--cluster-config-file nodes-7002.conf"
    networks:
      extnetwork:
        ipv4_address: 192.168.148.72
 
  redis7003:
    image: redis:6.2.14
    container_name: redis7003
    ports:
      - "7003:7003"
      - "17003:17003"
    volumes:
      - /home/duron/docker/redis_cluster/redis.conf:/conf/redis.conf
      - /home/duron/docker/redis_cluster/7003:/data
    command:
      - "redis-server"
      - "/conf/redis.conf"
      - "--port 7003"
      - "--cluster-enabled yes"
      - "--cluster-config-file nodes-7003.conf"
    networks:
      extnetwork:
        ipv4_address: 192.168.148.73
 
  redis7004:
    image: redis:6.2.14
    container_name: redis7004
    ports:
      - "7004:7004"
      - "17004:17004"
    volumes:
      - /home/duron/docker/redis_cluster/redis.conf:/conf/redis.conf
      - /home/duron/docker/redis_cluster/7004:/data
    command:
      - "redis-server"
      - "/conf/redis.conf"
      - "--port 7004"
      - "--cluster-enabled yes"
      - "--cluster-config-file nodes-7004.conf"
    networks:
      extnetwork:
        ipv4_address: 192.168.148.74
 
  redis7005:
    image: redis:6.2.14
    container_name: redis7005
    ports:
      - "7005:7005"
      - "17005:17005"
    volumes:
      - /home/duron/docker/redis_cluster/redis.conf:/conf/redis.conf
      - /home/duron/docker/redis_cluster/7005:/data
    command:
      - "redis-server"
      - "/conf/redis.conf"
      - "--port 7005"
      - "--cluster-enabled yes"
      - "--cluster-config-file nodes-7005.conf"
    networks:
      extnetwork:
        ipv4_address: 192.168.148.75
 
  redis7006:
    image: redis:6.2.14
    container_name: redis7006
    ports:
      - "7006:7006"
      - "17006:17006"
    volumes:
      - /home/duron/docker/redis_cluster/redis.conf:/conf/redis.conf
      - /home/duron/docker/redis_cluster/7006:/data
    command:
      - "redis-server"
      - "/conf/redis.conf"
      - "--port 7006"
      - "--cluster-enabled yes"
      - "--cluster-config-file nodes-7006.conf"
    networks:
      extnetwork:
        ipv4_address: 192.168.148.76
 
 
networks:
  extnetwork: # 定义外部桥接网络
    external:
      name: redis-net

什么是redis cluster的hash slot

redis的hash槽在redis集群中的作用是用来将数据分配到不同的slot,来降低单个节点的压力,来保证redis的工作效率。

redis 是如何将key分配到不同的槽里的呢

redis 是同过CRC16 算法对数据进行hash取值然后在和16384 进行去模的到的slot的结果,我们在查询/存储key的时候会更具slot去获取数据或写入数据。

为什么要分配16384个

Redis 集群使用哈希槽(hash slot)来决定一个给定的键应该被分配到哪个节点。总共有 16384 个哈希槽,这个数字是一个折中的选择。

如果哈希槽的数量太少,例如只有 100 个,那么在大规模集群中,每个节点将需要处理大量的哈希槽,这可能会导致负载分布不均。另一方面,如果哈希槽的数量太多,例如 1 亿,那么管理这些哈希槽的开销将会非常大,尤其是在节点添加或删除时。

因此,16384 是一个在分布均匀性和管理开销之间取得平衡的数字。它足够大,可以在大规模集群中实现均匀的负载分布,同时又足够小,可以在节点变动时快速重新分配哈希槽。

为什么redis hash 槽要选择CRC16算法

  1. 计算速度快:CRC16 是一种非常简单的算法,计算速度非常快。这对于 Redis 这种需要处理大量键值对的数据库系统来说非常重要。

  2. 分布均匀:虽然 CRC16 是一种简单的算法,但它生成的哈希值在 0 到 16383 之间的分布是相当均匀的。这意味着键值对在 Redis 集群的各个节点之间的分布也会比较均匀。

redis 是如何获取slot的

1.) 在我们进行查询和写入操作的时候,代码在构建玩cmd的时候我们就进入了process函数,该函数的第一步就是先获取slot,红框中的代码就是获取到hash槽中的slot的值
go-redis hash slot 之旅_第1张图片
2.)我们进入到cmdSlot 函数里面我们就会发现,我们马上要开始获取slot了,在进入cmdFirstKeyPos获取到pos值以后我们就可以进入slot函数获取hash slot的值了(keyPos 字段是用来帮助 go-redis 库正确地处理 Redis 集群的一个重要字段。)
go-redis hash slot 之旅_第2张图片
3.)我们从这里就看到了hash slot的算法了,他正如我说的那样通过crc16算出hash值和16384 进行取模来获取我们需要通过那个slot来获取/写入数据
go-redis hash slot 之旅_第3张图片

获取到slot后我们如何获取连接呢?

1.) 我们通过代码可以看到在获取到slot后,我们会进入一个cmdNode的一个函数里面,我们就是通过slot值在这个函数里面获取到node 节点的。
go-redis hash slot 之旅_第4张图片
2.)我们进入cmdNode 可以看出来,这个函数给我们做了读写分离,因为我们没有开启读写分离,所以我们默认会进入slotMasterNode里面
go-redis hash slot 之旅_第5张图片
3.) 我们进入这个函数可以看到,我们通过sloaNodes来获取slot 如果nodes获取失败 = 0的情况下 我们默认走了random模式 默认随机了
go-redis hash slot 之旅_第6张图片
4. )该函数我们可以看出来,这个函数判断了我们的slot是否在这些nodes 里面,如果在并获取这个节点的节点信息。
go-redis hash slot 之旅_第7张图片

注意:

以上代码是在"github.com/redis/go-redis/v9" v9版本的支持下进行的,如果我们使用的是v6版本,我们会发现在我们进行slot 获取的时候会报错,报错会存储到firstErr的一个字段里面,这时候系统监测到该字段有错误,就会默认进行 随机获取slot的一个操作。

redis: got 7 elements in COMMAND reply, wanted 6

所以我们如果想使用hash slot 就需要升级到高一些的版本。

你可能感兴趣的:(redis,golang,redis,哈希算法)