Redis核心技术与实战【学习笔记】 - 26.Redis数分布优化(应对数据倾斜问题)

简述

在切片集群中,数据会按照一定的规则分散到不同的实例上保存。比如,Redis Cluster 或 Codis 会先按照 CRC 算法的计算值对 Slot(逻辑槽)取模,同时 Slot 又有运维管理员分配到不同的实例上。这样,数据就被保存到相应的实例上了。

这种方法虽然实现起来比较简单,但是很容易导致一个问题:数据倾斜

数据倾斜有两类:

  1. 数据量倾斜:在某些情况下,实例上的数据分布不均衡,某个实例上的数据特别多。
  2. 数据访问倾斜:虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问非常频繁。

如果发生了数据倾斜,那么保存了大量数据,或者是保存了热点数据的实例的处理压力就会增大,速度变慢,甚至还可能会引起这个实例的内存资源耗尽,从而崩溃。这是我们在应用切片集群时要避免的。


1.数据量倾斜的成因和方法

当数据量倾斜发生时,数据在切片集群的多个实例上分布不均匀,大量数据集中到了一个或几个实例上,如下图所示:
在这里插入图片描述
那么,数据量倾斜是怎么产生的呢?这主要有三个原因,分别是某个实例上保存了 bigkey、Solt 分配不均衡以及 Hash Tag。

bigkey 导致倾斜

第一个原因是,某个实例上正好保存了 bigkey。bigkey 的 value 值很大(String 类型),或者是 bigkey 保存了大量集合元素,会导致这个实例的数据量增加,内存资源也相应增加。

而且,bigkey 的操作一般都会造成实例 IO 线程阻塞,如果 bigkey 的访问量比较大,就会影响到这个实例上的其他请求被处理的速度。

为了避免 bigkey 造成的数据倾斜,一个根本的应对方法是,在我们业务层生成数据时,要尽量避免把过多的数据保存在同一个键值对中

此时,如果 bigkey 正好是集合类型,我们还有一个方法,就是把 bigkey 拆分成很多个小的集合类型,分散保存到不同的实例上

我给你举个例子。假设 Hash 类型集合 user:info 保存了 100 万个用户的信息,是一个 bigkey。那么,我们就可以按照用户 ID 的范围,把这个集合拆分成 10 个小集合,每个小集合只保存 10 万个用户的信息。这样一来,我们就可以把 bigkey 化整为零、分散保存了,避免了 bigkey 给单个切片实例带来的访问压力。

需要注意的是,当 bigkey 访问量较大时,也会造成数据访问倾斜,我们一会再给你讲具体怎么应对。

Slot 分配不均衡导致倾斜

如果集群运维人员没有均衡地分配 Slot,就会有大量的数据被分配到同一个 Slot 中,而同一个 Slot 只会在一个实例上分布,这就会导致,大量数据被集中到一个实例上,造成数据倾斜。

我们以 Redis Cluster 为例,来介绍下 Slot 分布不均衡的情况。

Redis Cluster 一共有 16384 个 Slot,假设集群一共有 5 个实例,其中,实例 1 的硬件配置较高,运维人员在给实例 1 多分配些 Slot,把实例 1 的资源充分利用起来。

但是,我们其实并不知道数据和 Slot 的对应关系,这种做法就可能会导致大量数据正好被映射到实例 1 上的 Slot,造成数据倾斜,给实例 1 带来访问压力。

为了应对这个问题,我们可以通过运维规范,在分配之前,我们就要避免把过多的 Slot 分配到同一个实例。如果是已经分配好 Slot 集群,我们可以先查看 Slot 和实例的具体分配关系,从而判断是否有过多的 Slot 集中到同一个实例。如果有的话,就将部分 Slot 迁移到其他实例,从而避免数据倾斜。

不同集群上查看 Slot 分配情况的方式不同:如果是 Redis Cluster,就用 CLUSTER SLOTS 命令;如果是 Codis,就可以在 codis dashboard 上查看。

