19.Redis之集群

1.集群的基本介绍

  • 集群 这个词.
  • 广义的集群,只要你是多个机器,构成了分布式系统, 都可以称为是一个"集群"前面主从结构,哨兵模式,也可以称为是"广义的集群"
  • 狭义的集群,redis 提供的集群模式, 这个集群模式之下,主要是要解决,存储空间不足的问题(拓展存储空间)

哨兵模式提高了系统的可用性

哨兵模式中,本质上还是 redis 主/从节点(内存,256G,512G.上 TB 的服务器也不是没有(贵))存储数据,其中就要求一个主节点/从节点,就得存储整个数据的"全集

  • 此处关键问题,就是引入多台机器,每台机器存储一部分数据,
  • 设 有 1TB 的数据需要存储.
  • 拿两台机器来存,每个机器只需要存 512GB 即可.
  • 拿三台机器来存,每个机器只需要存 300 多 GB 即可,
  • 拿四台机,器来存,每个机器只需要存 256GB.....
  • 随着机器数目的增加,每个机器存储的数据量就减少了
  • 【只要机器的规模足够多,就可以存储任意大小的数据了,(公司的实力)】
  • 【不是说光搞3个机器就够了每个存储数据的机器还需要搭配若于个从节点】

2.如何把数据分成多分?

  • 把数据分成多份,应该怎么分?
  • 是一个 分片(sharding).
  • 三种主流的分片方式,

1.哈希求余

  • 借鉴了哈希表的基本思想.
    借助 hash 函数,把一个 key 映射到整数,再针对数组的长度
    求余,就可以得到一个数组下标.
  • 比如有三个分片,编号 012
    此时就可以针对要插入的数据的 key(redis 都是 键值对 结构的数据)计算 hash 值.(比如,使用 md5)【md5 本身就是一个计算 hash 值的算法针对一个字符串,里面的内容进行一系列的数学变换 =>整数.】再把这个 hash 值余上分片个数,就得到了一个下标,此时就可以把这个数据放到该下标对应的分片中了.
  • 【缺陷】
  • 一旦服务器集群需要扩容,就需要更高的成本了
    分片主要目的就是为了能提高存储能力.
    分片越多,能存的数据越多,成本也更高,
  • 一般都是先少搞几个分片.(3 个)
    但是随着业务逐渐增长,数据变多了~~3 个分片就已经不足以保存了
  • 就需要"扩容"
    引入新的分片,N 就改变了
    hash(key)% N >=0
  • 当 hash 函数和 key 都不变的情况下,如果 N 改变了整体的分片结果仍然会变!!
  • 如果发现某个数据,在扩容之后,不应该待在当前的分片中了,就需要重新进行分配 (搬运数据)
  • 此处列出的这些值,就可以脑补成 hash(key)假设当前计算完 hash 值之后,得到的 数值正好是 100-120
  • 共 20 个数据,只有 3 个数据不需要搬运~~ 搬运了 17 个数据如果是 20 亿 个数据呢?? 17 亿数据就要搬运...这就是一个大活了!!
  • 上述级别的扩容,开销极大的,往往是不能直接在生产环境上操作的,只能通过"替换"的方式来实现扩容。
  • 依赖的机器更多了.成本更高,操作步骤非常复杂!!!

2.一致性哈希算法

  • 会导致数据不均匀的问题
  • 此时, 只需要把 0 号分⽚上的部分数据, 搬运给 3 号分⽚即可. 1 号分⽚和 2 号分⽚管理的区间都是不变的.
  • 优点: ⼤⼤降低了扩容时数据搬运的规模, 提⾼了扩容操作的效率.
  • 缺点: 数据分配不均匀 (有的多有的少, 数据倾斜).

