当前位置: 首页 > article >正文

【redis】集群 数据分片算法:哈希求余、一致性哈希、哈希槽分区算法

文章目录

  • 什么是集群
  • 数据分片算法
    • 哈希求余
      • 分片搬运
    • 一致性哈希
      • 扩容
    • 哈希槽分区算法
      • 扩容
      • 相关问题

什么是集群

广义的集群,只要你是多个机器,构成了分布式系统,都可以称为是一个“集群

  • 前面的“主从结构”和“哨兵模式”可以称为是“广义的集群”

此处我们介绍的是狭义的集群,redis 提供的“集群模式”,主要是解决存储空间不足的问题(拓展存储空间)

哨兵模式提高了系统的可用性。但是其本质上还是 redis 的主从节点存储数据。其中就要求一个主节点/从节点,就得存储整个数据的“全集”

  • 是用内存存储数据的,内存空间也都有限,很可能出现存储不下的情况

此处关键问题,就是引入多台机器,每台机器存储一部分数据

  • 随着机器数目的增加,每个机器存储的数据量就减少了
  • 只要机器的规模足够多,就可以存储任意大小的数据了(公司的实力)

不是说光引入多台机器就够了,每个存储数据的机器还需要搭配若干多个从节点image.png

数据分片算法

每块数据都称为是一个“分片”(上图的每个红框)

哈希求余

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

