【中间件】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 的相关文章

随机推荐

  • 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