深入Redis:复杂的集群

news2024/9/25 9:37:57

广义的集群,可能说只要是多台机器组成了分布式系统,就可以称之为集群。

狭义的集群,指的是Redis提供的集群模式,这个集群模式之下,主要是解决存储空间不足的问题,以及如何拓展存储空间。

之前的哨兵模式,本质上还是一个节点存储数据,要求一个主节点/从节点存储整个数据的“全集”。

假设有1TB的数据,拿两台机器和四台机器来存,每台机器就只需要存储512G和256G,只要机器的规模足够多就可以存储任意大小的数据了。

但是此处把数据分成多份,应该怎么分?

分片(Sharding)

  • Master1 和 Slave11 和 Slave12保存的是同样的数据,占总数据的1/3
  • Master2 和 Slave21 和 Slave22保存的是同样的数据,占总数据的1/3
  • Master3 和 Slave31 和 Slave32保存的是同样的数据,占总数据的1/3

这三组数据存储的数据都是不同的,每个红框的部分可以称之为一个分片。如果全量数据进一步增加,只需要再增加更多的分片就可以解决。

具体来说,如何分片?存储一个key的时候,这个数据应该存储再哪个分片上?读取的时候又应该去哪个分片读取?有比较主流的三个方式:

哈希求余

借鉴了哈希表的基本思想,用hash函数把一个key映射到整数,再针对数据的长度求余,就可以得到一个数组下标。

假设有个key,现在有3个分片。根据这个key来计算hash值,再把这个结果%3,结果是多少就分到哪个片区上。后续获取key的时候,也是针对这个key求hash,再对N求余,就可以找到对应的片区编号了。

优点:简单高效,数据分配均匀

缺点:一旦需要进行扩容,片区数目改变了,原有的映射规则就不起作用了。所有的查询操作都查不到key。此时要进行数据之间的片区转移,重新排列,以满足新的映射规则。这样的数据转移,资源消耗量极大。

如上可以看到,整个扩容一共21个key,只有3个key没有进行搬运,其他的都要搬运。

一致性哈希算法

为了改进上面的方法,能够高效进行扩容,“一致性哈希算法”就诞生了。

我们把2^32 -1均匀地映射到一个圆环上面,并且规律的切分好1号分片,2号分片,3号分片。

此时有一个key,计算这个key的hash值,算出来的值顺时针往下找,找到的第一个分片是哪个就属于哪个分片。

扩容的时候,原有的分片在环上的位置不动,只需要在环上安排一个新的分片即可。此时只需要把原来分片里面的部分数据,搬运给新的分片即可。剩下两个分片里面的数据和区间都是不变的。

优点:大大降低了扩容的时候数据搬运的规模,提高了扩容操作的效率。

缺点:数据分配不均匀,数据倾斜。

哈希槽分区算法

为了解决搬运成本高和数据分配不均匀,引入了哈希槽(hash slots)算法。

 hash_slot = crc16(key) % 16384
  哈希槽    计算hash的算法

、相当于把整个哈希值,映射到16384个槽位上,也就是[0,16383]。

再把这些槽位均匀的分配给每个分片,每个分片的节点都需要自己记录持有哪些分片。

假设当前有三个分片,一种可能的分配方式:

  • 0号分片:[0,5461],共5462个槽位
  • 1号分片:[5462,10923],共5462个槽位
  • 2号分片:[10924,16383],共5460个槽位

这里的分片规则是很灵活的,每个分片持有的槽位也不⼀定连续,每个分片的节点使用位图来表示自己持有哪些槽位。对于16384个槽位来说,需要2048个字节(2KB)大小的内存空间表示。

如果需要增加一个分片,就可以针对原来的槽位进行重新分配,比如把之前每个分片持有的槽位,各拿出来一点,分给新的分片。

  • 0号分片:[0, 4095],共4096个槽位。
  • 1号分片:[5462, 9557],共4096个槽位。
  • 2号分片:[10924, 15019],共4096个槽位。
  • 3号分片:[4096, 5461] + [9558, 10923] + [15019, 16383],共4096个槽位。

在实际使用Redis集群分片的时候,我们不需要手动指定哪些槽位分配给某个分片,只需要告诉某个分片应该持有多少个槽位即可。Redis会自动完成后续的槽位分配,以及对应的key搬运工作。