比如有三个分片:0、1、2

  1. 此时就可以针对要插入的 keyredis 都是键值对结构的数据),计算 hash 值(比如 MD5
  2. 再把这个 hash 值余上分片个数 N,就得到了一个下标
  3. 此时就可以把这个数据放到该下表对应的分片中了
  • hash(key) % N => 0 ,此时这个 key 就要存储在 0 号分片中
    后续查询 key 的时候,还是同样的算法
  • key 是一样的,hash 函数是一样的,得到的分片值就是一样的

[!quote] MD5 算法
其本身就是一个计算 hash 值的算法,针对一个字符串,里面的内容进行一系列的数学变换,得到的是一个十六进制的数字

  • MD5 计算结果是定长的;无论输入的原字符串多长,最终算出的结果就是固定长度
  • MD5 计算结果是分散的(哈希函数);两个原字符串,哪怕大部分都相同,只有一个小的地方不同,算出来的 MD5 值也会差别很大
  • MD5 计算结果是不可逆的(加密);给你原字符串,可以很容易算出 MD5 的值,给你 MD5 的值,很难还原出原始的字符串(理论上是不可行的)

分片搬运

一旦服务器需要扩容,就需要更高的成本了

分片主要目的是为了能提高存储能力,分片越多,能存的数据越多,成本也越高

  • 一般都是先搞几个分片(3 个)
  • 但是随着业务增长,数据变多了,3 个分片就已经不足以保存了,就需要扩容

但是引入新的分片之后,N 就改变了。hash(key) % N => 0

  • hash 函数和 key 都不变的情况下,如果 N 改变了,整体的分片结果仍然会变
  • 如果我们发现某个数据,在扩容之后,不应该待在当前的分片中了,就需要搬运

此处我们列出的这些值,可以脑补成 hash(key)。假设当前计算完 hash 值之后,得到的数值正好是 100-120image.png

  • 扩容后,绝大部分 key 都是需要进行搬运的
  • 搬运的时候,不仅仅只搬主节点,相关从节点也是都要搬运的,非常麻烦

如果是 20亿 个数据呢?

  • 这个级别的扩容,开销极大,往往是不能直接在生产环境上操作的,只能通过“替换”的方式来实现扩容
  • 这样依赖的机器更多了,成本更高,操作步骤非常复杂

一致性哈希

可以有效的降低上面搬运的开销

  1. 0->2^32-1 这个数据空间,映射到一个圆环上,数据按照顺时针方向增长![[Pasted Image 20250326152129_941.png|426]]

  2. 假设当前存在三个分片,就把分片放到圆环的某个位置上image.png|386

  3. 假定有一个 key,计算得到 hashH,那么这个 key 映射到哪个分片呢?

    • 就是从 H 所在位置,顺时针往下找,找到的第一个分片,即为该 key 所从属的分片
      image.png

这就相当于,N 个分片的位置,把整个圆环分成了 N 个管辖区间,keyhash 值落在某个区间内,就归对应区间管理image.png

  • 哈希求余这种操作中,当前 key 属于哪个分片,是交替的,而这种交替出现就会导致成本变大
    • 101 属于 0
    • 102 属于 1
    • 103 属于 2
  • 在一致性哈希这样的设定下,把交替出现改成了连续出现

扩容

原有分片在环上的位置不动,只要在环上新安排一个分片位置即可image.png

  • 此时,只需要把 0 号分片上的部分数据,搬运给 3 号分片即可。1 号和 2 号分片管理的区间都是不变的

优点:大大降低了扩容时数据搬运的规模,提高了扩容操作的效率
缺点:数据分配不均匀(有的多有的少,数据倾斜)

如果一次扩容高多个分片,确实是一个好的思路,可以避免刚才的数据倾斜的情况。总的搬运数量仍然是比最初的 hash 求余的方式更少的

  • 最大的问题:领导会给你批这么多机器码?

哈希槽分区算法

redis 真正采用的分片算法


hash_slot crc16(key) % 16384
  • crc16 是一种 hash 值的算法
  • 1638416 * 1024 => 2^14(16KB)
  • hash_slot 是哈希槽
  • 相当于是把整个哈希值,映射到 16384 个槽位上,也就是 [0, 16383],然后再把这些槽位比较均匀的分配给每个分片上,每个分片的节点都需要记录自己持有哪些分片

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

  • 0 号分片:[0, 5461],共 5462 个槽位
  • 1 号分片: [5462, 10923],共 5462 个槽位
  • 2 号分片: [10924, 16383],共 5460 个槽位
    虽然不是严格意义的均匀,但是差异非常小。此时这三个分片上的数据就是比较均匀的了

这种算法,本质就是把一致性哈希和哈希求余这两种方法结合了一下

上面只是一种可能的分片方式,实际上分片是非常灵活的。每个分片持有的槽位号,可以使连续的,也可以是不连续的,只要数量差不多

  • 此处每个分片都会使用“位图”这样的数据结构,表示出当前有多少槽位号
  • 16384bit 位,用每一位 0/1 来区分自己这个分片当前是否持有该槽位号

扩容

如果需要扩容,比如新增一个 3 号分片,就可以针对原有的槽位进行重新分配

比如可以把之前每个分片持有的槽位,各拿出一点,分给新分片。一种可能得分配方式:

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

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

  • 不过也可以手动配置

相关问题

  1. redis 集群是最多有 16384 个分片吗?

并非如此,如果每个分片上就只有一个槽位,此时很难保证数据在各个分片上的均衡性

  • key 是要先映射到槽位,再映射到分片。如果每个分片包含的槽位较多,如果槽位个数相当,就可以认为是包含的 key 数量相当
  • 如果每个分片包含的槽位非常少,槽位个数不一定能直观的反映到 key 的数目
  • 有的槽位可能是有多个 key;有的槽位可能是没有 key

实际上 redis 的作者建议集群分片数不应该超过 1000

  • 如果真是 1.6w 个分片,整个数据服务器的集群规模就太可怕了,几万台主机构成的集群了,整个集群的可用性是非常堪忧的
  1. 槽位数量为什么是 16384

redis 作者的答案: https://github.com/redis/redis/issues/2576
The reason is:

  1. Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to update an old config. This means they contain the slots configuration for a node, in raw form, that uses 2k of space with16k slots, but would use a prohibitive 8k of space using 65k slots.
  2. At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs.

So 16k was in the right range to ensure enough slots per master with a max of 1000 maters, but a small enough number to propagate the slot configuration as a raw bitmap easily. Note that in small clusters the bitmap would be hard to compress because when N is small the bitmap would have slots/N bits set that is a large percentage of bits set.

翻译过来⼤概意思是:

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

  • 另⼀⽅⾯, Redis 集群⼀般不建议超过 1000 个分⽚. 所以 16k 对于最⼤ 1000 个分⽚来说是⾜够⽤的, 同时也会使对应的槽位配置位图体积不⾄于很⼤

  • 虽然 8KB2KB 也打不了多少,但是心跳包是周期性通信的,非常频繁,很吃网络带宽
  • 这个值个数上基本够用了,同时占用的硬件资源(网络带宽)又不是很大

相关文章:

【redis】集群 数据分片算法:哈希求余、一致性哈希、哈希槽分区算法

文章目录 什么是集群数据分片算法哈希求余分片搬运 一致性哈希扩容 哈希槽分区算法扩容相关问题 什么是集群 广义的集群,只要你是多个机器,构成了分布式系统,都可以称为是一个“集群” 前面的“主从结构”和“哨兵模式”可以称为是“广义的…...

基于Springboot的网上订餐系统 【源码】+【PPT】+【开题报告】+【论文】

网上订餐系统是一个基于Java语言和Spring Boot框架开发的Web应用,旨在为用户和管理员提供一个便捷的订餐平台。该系统通过简化餐饮订购和管理流程,为用户提供快速、高效的在线订餐体验,同时也为管理员提供完善的后台管理功能,帮助…...

Redis常见面试问题汇总

Redis 面试笔记整理 一、Redis 基础知识1. Redis 概述Redis 是什么?主要特点有哪些?Redis 和 Memcached 的区别是什么?Redis 是单线程还是多线程?为什么单线程还能高效?Redis 6.0 之后的多线程模型是怎样的&#xff1f…...

【redis】集群 如何搭建集群详解

文章目录 集群搭建1. 创建目录和配置2. 编写 docker-compose.yml完整配置文件 3. 启动容器4. 构建集群超时 集群搭建 基于 docker 在我们云服务器上搭建出一个 redis 集群出来 当前节点,主要是因为我们只有一个云服务器,搞分布式系统,就比较…...

NLP高频面试题(二十)——flash attention原理

FlashAttention是一种针对Transformer模型中自注意力机制的优化算法,旨在提高计算效率并降低内存占用,特别适用于处理长序列任务。 在Transformer架构中,自注意力机制的计算复杂度和内存需求随着序列长度的平方增长。这意味着当处理较长序列时…...

飞牛NAS本地部署小雅Alist结合内网穿透实现跨地域远程在线访问观影

文章目录 前言1. VMware安装飞牛云(fnOS)1.1 打开VMware创建虚拟机1.3 初始化系统 2. 飞牛云搭建小雅Alist3. 公网远程访问小雅Alist3.1 安装Cpolar内网穿透3.2 创建远程连接公网地址 4. 固定Alist小雅公网地址 前言 嘿,小伙伴们&#xff0c…...

Episode, time step, batch, epoch

1. Episode(回合) 回合(episode)表示智能体从开始执行任务到完成任务(例如成功到达目标或触发失败条件)的全过程。 例如,如果我们训练一个四足机器人走到一个目标点,一个回合就是从…...

Linux版本控制器Git【Ubuntu系统】

文章目录 **前言**一、版本控制器二、Git 简史三、安装 Git四、 在 Gitee/Github 创建项目五、三板斧1、git add 命令2、git commit 命令3、git push 命令 六、其他1、git pull 命令2、git log 命令3、git reflog 命令4、git stash 命令 七、.ignore 文件1、为什么使用 .gitign…...

browser-use 库网页元素点击测试工具

目录 代码代码解释输出结果 代码 import asyncio import jsonfrom browser_use.browser.browser import Browser, BrowserConfig from browser_use.dom.views import DOMBaseNode, DOMElementNode, DOMTextNode from browser_use.utils import time_execution_syncclass Eleme…...

Vue 中使用 ECharts

在 Vue 中使用 ECharts 主要分为以下步骤,结合代码示例详细说明: 1. 安装 ECharts 通过 npm 或 yarn 安装 ECharts: npm install echarts --save # 或 yarn add echarts2. 基础使用(完整引入) 在 Vue 组件中使用 &…...

Spring AI + DeepSeek 构建大模型应用 Demo

Spring AI + DeepSeek 构建大模型应用 Demo 下面我将展示如何使用 Spring AI 框架结合 DeepSeek 的大模型能力构建一个简单的 AI 应用。 1. 环境准备 首先确保你已安装: JDK 17+Maven 3.6+Spring Boot 3.2+2. 创建 Spring Boot 项目 使用 Spring Initializr 创建项目,添加…...

解决GitLab无法拉取项目

1、验证 SSH 密钥是否已生成 ls ~/.ssh/ 如果看到类似 id_rsa 和 id_rsa.pub 的文件,则说明已存在 SSH 密钥。 避免麻烦,铲掉重来最方便。 如果没有,请生成新的 SSH 密钥: ssh-keygen -t rsa -b 4096 -C "your_emailexam…...

POSIX 线程取消与资源清理完全指南

POSIX 线程取消与资源清理完全指南 引言:为什么需要线程取消机制? 在多线程编程中,优雅地终止线程并确保资源释放是开发者面临的重要挑战。直接终止线程可能导致内存泄漏、文件未关闭等问题。POSIX 线程库提供了一套完整的线程取消和清理机…...

FPGA学习篇——Verilog学习之寄存器的实现

1 寄存器理论 这里在常见的寄存器种加了一个复位信号sys_rst_n。(_n后缀表示复位信号低电平有效,无这个后缀的则表示高电平有效) 这里规定在时钟的上升沿有效,只有当时钟的上升沿来临时,输出out 才会改变,…...

Cursor异常问题全解析-无限使用

title: Cursor异常问题全解析无限使用 tags: cursor categories:aiai编程 mathjax: true description: Cursor异常问题全解析与解决方案大全 abbrlink: 64908bd0 date: 2025-03-19 14:48:32 🤖 Assistant 🚨 Cursor异常问题全解析与解决方案大全 &…...

【VUE】ant design vue实现表格table上下拖拽排序

适合版本&#xff1a;ant design vue 1.7.8 实现效果&#xff1a; 代码&#xff1a; <template><div class"table-container"><a-table:columns"columns":dataSource"tableData":rowKey"record > record.id":row…...

Vue实现动态数据透视表(交叉表)

需求:需要根据前端选择的横维度、竖维度、值去生成一个动态的表格&#xff0c;然后把交叉的值放入到对应的横维度和竖维度之下&#xff0c;其实就是excel里面的数据透视表功能&#xff0c;查询交叉语句为sql语句。 实现页面&#xff1a; 选择一下横维度、竖维度、值之后点击查…...

推荐《人工智能算法》卷1、卷2和卷3 合集3本书(附pdf电子书下载)

今天&#xff0c;咱们就一同深入探讨人工智能算法的卷1、卷2和卷3&#xff0c;看看它们各自蕴含着怎样的奥秘&#xff0c;并且附上各自的pdf电子版免费下载地址。 《人工智能算法&#xff08;卷1&#xff09;&#xff1a;基础算法》 下载地址&#xff1a;https://www.panziye…...

元宇宙浪潮下,数字孪生如何“乘风破浪”?

在当今科技飞速发展的时代&#xff0c;元宇宙的概念如同一颗璀璨的新星&#xff0c;吸引了全球的目光。元宇宙被描绘为一个平行于现实世界、又与现实世界相互影响且始终在线的虚拟空间&#xff0c;它整合了多种前沿技术&#xff0c;为人们带来沉浸式的交互体验。而数字孪生&…...

WPF 附加属性

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;附加属性&#xff08;Attached Properties&#xff09;是一种特殊的依赖属性机制&#xff0c;它允许父元素为子元素提供额外的属性支持。这种特性特别适用于布局系统、输入处理和其他需要跨多个控件…...

数据分析 之 怎么看懂图 一

韦恩图怎么看 ①颜色:不同颜色代表不同的集合 ②)颜色重叠部分:表示相交集合共有的元素 ③颜色不重叠的部分:表示改集合独有的元素 ④数字:表示集合独有或共有的元素数量 ⑤百分比:表示该区域元素数占整体的比例 PCA图怎么看 ① 第一主成分坐标轴及主成分贡献率主成分贡献…...