3.哈希槽分区算法

  • 【问题1】
  • Redis 集群是最多有 16384 个分片吗?
  • 每个分片上就只有一个槽位.(此时很难保证数据在各个分片上的均衡性~~)(有的槽位可能是 有多个 key,有的槽位可能是 没有 key ~)
  • key 是要先映射到槽位,再映射到分片的
  • 如果每个分片包含的槽位比较多,如果槽位个数相当, 就可以认为是包含的 key 数量相当的:
  • 如果每个分片包含的槽位非常少,槽位个数不一定能直观的反应到 key 的数目
  • 实际上 Redis 的作者建议集群分片数不应该超过(1000.
  • 如果真是1.6w 个分片,整个数据服务器的集群规模就太可怕了
  • 几万台主机构成的集群了.整个集群的可用性是非常堪忧的!!
  • 【问题2】
  • 问题二: 为什么是 16384 个槽位?
  • 心跳包中包含了该节点持有哪些 slots.
  • 需要表示出该节点持有哪些槽位
  • 虽然 8kb 比2kb 也大不了多少, 但是心跳包,周期性通信的.(非常频繁 & 网络带宽
  • 这个值个数上基本够用了.同时占用的硬件资源(网络带宽)又不是很大

3.搭建集群环境

3.1 生成配置文件

  • 基于 docker 在咱们云服务器上搭建出一个 redis 集群出来.
  • 当前阶段,主要是因为咱们只有一个 云服务器,搞分布式系统, 就比较麻烦
  • 实际工作中,一般是通过多个主机的方式,来搭建集群的,
第⼀步: 创建⽬录和配置

创建 redis-cluster ⽬录. 内部创建两个⽂件

一定要记得,把之前启动 redis 容器,给停止掉!!
  • 在 linux 上,以 .sh 后缀结尾的文件,称为"shell(脚本)【剧本,也可以称为脚本,】
  • 使用 linux 的时候, 都是通过一些命令来进行操作的.
  • 使用命令操作,就非常适合把命令给写到一个文件中,批量化执行,
  • 同时,还能加入, 条件,循环,函数 等机制
  • 因此,就可以基于这些来完成更复杂的工作了
  • 需要创建 11 个 redis 节点.这些 redis 的配置文件内容,大同小异.
  • 此时就可以使用脚本来批量生成.(也可以不使用脚本,手动一个一个改)
  • generate.sh 内容如下
  for port in $(seq 1 9); \
  do \
  mkdir -p redis${port}/
  touch redis${port}/redis.conf
  cat << EOF > redis${port}/redis.conf
  port 6379
  bind 0.0.0.0
  protected-mode no
  appendonly yes
  cluster-enabled yes
  cluster-config-file nodes.conf
  cluster-node-timeout 5000
  cluster-announce-ip 172.30.0.10${port}
  cluster-announce-port 6379
  cluster-announce-bus-port 16379
  EOF
  done
  # 注意 cluster-announce-ip 的值有变化. 
  for port in $(seq 10 11); \
  do \
  mkdir -p redis${port}/
  touch redis${port}/redis.conf
  cat << EOF > redis${port}/redis.conf
  port 6379
  bind 0.0.0.0
  protected-mode no
  appendonly yes
  cluster-enabled yes
  cluster-config-file nodes.conf
  cluster-node-timeout 5000
  cluster-announce-ip 172.30.0.1${port}
  cluster-announce-port 6379
  cluster-announce-bus-port 16379
  EOF
  done
  • 成功!!!

3.2 创建容器

编写 docker-compose.yml

  version: '3.3'
  networks:
    mynet:
      ipam:
        config:
          - subnet: 172.30.0.0/24
  services:
    redis1:
      image: 'redis:5.0.9'
      container_name: redis1
      restart: always
      volumes:
        - ./redis1/:/etc/redis/
      ports:
        - 6371:6379
        - 16371:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.101
    redis2:
      image: 'redis:5.0.9'
      container_name: redis2
      restart: always
      volumes:
        - ./redis2/:/etc/redis/
      ports:
        - 6372:6379
        - 16372:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.102
    redis3:
      image: 'redis:5.0.9'
      container_name: redis3
      restart: always
      volumes:
        - ./redis3/:/etc/redis/
      ports:
        - 6373:6379
        - 16373:16379
  command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.103
    redis4:
      image: 'redis:5.0.9'
      container_name: redis4
      restart: always
      volumes:
        - ./redis4/:/etc/redis/
      ports:
        - 6374:6379
        - 16374:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.104
    redis5:
      image: 'redis:5.0.9'
      container_name: redis5
      restart: always
      volumes:
        - ./redis5/:/etc/redis/
      ports:
        - 6375:6379
        - 16375:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.105
    redis6:
      image: 'redis:5.0.9'
      container_name: redis6
      restart: always
      volumes:
        - ./redis6/:/etc/redis/
      ports:
        - 6376:6379
        - 16376:16379
  command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.106
    redis7:
      image: 'redis:5.0.9'
      container_name: redis7
      restart: always
      volumes:
        - ./redis7/:/etc/redis/
      ports:
        - 6377:6379
        - 16377:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.107
    redis8:
      image: 'redis:5.0.9'
      container_name: redis8
      restart: always
      volumes:
        - ./redis8/:/etc/redis/
      ports:
        - 6378:6379
        - 16378:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.108
    redis9:
      image: 'redis:5.0.9'
      container_name: redis9
      restart: always
      volumes:
        - ./redis9/:/etc/redis/
      ports:
        - 6379:6379
        - 16379:16379
  command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.109

    redis10:
      image: 'redis:5.0.9'
      container_name: redis10
      restart: always
      volumes:
        - ./redis10/:/etc/redis/
      ports:
        - 6380:6379
        - 16380:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.110
    redis11:
      image: 'redis:5.0.9'
      container_name: redis11
      restart: always
      volumes:
        - ./redis11/:/etc/redis/
      ports:
        - 6381:6379
        - 16381:16379
      command:
        redis-server /etc/redis/redis.conf
      networks:
        mynet:
          ipv4_address: 172.30.0.111


*

3.3 配置集群关系

1)生成每个 redis 节点的配置文件

2)使用 docker 创建出 11 个 redis 节点, 并且启动容器