问题一:Redis集群是最多有16384个分片吗?

如果一个分片只有一个槽位,这对于集群的数据均匀是难以保证的。Redis作者建议分片数不应该超过1000。

问题二:为什么是16384个槽位?

Redis作者的回答:

节点之间通过心跳包通信。心跳包中包含了该节点持有哪些slots,这个是使用位图这样的数据结构表示的。表示16384(16k)个slots,需要的位图大小是2KB。如果给定的slots数更多了,比如65536个了,此时就需要消耗更多的空间,8KB位图表示了。8KB对于内存来说不算什么,但是在频繁的网络心跳包中,还是一个不小的开销。

另一方面,Redis集群一般不建议超过1000个分片。所以16k对于最大1000个分片来说是够用的,同时也会使对应的槽位配置位图体积不至于很大。

集群搭建

集群搭建基于docker,搭建一个集群,每一个节点都是一个容器。只需要创建11个redis节点,这些redis的配置文件内容大同小异。但是11个如果要手动添加的话太繁琐了,此时就可以使用脚本来批量生成。在Linux上,以 .sh 为后缀结尾的文件,称为“shell脚本”。

首先要停止原来启动的节点。分别到redis-data和redis-sentinel文件夹里,启动运行docker-compose down 命令就可以停止掉原来的docker容器。

在redis文件夹中创建reids-cluster,内部创建好两个文件,再把.sh文件的内容完成,就可以通过bash命令启动.sh文件了。很方便的,11个redis文件夹就被创建出来了。

#!/bin/bash

# 创建Redis实例目录并生成配置文件
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 的值有变化

# 创建额外的Redis实例目录并生成配置文件
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

每个redis文件夹中都有一个redis.conf文件,并且每个配置文件都不同。区别在于每个配置中的cluster-announce-ip都是不同的,其他部分都相同。这里的ip要和yml中的ip对应上。

当我们确认docker和redis都关闭后,此时执行启动容器的命令,就可以看到11个redis服务器都被启动起来了。

但是到此,我们还没有把这些redis配置成集群,他们还只是各干各的。

通过命令可以把前9个主机构建成集群,后两个主机暂时不用:

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
最后一串字符指的是:从节点2个

此时,redis节点被自动分配好了主节点和从节点,并且会自动分配好16384个槽位。此时101-109九个节点,是一个整体。使用客户端连接上任意一个节点,本质上都是等价的。

cluster nodes 
查看当前集群的信息

设置成集群模式之后,当前数据就分片了。可以在启动redis-cli的时候,加上 -c 选项,客户端发现当前key的操作不在当前分片上的时候,就能够自动的重定向到对应的分片主机。

但是也需要注意,如果key是分散在不同的分片上,用之前的操作就可能会有些问题。

故障转移

此处的故障转移,和哨兵那里的还不太一样~手动停止一个主节点,来观察效果。

集群中的所有节点都会周期性的使用心跳包进行通信。进行一系列判定之后,最终才会把某个节点标记成FAIL(客观下线)。

如果我们停掉了主节点1,此时会有一个slave节点变成新的主节点,哪怕我们重新启动原来的主节点1,这个节点也仅仅是变成slave。

Reft算法

上述选举的过程就称之为Raft算法,这是一种在分布式系统中广泛使用的算法。再随机休眠时间的加持下,基本上就是谁先唤醒,谁就能竞选成功。

集群扩容

现在101-109,9个主机构成了3主6从结构的集群了。此时我们把110和111主机也加入到集群中去,以110为master,111为slave,把数据分片从3变成4。

集体扩容是一件风险高、成本高的操作!

把新的主节点加入到集群

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

add-node后的第⼀组地址是新节点的地址,第⼆组地址是集群中的任意节点地址。

重新分配slots

 redis-cli --cluster reshard 172.30.0.101:6379

reshard后的地址是集群中的任意节点地址。

执行之后,会进入交互式操作,redis会提示输入以下内容: 

  • 多少个slots要进行reshard?(此处我们填写4096)
  • 哪个节点来接收这些slots?(此处我们填写 172.30.0.110 这个节点的集群节点id) 
  • 这些slots从哪些节点搬运过来?(此处我们填写all,表示从其他所有的节点都进行搬运)

给新的主节点添加从节点

redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster
slave --cluster-master-id [172.30.1.110 节点的nodeId]

此外,还有集群缩容,代码连接集群等知识,考虑到本文篇幅就不再继续了,接下来,我们会开启缓存的学习~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2126247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++中string的简单实现

string的简单实现中一些函数的实现可以复用一些其他的函数来实现&#xff1b;比较重要的是在实现是深浅拷贝问题 目录 string的结构 实现构造和析构 reserve扩容 容量 push_back和append insert和erase的实现 swap的实现&#xff08;不是成员函数但是string类的友元&…

【c++】类和对象详解

✅博客主页:爆打维c-CSDN博客​​​​​​ &#x1f43e; &#x1f539;分享c语言知识及代码 来都来了! 点个赞给博主个支持再走吧~&#xff01; 一.类的定义 &#xff08;1&#xff09;类定义格式 class为类定义的关键字&#xff0c;定义一个类格式如下: class 类名{//代码…

kubelet 探针

目录 1 k8s中kubelet 探针的介绍 1.1 探针是由 kubelet 对容器执行的定期诊断: 1.2 Kubelet 可以选择是否执行在容器上运行的三种探针执行和做出反应&#xff1a; 1.3 ReadinessProbe 与 LivenessProbe 的区别 1.4 StartupProbe 与 ReadinessProbe、LivenessProbe 的区别 2 实…

CCRC-DSA数据安全评估师:网络安全风险评估

1.网络安全风险评估概述 1.1概念 在当今信息化时代&#xff0c;网络安全成为了组织不可或缺的一部分。 风险评估作为一种科学方法&#xff0c;其目的是对网络系统的保密性、完整性、可控性和可用性这四个核心安全属性进行深入分析。 这一过程不仅包括识别网络系统中存在的脆…

Snipaste无法使用F1、F3等快捷键的保姆级解决方法

在Snipaste中按F1、F3等快捷键无效的可能原因&#xff1a; 1. 软件设置&#xff1a; 检查Snipaste的设置&#xff0c;确保F1被正确设置为截屏热键&#xff0c;并确认没有其他软件占用或冲突。 2. 热键冲突&#xff1a; 笔记本电脑的功能键&#xff08;F1-F12&#xff09;通常…

MySQL 数据库:原理、应用与发展

摘要&#xff1a;本文深入探讨了 MySQL 数据库相关内容。首先介绍了 MySQL 作为开源关系型数据库管理系统的显著特点&#xff0c;包括易用性、跨平台性、高性能、可扩展性、开源免费以及数据安全性等方面。接着详细阐述了其安装与配置过程&#xff0c;涵盖在不同操作系统上的安…

STM32使用 :串口的接收与发送

一、串口 在 STM32 中&#xff0c;串口&#xff08;UART&#xff0c;通用异步收发传输器&#xff09;是用于串行通信的外设。它在嵌入式系统中的作用非常广泛&#xff0c;主要包括几个方面 数据通信 串口用于微控制器与其他设备之间的数据传输。这些设备可以是其他微控制器、…

F12抓包08:查看网站Cookie

课程大纲 1、查看Cookie 1. 应用界面查看&#xff1a;按F12进入浏览器的开发者模式 - “应用”&#xff08;Application&#xff09; - Cookie&#xff0c;可查看Cookie并进行增、删、改、查操作。 2. 控制台命令行查看&#xff1a;按F12进入浏览器的开发者模式 - “控制台”&…

【无标题】nginx服务器代码信息、数据库连接信息、敏感文件的路径、服务器版本信息发起有针对性的攻击

Nginx敏感文件的路径、服务器版本信息 Nginx 403、404、500等错误时&#xff0c;返回详细错误信息。报错信息中可能会包含服务器代码信息、数据库连接信息、敏感文件的路径、服务器版本信息等&#xff0c;攻击者可以利用这些信息来寻找已知的漏洞&#xff0c;从而发起有针对性…

『功能项目』管理器基类【38】

我们打开上一篇37单例模式框架的项目&#xff0c; 本章要做的事情是编写管理器基类 首先创建脚本&#xff1a;ManagerBase.cs using UnityEngine; public abstract class ManagerBase : MonoBehaviour{public virtual void Init() { } } public class ManagerBase<T> : …