比如说,我们执行 CLUSTER SLOTS 命令查看 Slot 分配情况。命令返回结果显示:

  • Slot0 到 Slot5460 被分配到实例 127.0.0.1:6379
  • Slot5461 到 Slot10922 被分配到实例 127.0.0.1:7001
  • Slot0 到 Slot16383 被分配到实例 127.0.0.1:7002
127.0.0.1:6379> CLUSTER SLOTS
1) 1) (integer) 02) (integer) 54603) 1) "127.0.0.1"2) (integer) 63793) "169fa8ec32802edf671f7e9156f8cab04ce6db54"
2) 1) (integer) 54612) (integer) 109223) 1) "127.0.0.1"2) (integer) 70013) "2fd9d6f56828af1c8290f91da6cff1a11e1e74e7"
3) 1) (integer) 109232) (integer) 163833) 1) "127.0.0.1"2) (integer) 70023) "7c842c75a501c7991d75b04b76331f1f2ffb865c"

本人在自己的本机,启动了三个 Redis 实例,运行redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:7001 127.0.0.1:7002 即可搭建分片集群,运行成功后,结果如下。
在这里插入图片描述

如果一个实例上有太多的 Slot,我们就可以使用迁移命令把这些 Slot 迁移到其他实例上。在 Redis Cluster 中,我们可以使用 3 个命令完成 Slot 迁移。

  1. CLUSTER SETSLOT :使用不同的选项进行三种设置,分别是设置 Slot 要迁入的目标实例,Slot 要迁出的源实例,以及 Slot 所属的实例。
  2. CLUSTER GETKEYSINSLOT:获取某个 Slot 中一定数量的 key。
  3. MIGRATE:把一个 key 从源实例实际迁移到目标实例。

我来借助一个例子,带你了解这三个命令如何使用。

假设,我们要把 Slot 300 从源实例(ID 为 1)迁移到目标实例(ID 为 3),那要怎么做呢?

第一步,我们现在目标实例 3 上执行下面的命令,将 Slot 300 的源实例设置为实例 1,表示要从实例 1 上迁入 Slot 300。

CLUSTER SETSLOT 300 IMPORTING 1

第二步,在源实例 1 上,我们把 Slot 300 的目标实例设置为 3,这表示,Slot 300 要迁出到实例 3 上,如下所示:

CLUSTER SETSLOT 300 MIGRATING 3

第三步,从 Slot 300 中获取 100 个key。因为 Slot 中的 key 数量可能很多,所以,我们需要在客户端上多次执行下面这条命令,分批次获得并迁移 key。

CLUSTER GETKEYSINSLOT 300 100

第四步,把刚才获取的 100 个 key 中的 key1 迁移到目标实例 3 上(IP 地址为 )

MIGRATE 127.0.0.1 7002 key1 0 timeout

最后,我们重复执行第 3 和第 4 步,直到 Slot 中的所有 key 都迁移完成。

从 Redis 3.0.6 开始,也可以使用 KEYS 选项,一次迁移多个 key(key1、2、3),这样可以提升迁移效率。

MIGRATE 127.0.0.1 7002 "" 0 timeout KEYS key1 key2 key3

对于 Codis 来说,我们可以执行下面的命令进行数据迁移。其中,我们把 dashboard 组件的连接地址设置为 ADDR,并且把 Slot 300 迁移到编号为 6 的 codis server group 上。

codis-admin --dashboard=ADDR -slot-action --create --sid=300 --gid=6

除了 bigkey 和 Slot 分配不均衡会导致数据量倾斜,还有一个导致倾斜的原因,就是使用了 Hash Tag 进行数据切片。

Hash Tag 导致倾斜

Hash Tag 是指加载键值对 key 中的一对花 {}。这对括号会把 key 的一部分括起来,客户端在计算 key 的 CRC16 值时,只对 Hash Tag 花括号中的 key 内容进行计算。如果没用 Hash Tag 的话,客户端计算整个 key 的 CRC16 的值。