手写数据库MYDB(一):项目启动效果展示和环境配置问题说明

1.项目概况 这个项目实际上就是一个轮子项目&#xff0c;现在我看到的这个市面上面比较火的就是这个首先RPC&#xff0c;好多的机构都在搞这个&#xff0c;还有这个消息队列之类的&#xff0c;但是这个是基于MYSQL的&#xff0c;我们知道这个MYSQL在八股盛宴里面是重点考察对象…...

深入理解椭圆曲线密码学(ECC)与区块链加密

椭圆曲线密码学&#xff08;ECC&#xff09;在现代加密技术中扮演着至关重要的角色&#xff0c;广泛应用于区块链、数字货币、数字签名等领域。由于其在提供高安全性和高效率上的优势&#xff0c;椭圆曲线密码学成为了数字加密的核心技术之一。本文将详细介绍椭圆曲线的基本原理…...

使用 PowerShell 脚本 + FFmpeg 在 Windows 系统中批量计算 MP4视频 文件的总时长

步骤 1&#xff1a;安装 FFmpeg 访问 FFmpeg 官网(Download FFmpeg)&#xff0c;下载 Windows 版编译包&#xff08;如 ffmpeg-release-full.7z&#xff09;。或者到&#xff08;https://download.csdn.net/download/zjx2388/90539014&#xff09;下载完整资料 解压文件&#…...