【Qt系列样式表】探索Qt Widget的艺术化设计与应用(Macos风格)(持续更新中...)

✨✨ Rqtz 个人主页 : 点击✨✨ &#x1f308;Qt系列专栏:点击 &#x1f388;PyQt系列专栏:点击&#x1f388; &#x1f388;Qt智能车上位机专栏: 点击&#x1f388; &#x1f388;Qt串口助手专栏:点击&#x1f388; &#x1f4ab;宗旨:共享IT之美,共创机器未来 目录 界面…

毕业论文word页眉页脚和页码的问题

多找B站视频查看视频操作方法。 问题1&#xff1a; 不同章节的页眉显示不同内容。 解决办法&#xff1a; “布局”里面插入分节符 &#xff08;非 分页符。&#xff09; 问题2&#xff1a; 页眉需要奇偶页内容不同 解决办法&#xff0c;编辑页眉部分&#xff0c;设置 奇偶页…

Qt (15)【Qt窗口 —— 字体对话框 QFontDialog | 输入对话框 QInputDialog】

阅读导航 引言一、字体对话框 QFontDialog1. 简介2. 基本用法3. 示例代码 二、输入对话框 QInputDialog1. 简介2. 基本用法&#xff08;1&#xff09;双精度浮点型输入数据对话框&#xff08;2&#xff09;整型输入数据对话框&#xff08;3&#xff09;选择条目型输入数据框 3.…

李沐对大模型趋势的几点判断

李沐是上海交通大学 2011 届计算机科学与工程系本硕系友。他曾担任亚马逊资深首席科学家&#xff0c;加州大学伯克利分校和斯坦福大学的访问助理教授&#xff0c;是前 Marianas Labs 联合创始人&#xff0c;深度学习框架 Apache MXNet 的创始人之一。目前是 BosonAI 联合创始人…

【数据分析】标准误差与标准差的区别

标准误差&#xff08;Standard Error, SE&#xff09;和标准差&#xff08;Standard Deviation, SD&#xff09;是两个在统计学中非常重要的概念&#xff0c;但它们的含义和用途有所不同。以下是它们之间的主要区别&#xff1a; 定义&#xff1a; 标准差&#xff1a;衡量单个数…

【mybatis】使用模糊查询时报错:Encountered unexpected token: “?“ “?“

报错信息如下&#xff1a; Mapper.xml报错代码&#xff1a; AND HILIST_NAME like %#{hilistName}% 解决方案&#xff1a; 把模糊查询的 sql 语句改为使用 CONCAT 命令拼接, 就不会报错了。 AND HILIST_NAME like CONCAT(%, #{hilistName},%)

深入探讨-JavaScript-逻辑赋值运算符

null && 100**2 // null undefined && 100**2 // undefined 逻辑赋值运算符 && || ?? 这个运算符将赋值与条件逻辑运算符结合在一起&#xff0c;因此命名为**“逻辑赋值”** 。它们只是一种简写&#xff0c; 例如&#xff0c;x && y是x …

Windows本地部署ollama并实现无公网IP远程运行qwen大语言模型

文章目录 前言1. 运行Ollama2. 安装Open WebUI2.1 在Windows系统安装Docker2.2 使用Docker部署Open WebUI 3. 安装内网穿透工具4. 创建固定公网地址 前言 本文主要介绍如何在Windows系统快速部署Ollama开源大语言模型运行工具&#xff0c;并安装Open WebUI结合cpolar内网穿透软…

打造智能数据分析平台:基于 Flask 的数据处理与模型精度验证系统

数据分析和机器学习已成为企业和科研中不可或缺的核心技术。在这个数据驱动的时代&#xff0c;能够快速处理海量数据&#xff0c;并通过智能算法提取出有用信息&#xff0c;成为了提升竞争力的关键。为了解决这些需求&#xff0c;我基于 Flask 开发了一款功能强大、模块化的数据…

【蓝桥杯单片机-0.基于定时器的时钟程序设计】

蓝桥杯单片机-0.基于定时器的时钟程序设计 题目小注意点按键三行矩形按键按键功能时间更新显示界面的小数点LED灯闪烁其他功能 完整代码 链接: 视频搭配视频&#xff0c;这里只是一些笔记&#xff0c;并不完整 题目 小注意点 按键三行 Key_Val Key_Read();//实时读取键码值…