【中间件】Redis如何解决BigKey

2023-11-13

BigKey 的弊端

BigKey 需要解决,根源就在于 BigKey 会带来的问题。

占用内存
因为 Redis 数据结构的底层数据结构,大 Key 会占用更多的内存空间,造成更大的内存消耗。
无标题3.png
单线程模型
因为 Redis 的通信依赖于 Socket 连接,Redis 将服务器对 Socket 的操作抽象为文件事件,服务端与客户端的通信会产生文件事件。
Redis 通过单线程,并通过 I/O 多路复用来处理来自客户端的多个连接请求,当产生连接后,将 Socket 放入队列,并通过事件分派器来选择相应的处理程序。服务端通过监听这些事件,并完成相应的处理。
Redis 基于反应器模型(Reactor Pattern)开发了网络事件处理器,并称之为文件事件处理器。文件事件处理器使用 I/O 多路复用来同时监听多个 Socket 套接字,并根据不同的套接字所执行的任务选择相应的事件处理器。被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作,与操作相关的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
I/O 多路复用监听多个套接字,并向文件事件分派器分派产生事件的套接字。如果有多个文件事件,I/O 多路复用程序会将所有产生事件的套接字放到一个队列里,并通过有序、同步、一次一个套接字的方式向文件事件分派器传送套接字。当上一个套接字的事件被处理完毕后,I/O 多路复用才会向文件分派器传送下一个套接字。文件事件分派器接受到 I/O 多路复用程序分派的套接字后,根据套接字类型选择相应的事件处理器。服务器根据套接字类型的不同,关联不同的事件处理器,即发生某事件后,该执行哪些操作。
无标题1.png

  1. 客户端连接请求交由 I/O 多路复用程序进行处理;
  2. 将 Socket 操作抽象为文件事件,放入 Socket 队列;
  3. 文件事件分派器将 Socket 队列取出,交给对应的事件处理器进行处理。

因为大 Key 的存在,所以在产生对应的 Socket 时,就会占用非常大的内存,影响网络 I/O 的效率,降低整个处理链路的效率。

参考文档:https://blog.csdn.net/Revivedsun/article/details/100006458

执行指令 bigkeys

在 redis 6.0 版本中,我们可以使用提供的--bigkeys参数得到各个数据类型占用空间最大的 Key。
在 docker 中,我们可以执行指令:

docker exec -it redis redis-cli -p 6379 --bigkeys

image.png
如果说存在大 Key ,我们可以得到:

# redis-cli -p 6379 --bigkeys

# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).

[00.00%] Biggest string found so far '"ballcat:oauth:refresh_auth:f6cdb384-9a9d-4f2f-af01-dc3f28057c20"' with 4437 bytes
[00.00%] Biggest list   found so far '"my-list"' with 17 items

-------- summary -------

Sampled 5 keys in the keyspace!
Total key length in bytes is 264 (avg len 52.80)

Biggest   list found '"my-list"' has 17 items
Biggest string found '"my-string"' has 4437 bytes