举个例子,假设 key 是 user:profile:3231,我们把其中的 3231 作为 Hash Tag,此时,key 就变成了 user:profile:{3231} 。当客户端计算这个 key 的 CRC16 值时,就只会计算 3231 的 CRC16 值。否则,客户端会计算整个 “user:profile:3231” 的 CRC16 值。

使用 Hash Tag 的好处是,如果不同 key 的 Hash Tag 内容都是一样的,那么这些 key 对应的数据会被映射到同一个 Slot 中,同时会被分配到同一个实例上。

下表就显示了使用 Hash Tag 后,数据被映射到相同 Slot 的情况。

数据key哈希计算对应的Slot
user:profile:{3231}CRC16(‘3231’) mod 163841024
user:profile:{5328}CRC16(‘3231’) mod 53283210
user:order:{3231}CRC16(‘3231’) mod 163841024
user:order:{5328}CRC16(‘3231’) mod 53283210

其中, user:profile:{3231} 和 user:order:{3231} 的 Hash Tag 一样,都是 3231,它们的 CRC16 计算值对 16384 取模后的值也是一样的,所以就对应到了相同的 Slot 1024 中。user:profile:{5328} 和 user:order:{5328} 也是相同的映射结果。

Hash Tag 一般使用场景是什么呢? 其实它主要用在 Redis Cluster 和 Codis,支持事务操作和范围操作。因为 Redis Cluster 和 Codis 本身并不支持夸实例的事物操作和范围查询,当业务应用有这些需求时,就只能先把这些数据读取到业务层进行事务处理,或者是逐个查询每个实例,得到范围查询的结果。

这样操作起来很麻烦,所以,我们可以使用 Hash Tag 把要执行事务操作或范围查询的数据映射到同一实例上,这样就能很轻松地实现事务或范围查询了。

但是,使用 Hash Tag 的潜在问题,就是大量的数据可能被集中到一个实例上,导致数据倾斜,集群中的负载不均衡。我们需要在范围查询、事务执行的需求和数据倾斜带来的访问压力之间,进行取舍。

2.数据访问倾斜的成因和应对方法

发生数据访问倾斜的根本原因,就是实例上存在热点数据(比如新闻应用中的热点新闻内容、电商促销活动中的热门商品,等等)。

一旦热点数据被存在了某个实例中,那么,这个实例的请求访问量就会远高于其他实例,面临巨大压力,如下所示:
在这里插入图片描述
和数据量倾斜不同,热点数据通常是一个或几个数据,所以,直接重新分配 Slot 并不能解决问题热点数据的问题。通常来说,热点数据以服务读操作为主,在这种情况下,我们可以采用热点数据多副本的方法来应对。

热点数据多副本的方法的具体做法是,我们热点数据复制多份,在每一个数据副本的 key 中增加一个随机前缀,让它和其他副本数据不会映射到同一个 Slot 中。这样一来,热点数据既有多个副本可以同时服务请求,同时,这些副本数据的 key 又不一样,会被映射到不同的 Slot 中。在给这些 Slot 分配实例时,我们也要注意把他们分配到不同的实例上,那么,热点数据的访问压力就被分散到不同的实例上。

这里,有个地方需要注意下,热点数据多副本方法只能针对只读的热点数据。如果热点数据是有读有写的话,就不适合采用多副本的方案了,因为要保证多副本间的数据一致性,会带来额外的开销。

对于有读有写的热点数据,我们就要给实例本身增加资源,例如使用配置更高的机器,来应对大量的访问压力。

3.小结

本节,主要介绍了数据倾斜的两种情况:数据量倾斜和数据访问倾斜。

造成数据量倾斜的原因主要有 3 个:

  1. 数据中有 bigkey,导致某个实例的数据量增加
  2. Slot 手工分配不均,导致某个实例或某些实例上有大量数据。
  3. 使用了 Hash Tag,导致数据集中到某些实例上。