3)使用 redis-cli 执行构建集群命令

redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379 172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379 172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379 --cluster-replicas 2

3.4 使用集群

  • redis-cli -h 172.30.0.101 -p 6379

4.故障处理

5.集群扩容

101-1099个主机,构成了3主,6 从结构的集群了

110 和 111 也加入到集群中

以110为 master, 111为 slave.=>把数据分片从 3->4

集群扩容操作,是一件风险较高,成本较大的操作!!!

1.新的主节点(110) 加入到集群中

redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379

2.重新分配 slots

redis-cli --cluster reshard 172.30.0.101:6379

3.给新的主节点添加从节点

光有主节点了, 此时扩容的⽬标已经初步达成. 但是为了保证集群可⽤性, 还需要给这个新的主节点添加从节点, 保证该主节点宕机之后, 有从节点能够顶上

redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave --cluster-master-id c999d6e82415680b57868cc3c59f9f1a779a59cd

6.集群的缩容

把一些节点拿掉,减少分片的数量,

般都是进行扩容,很少缩容!

7.小结

1)集群是什么,解决了什么问题?

2)数据分片算法[重点/考点]

a)哈希求余

b)一致性哈希算法

c)哈希槽分区算法(redis)

3)搭建 redis 集群,

4)集群容灾.故障转移

5)集群扩容.

6)代码连接集群

使用的库, 得能够支持 集群模式.

相关推荐
学会沉淀。几秒前
Docker学习
java·开发语言·学习
如若1231 分钟前
对文件内的文件名生成目录,方便查阅
java·前端·python
PyAIGCMaster3 分钟前
文本模式下成功。ubuntu P104成功。
服务器·数据库·ubuntu
xo1988201110 分钟前
鸿蒙人脸识别
redis·华为·harmonyos
drebander15 分钟前
MySQL 查询优化案例分享
数据库·mysql
初晴~31 分钟前
【Redis分布式锁】高并发场景下秒杀业务的实现思路(集群模式)
java·数据库·redis·分布式·后端·spring·
盖世英雄酱5813636 分钟前
InnoDB 的页分裂和页合并
数据库·后端
黑胡子大叔的小屋1 小时前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark1 小时前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
雷神乐乐2 小时前
Spring学习(一)——Sping-XML
java·学习·spring