1 lists with 17 items (20.00% of keys, avg size 17.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
4 strings with 4831 bytes (80.00% of keys, avg size 1207.75)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00

查看上述的打印结果,我们可以知道该命令只能得到每种数据类型的 Top 1 空间占用的 Key ,所以这个命令存在一定的局限性。而且,该命令会执行 Scan 扫描所有的 Key 空间去寻找最大的 Key ,会对 redis 的性能具有一定影响。

debug指令

除了 --bigkey 参数之外,还有一个参数也可以执行 Key 的分析。

DEBUG OBJECT <KeyName>

# 示例
redis> DEBUG OBJECT my_pc
Value at:0xb6838d20 refcount:1 encoding:raw serializedlength:9 lru:283790 lru_seconds_idle:150

redis> DEBUG OBJECT your_mac
(error) ERR no such key

Debug Object 命令是一个调试命令,它不应被客户端所使用。当 key 存在时,返回有关信息。 当 key 不存在时,返回一个错误。

其中 serializedlength 的值为该 Key 的序列化长度。但是 Key 的序列化长度并不等同于它在内存空间中的真实长度。此外 debug object 属于调试命令,运行代价较大,并且在其运行时,进入 Redis 的其余请求将会被阻塞直到其执行完毕,且每次只能查找单个 key 的信息,官方不推荐使用。

该指令用于分析,主要有以下的特点:

① 分析与实际存在差异,内存和序列化结果不一致;
② 运行指令代价比较大;
③ 运行时阻塞。

参考文档:http://redisdoc.com/debug/debug_object.html
https://blog.csdn.net/Weixiaohuai/article/details/125391957

分析 RDB 文件

通过分析 RDB 文件来找出 big key。前提是 Redis 采用的是 RDB 持久化方式。
网上有现成的代码/工具可以直接拿来使用:

  • redis-rdb-tools :Python 语言写的用来分析 Redis 的 RDB 快照文件用的工具。
  • rdb_bigkeys : Go 语言写的用来分析 Redis 的 RDB 快照文件用的工具,性能更好。

对于线上生产环境,如果需要分析一段时间内的大 Key ,同时采用的并不是 RDB 持久化方式,我们在条件允许的环境下,可以采取以下的步骤进行:

  1. 导出 AOF 文件,在备份机器上执行复原;
  2. 在机器上使用 save 指令获得 RDB 文件;
  3. 使用工具分析 RDB 文件。

image.png
事实上到这一步,只是解决了 BigKey 的排查问题。但是真正需要解决大 Key ,要依赖一些其他的手段。

BigKey解决/减少内存占用

对于 BigKey ,无非就是减小 key 对应的 value 值的大小,也就是对于 String 数据结构的话,减少存储的字符串的长度;对于 List、Hash、Set、ZSet 数据结构则是减少集合中元素的个数。

拆分集合类元素

如果针对集合类数据结构,例如 List、Hash、Set、ZSet 数据结构,我们需要减少其中元素的个数。以 List 为例,具体做法:

  1. 原 List 的 Key 非常大,我们拆分为 5 个小的 Key;
  2. 先计算 Key 的哈希值,利用 hash(原key)%5 得到目标的 Key 处于 5 个小 Key 中的哪一个 Key。

这只是简单的拆分,基本思想遵循拆分元素个数解决。

异步删除大Key

参考文档:https://www.modb.pro/db/390777

对于大 key ,我们可以执行删除操作。删除操作主要依赖于异步操作指令:

unlink <keyName>

为什么不使用 del 指令而是使用 unlink 指令?

  1. del 指令在删除 key 的时候会阻塞主线程;
  2. unlink 指令属于异步操作,在执行的时候只会在主线程执行一些判断和其他操作,并不会造成长时间的主线程阻塞;
  3. unlink 不建议用来删除比较小的 Key ,可能会出现在主线程执行判断和其他操作的成本远大于 del 指令的情况出现。

监控 Redis 的内存

可以通过给 Redis 设置最大内存的方式,保持机器的 redis 内存占用维持在一个水平线以下。一旦即将超过最大内存限制,将会触发内存淘汰策略。

config set maxmemory 1G
config rewrite

此外,监控 Redis 还可以通过一些第三方软件来完成,比如 Application Manager 等。在现在流行的云服务厂商,也会提供有高级的配套监控服务。
我们可以自己利用内存监控,设置合理的 Redis 内存报警阈值来提醒我们此时可能有大 Key 正在产生,如:Redis 的内存使用率、内存固定时间内增长率等。

参考文档:https://zhuanlan.zhihu.com/p/476713841
https://www.jianshu.com/p/4917f733a239

定期清理失效数据

如果部分 Key 有业务不断以增量方式写入大量的数据,并且忽略了时效性,这样会导致大量的失效数据堆积。可以通过定时任务的方式,对失效数据进行清理。
定时清理失效数据,也可以降低 redis 的内存使用。

压缩 Value 数据

使用序列化、压缩算法将 Key 的大小控制在合理范围内,但是需要注意,序列化、反序列化都会带来一定的消耗。如果压缩后,value 还是很大,那么可以进一步对 key 进行拆分。

减少相同 Key 存储

对于相同元素的 Key 值,我们可以将多个非常小的 Key 进行整合,使用适当的数据结构进行存储,可以减少相同的 Key 前缀的空间占用。

user.name = michael;
user.age=20
user.id=1840800

# 可以使用 hash 进行改造
Key: user:1840800
Value: user Object
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【中间件】Redis如何解决BigKey 的相关文章

  • 如何使用 Jsoup 获取包含非 ASCII 字符(ą、ś ...)的 URL?

    我正在使用 jsoup 解析一些波兰网站 但我对 URL 中的 等特殊字符有问题example com k t读起来像example com k 每个没有这个特殊字符的查询都可以完美运行 我努力了Document doc Jsoup par
  • 如何注入“运行时”依赖项,例如登录用户,该依赖项在应用程序启动时不可用?

    我只是不明白这个 我在我的 java GWT 应用程序中使用 Gin 来进行 DI 登录屏幕集成到完整的应用程序窗口中 用户登录后 我想将用户对象注入到我创建的其他类 例如 GUI Presenters 中 因此我相信存在某种运行时依赖性
  • 在 libgdx 中批处理多维数据集时出现问题

    我正在尝试开发一款游戏 在屏幕上渲染多达 300 个立方体 为每个多维数据集创建新的 modelInstance 时 modelBatch 的性能非常糟糕 据我所知 没有 3d 批处理可以将所有立方体批处理到一次绘制调用 所以我拼命地尝试以
  • 浏览时 Java Applet 不会被终止

    当用户离开加载小程序的页面时 如何停止 Java 小程序的进程 我正在使用 Chrome 现在要杀死小程序 我必须使用窗口的任务栏并杀死进程 java exe Java applet 具有生命周期方法 那些是init start stop
  • rmi类找不到异常

    我使用 java rmi 编写了一个简单的项目并导出到可执行 jar 文件 当我尝试运行它时 有时会出现异常 有时会起作用 当我指定 Djava rmi server codebase file serverClasses 时 它似乎没有正
  • Maven 部署:deploy-file 发布所有文件而不是一个

    我正在使用 Maven 构建我的 Java 应用程序Maven 组装插件 https maven apache org plugins maven assembly plugin 创建一个可执行的 jar 因此 目标文件夹包含多个 jar
  • 在 Selenium Grid 中注册 PhantomJS 节点时出错

    我有以下问题 我成功启动了 Selenium Grid hub java jar selenium server standalone 2 53 0 jar role hub 之后我尝试使用以下命令启动 PhantomJS 节点 phant
  • Runtime.getRuntime().exec(cmd) 挂起

    我正在执行一个命令 该命令返回文件的修订号 文件名 但如果执行命令时出现问题 应用程序就会挂起 我可以做什么来避免这种情况 请在下面找到我的代码 String cmd cmd C si viewhistory fields revision
  • 控制启动时的竞争条件

    我有一些代码想要执行一些一次性初始化 但这段代码没有明确的生命周期 因此在初始化完成之前 我的逻辑可能会被多个线程调用 所以 我想基本上确保我的逻辑代码 等待 直到初始化完成 这是我的第一次剪辑 public class MyClass p
  • 如何在 HashiCorp Vault 中安全地存储 Spring Boot 应用程序的机密?

    我已阅读以下教程 保险库配置 https spring io guides gs vault config 好的 我们安装了 Vault 服务器并放置了 2 对秘密属性 vault kv put secret gs vault config
  • 在 XSSF 工作簿上设置密码保护

    我想为使用 poi 3 14 创建的 xlsx 文件添加密码保护 该文档声称 这是可能的 http poi apache org cryption html http poi apache org encryption html 使用我尝试
  • Thread.interrupt() 和 Thread.interrupted() 到底是如何工作的? [复制]

    这个问题在这里已经有答案了 从设置线程状态的角度来看 我不清楚这两种方法 Java 文档说 Thread interrupt 设置线程中断状态标志 调用 Thread interrupted 方法给出线程的状态并清除该标志 当这在实际场景中
  • CXF 增加连接池大小而不更改 http.maxConnections

    最近我被要求将 CXF 配置为与我们旧的 XFire 服务相同的参数 这些参数之一是Keep Alive timeout 60 max 20 然而 我做了一些研究 看来 CXF 使用 JVMHttpURLConnection引擎盖下的对象
  • 使用会话空闲超时进行轮询

    我对 Tomcat 中的所有应用程序使用单点登录 我的要求是 我必须轮询应从后端获取的事务状态 但它也不应该影响会话的空闲超时 有人可以建议是否可以做点什么吗 Thanx 我不知道是否有标准方法可以做到这一点 如果没有 你可以写一个过滤器
  • 不支持使用 JDK 版本“11.0.1”进行构建。请安装 JDK 版本 `1.8.0`

    我已经下载了 Visual Studio for Mac 并尝试开始学习 Xamarin iOS 和 Android 问题是当我尝试运行 android 项目时出现以下错误 Building with JDK Version 11 0 1
  • 枚举

    我试图拥有一组扩展通用接口的枚举 例如 interface Fooable void someCommonMethod enum E1 implements Fooable some enumuerations and a definiti
  • 避免加密和编码的 URL 字符串中的换行符

    我正在尝试实现一个简单的字符串编码器来混淆 URL 字符串的某些部分 以防止它们被用户弄乱 我使用的代码几乎与示例中的相同JCA指南 http docs oracle com javase 6 docs technotes guides s
  • 在地图中的图块上实现鼠标单击事件

    我正在尝试在 JPanel 上实现图像 基本上是地图上的图块 的鼠标单击事件 我只是不知道该怎么做 我有一个扩展 JPanel 的 Main 类 我正在从图块服务器检索图块 并根据特定的缩放级别在 Main 类的 PaintComponen
  • 如何读取FTL文件中的JSONArray?

    我在我的 Java 文件中硬编码了以下 JSON 对象 JSONObject notificationInfoJson new JSONObject notificationInfoJson put title Payment Receiv
  • Cassandra 会话与集群 有什么可分享的?

    考虑 Cassandra 的 Session 和 Cluster 类 Java 驱动程序 我想知道有什么区别 在 Hibernate 中 每次都会创建一个会话并共享会话工厂 从许多来源我了解到 它被认为是创建一个会话并在多个线程之间共享它

随机推荐

  • PowerDesigner中显示name, code,comment的解决方法 修正脚本,执行不会重复添加comment...

    Option Explicit ValidationMode True InteractiveMode im Batch Dim mdl the current model get the current active model Set
  • 虚拟机内搭建CTFd平台搭建及CTF题库部署,局域网内机器可以访问

    一 虚拟机环境搭建 1 安装docker git docker compose ubuntu sudo apt get update 更新系统 sudo apt get y install docker io 安装docker sudo a
  • zxing解析二维码demo

    源文件 cpp include funset hpp include
  • pvr 与 png 的内存占用

    原文链接 http blog sina com cn s blog 6fbe210701015j7z html Zwoptex 生成的 spritesheet 除了可以导出 png 格式的图片外还有 pvr 格式 pvr 格式是 iOS 的
  • 微前端乾坤的实现以及注意事项

    微前端乾坤 微前端乾坤 主应用 子应用 主应用配置 子应用配置 问题 微前端乾坤 qiankun 是一个基于 single spa 的微前端实现库 拥有的特点 JS沙箱 样式隔离 元素隔离 数据通信 预加载 HTML Entry qiank
  • TortoiseGit(git客户端)清除删除账号密码

    在使用git bash 克隆项目时 出现了remote HTTP Basic Access denied错误 我的解决方法如下 删除后 就可以在克隆项目时 重新填写git账户和密码
  • 统计学常用概念:T检验、F检验、卡方检验、P值、自由度

    常用检验公示表 自由度概念 在统计模型中 自由度指样本中可以自由变动的变量的个数 当有约束条件时 自由度减少 自由度计算公式 自由度 样本个数 样本数据受约束条件的个数 即df n k df自由度 n样本个数 k约束条件个数 例 一组数据
  • QT发布软件

    Qt Creator 完成对release版本编译完成之后 就需要将exe文件发布出来 单纯的只拷贝exe文件是不能运行的 exe的运行需要依赖很多的Qt库 1 生成可以执行的exe文件 这里需要将exe文档放在一个单独创建的test文件夹
  • dos命令大全

    DOS命令 是DOS操作系统的命令 是一种面向磁盘的操作命令 主要包括目录操作类命令 磁盘操作类命令 文件操作类命令和其它命令 DOS命令不区分大小写 比如C盘的Program Files 在dos命令中完全可以用 progra 1 代替
  • log4c cmakelist.txt config.h

    cmake minimum required VERSION 2 8 12 project log4c add definitions DHAVE CONFIG H add definitions D CRT SECURE NO WARNI
  • 【pybind11入门】Windows下为Python创建C++扩展

    在Windows下使用pybind11为python添加C 扩展 这篇文章记录下整个安装 测试 使用流程 主要内容 1 安装编译工具 2 测试pybind11编译是否正常 3 使用pybind11创建C 扩展 4 在python中调用 1
  • 迈拓 kvm 切换热键

    4台电脑之间切换的时候 可以按KVM上面的开关 也可以用热键切换 热键的切换方法如下 1 切换到第一台电脑 Scroll Lock 1 第1台电脑 2 切换到第二台电脑 Scroll Lock 2 第2台电脑 3 切换到第三台电脑 Scro
  • JLink和ST-Link接口引脚介绍

    STM32F1系列 STM8S系列 PY32F003系列都用过好久了 但是对JLink和ST Link下载器认识 还是很肤浅的 有时候 需要自己接线 却不知道引脚定义 特整理如下 1 ST Link ST Link适合对象是STM8和STM
  • Markdown学习笔记

    这个是源代码 由于无法在markdown下直接显示 所以这里采用富文本格式 Markdown学习笔记 你好 2020 7 28 段落 间隔一或多行行表示一个回车 两者没有区别 这是没有产生的效果 天王盖地虎 宝塔镇河妖 这是有回车的效果 天
  • 若依框架修改Vue请求超时时间

    ruoyi ui gt src gt utils gt request js 修改request js下的 timeout 10000 单位 毫秒
  • 软件设计师笔记 2021年下半年

    软件设计师笔记 1 第一章 计算机知识 控制器包含 地址寄存器 S single M multiple I 指令流 Data 数据流 2 第二章
  • 【状态估计】基于UKF、AUKF的电力系统负荷存在突变时的三相状态估计研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及数据 1 概述 基于UKF和AUKF的电力系统负荷存在突
  • ARM发布Cortex-X1,是为了向苹果自研A系列处理器发起冲击吗?

    对于Arm来说 2019年是伟大的一年 这一年ARM的Cortex内核依然是手机CPU领域的佼佼者 特别是Cortex A77 红极一时的高通骁龙865处理器采用的就是Cortex A77 据说采用骁龙865处理器的手机有70款之多 其中就
  • c语言文件处理中ab,C语言文件处理中wt是什么操作方式?

    匿名用户 1级 2013 04 25 回答 最常用的文件使用方式及其含义如下 1 r 为读而打开文本文件 不存在则出错 2 rb 为读而打开二进制文件 3 w 为写而打开文本文件 若不存在则新建 反之 则从文件起始位置写 原内容将被覆盖 4
  • 【中间件】Redis如何解决BigKey

    BigKey 的弊端 BigKey 需要解决 根源就在于 BigKey 会带来的问题 占用内存 因为 Redis 数据结构的底层数据结构 大 Key 会占用更多的内存空间 造成更大的内存消耗 单线程模型 因为 Redis 的通信依赖于 So