而数据访问倾斜的主要原因是有热点数据存在,导致大量访问请求集中到了热点数据所在的实例上。

为了应对数据倾斜问题,总结了下面四个方法。

倾斜类型倾斜成因应对方法
数据量倾斜存在bigkey业务层避免创建 bigkey
把集合类型的 bigkey 拆分成多个小集合,分散保存
数据量倾斜Slot 手工分配不均制定运维规范,避免把过多 Slot 分配到一个实例上
数据量倾斜使用 Hash Tag,导致大量数据集中到一个 Slot如果 Hash Tag 会造成数据倾斜,优先避免数据倾斜,不适用 Hash Tag
数据访问倾斜存在热点数据采用带有不同 key 前缀的多副本方法

当然,如果以及发生了数据倾斜,我们可以通过数据迁移来缓解数据倾斜的影响。Redis Cluster 和 Codis 集群都提供了查看 Slot 分配和手工迁移的 Slot 命令。

最后,关于集群的实例资源配置,给你一个小建议:在构件切片集群时,尽量使用大小配置相同的实例(例如实例内存保持相同),这样可以避免因实例资源不均衡而在不同实例上分配不同数量的Slot。

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

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

相关文章

【芯片设计- RTL 数字逻辑设计入门 番外篇 9 -- SOC 中PL端与PS端详细介绍】

文章目录 Programmable Logic and Processing SystemPL(Programmable Logic)特点PS和PL之间的协同设计和开发工具 Programmable Logic and Processing System 在系统级芯片(SoC)的上下文中,“PL” 通常指的是可编程逻…

test fuzz-04-模糊测试 jazzer Coverage-guided, in-process fuzzing for the JVM

拓展阅读 开源 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息) 开源 Junit performance rely on junit5 and jdk8.(java 性能测试框架。性能测试。压测。测试报告生成。) test fuzz-01-模糊测试(Fuzz Testing) test fuzz-…

自动化AD域枚举和漏洞检测脚本

linWinPwn 是一个 bash 脚本,可自动执行许多 Active Directory 枚举和漏洞检查。该脚本基于很多现有工具实现其功能,其中包括:impacket、bloodhound、netexec、enum4linux-ng、ldapdomaindump、lsassy、smbmap、kerbrute、adidnsdump、certip…

YOLO系列详解(YOLOV1-YOLOV3)

YOLO算法 简介 本文主要介绍YOLO算法,包括YOLOv1、YOLOv2/YOLO9000和YOLOv3。YOLO算法作为one-stage目标检测算法最典型的代表,其基于深度神经网络进行对象的识别和定位,运行速度很快,可以用于实时系统。了解YOLO是对目标检测算…

【leetcode热题100】子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。 示例 1: 输入:nums [1,2,2] 输出…

C++初阶:适合新手的手撕vector(模拟实现vector)

上次讲了常用的接口:C初阶:容器(Containers)vector常用接口详解 今天就来进行模拟实现啦 文章目录 1.基本结构与文件规划2.空参构造函数(constructor)4.基本函数(size(),capacity(),resize(),reserve())4.增…

算法学习——LeetCode力扣栈与队列篇1

算法学习——LeetCode力扣栈与队列篇1 232. 用栈实现队列 232. 用栈实现队列 - 力扣(LeetCode) 描述 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): 实现 MyQu…

HiveSQL——sum(if()) 条件累加

注:参考文章: HiveSql面试题10--sum(if)统计问题_hive sum if-CSDN博客文章浏览阅读5.8k次,点赞6次,收藏19次。0 需求分析t_order表结构字段名含义oid订单编号uid用户idotime订单时间(yyyy-MM-dd)oamount订…

阿里云游戏服务器多少钱一年?

阿里云游戏服务器租用价格表:4核16G服务器26元1个月、146元半年,游戏专业服务器8核32G配置90元一个月、271元3个月,阿里云服务器网aliyunfuwuqi.com分享阿里云游戏专用服务器详细配置和精准报价: 阿里云游戏服务器租用价格表 阿…