中医气血精津辨证

中医气血精津辨证 一、气血精津辨证概述 基本概念&#xff1a; 气血精津是构成人体和维持生命活动的基本物质&#xff0c;其生成、运行、输布与脏腑功能密切相关。辨证核心&#xff1a;通过分析气血精津的盛衰、运行障碍及其相互关系&#xff0c;判断疾病本质。 生理关系&…...

Intellij IDEA2023 创建java web项目

Intellij IDEA2023 创建java web项目 零基础搭建web项目1、创建java项目2、创建web项目3、创建测试页面4、配置tomcat5、遇到的问题 零基础搭建web项目 小白一枚&#xff0c;零基础学习基于springMVC的web项目开发&#xff0c;记录开发过程以及中间遇到的问题。已经安装了Inte…...

Scrapy结合Selenium实现滚动翻页数据采集

引言 在当今的互联网数据采集领域&#xff0c;许多网站采用动态加载技术&#xff08;如AJAX、无限滚动&#xff09;来优化用户体验。传统的基于Requests或Scrapy的爬虫难以直接获取动态渲染的数据&#xff0c;而Selenium可以模拟浏览器行为&#xff0c;实现滚动翻页和动态内容…...

Node.js从0.5到1学习计划

以下是针对零基础学习者的10天Node.js高效学习计划&#xff0c;每天聚焦核心知识点并配合实战练习&#xff1a; &#x1f4c6; 10天Node.js速成计划&#xff08;每日4-6小时&#xff09; 核心目标&#xff1a;掌握Node.js核心机制 完成3个实战项目 &#x1f4cd; Day 1-2&…...

python 的 obj的key 变成双引号

在Python中&#xff0c;当你序列化一个对象&#xff08;例如使用json.dumps()方法将对象转换为JSON字符串&#xff09;时&#xff0c;默认情况下&#xff0c;字典的键&#xff08;keys&#xff09;会被转换为字符串。如果你的字典中的键本身就是字符串&#xff0c;并且你想要在…...

sqlmap 源码阅读与流程分析

0x01 前言 还是代码功底太差&#xff0c;所以想尝试阅读 sqlmap 源码一下&#xff0c;并且自己用 golang 重构&#xff0c;到后面会进行 ysoserial 的改写&#xff1b;以及 xray 的重构&#xff0c;当然那个应该会很多参考 cel-go 项目 0x02 环境准备 sqlmap 的项目地址&…...