【计算几何】确定两条连续线段向左转还是向右转

确定两条连续线段向左转还是向右转 目录 一、说明二、算法2.1 两点的叉积2.2 两个段的叉积 三、旋转方向判别3.1 左转3.2、右转3.3 共线判别 一、说明 如果是作图,或者是判别小车轨迹。为了直观地了解,从当前点到下一个点过程中,什么是左转、…

第77讲用户管理功能实现

用户管理功能实现 前端&#xff1a; views/user/index.vue <template><el-card><el-row :gutter"20" class"header"><el-col :span"7"><el-input placeholder"请输入用户昵称..." clearable v-model"…

JavaEE作业-实验二

目录 1 实验内容 2 实验要求 3 思路 4 核心代码 5 实验结果 1 实验内容 实现两个整数求和的WEB程序 2 实验要求 ①采用SpringMVC框架实现 ②数据传送到WEB界面采用JSON方式 3 思路 ①创建一个SpringMVC项目&#xff0c;配置好相关的依赖和配置文件。 ②创建一个Con…

Centos7之忘记Root用户密码的处理方式

Centos7之忘记Root用户密码的处理方式 文章目录 Centos7之忘记Root用户密码的处理方式1.场景描述2. 重置密码1. 重启系统进入编辑界面2. 按方向键下键↓&#xff0c;找到设置语言的地方3. 进入bash界面后&#xff0c;可以输入passwd命令重新设置root密码 1.场景描述 长时间未使…

导数的几何意义【高数笔记】

1. 高数中的导数几何意义&#xff0c;与中学中斜率的联系 2. 导函数与导数的区别和联系又是什么 3. 导数的几何意义的题型是什么 4. 这些题型又有哪些区别 5. 点在曲线外和点在曲线上&#xff0c;需要注意什么 6. 法线和切线有什么关系 7. 法线是什么

无性能损失!让SAM加速近50倍!EfficientViT-SAM来了!

今天给大家分享一个加速视觉分割大模型的工作&#xff1a;EfficientViT-SAM。这是一种新的加速SAM系列。保留了SAM的轻量级提示编码器和mask解码器&#xff0c;同时用EfficientViT替换了沉重的图像编码器。对于训练&#xff0c;首先从SAM-ViT-H图像编码器到EfficientViT的知识蒸…

Github 2024-02-11 开源项目日报Top10

根据Github Trendings的统计&#xff0c;今日(2024-02-11统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4非开发语言项目2C项目1C项目1Solidity项目1JavaScript项目1Rust项目1HTML项目1 免费服务列表 | f…

实战案例:将已有的 MySQL8.0 单机架构变成主从复制架构

操作步骤 修改 master 主节点 的配置&#xff08; server-id log-bin &#xff09;master 主节点 完全备份&#xff08; mysqldump &#xff09;master 主节点 创建复制用户并授权master 主节点 将完全备份文件拷贝至从节点修改 slave 从节点 的配置&#xff08; server-id rea…

全功能的屏幕截图工具 - PicPick

全功能的屏幕截图工具 - PicPick 1. PicPick1.1. PicPick 中文1.2. Hot keys References 1. PicPick https://picpick.app/zh/ https://picpick.app/en/ A full-featured screen capture and recording tool, Intuitive image editor, color picker, color palette, pixel-ru…

腾讯云4核8G服务器性能如何?支持多少用户访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

【大厂AI课学习笔记】【1.5 AI技术领域】(10)对话系统

对话系统&#xff0c;Dialogue System&#xff0c;也称为会话代理。是一种模拟人类与人交谈的计算机系统&#xff0c;旨在可以与人类形成连贯通顺的对话&#xff0c;通信方式主要有语音/文本/图片&#xff0c;当然也可以手势/触觉等其他方式 一般我们将对话系统&#xff0c;分…