【Redis】Redis中的Big Key问题:排查与解决思路

原创不易,注重版权。转载请注明原作者和原文链接

文章目录

    • Big Key问题介绍
    • Big Key问题排查
      • BIGKEYS命令
        • Debug Object
        • memory usage
      • redis-rdb-tools
    • Big Key问题解决思路
      • 分割大key
      • 对象压缩
      • 直接删除

在处理大型数据时,Redis 作为我们的非关系型数据库经常出现在解决方案之中。然而,在使用 Redis 的过程中,有一些问题可能会悄无声息地影响我们的系统性能,其中最具代表性的就是 Big Key 问题。

这个问题往往被低估,Big Key会对 Redis 的效率和整体性能产生重大影响。在本文中,我们将深入探索 Big Key 问题的源头,讨论它如何影响系统性能,并提供相应的解决策略。通过了解和解决 Big Key 问题,我们可以更有效地利用 Redis,优化我们的系统并提高性能。

Big Key问题介绍

在Redis中,每个key都有一个对应的value,如果某个key的value过大,就会导致Redis的性能下降或者崩溃。

因为Redis需要将大key全部加载到内存中,这会占用大量的内存空间,会降低Redis的响应速度,这个问题被称为Big Key问题。

不要小看这个问题,它可是能让你的Redis瞬间变成“乌龟”,由于Redis单线程的特性,操作Big Key的通常比较耗时,也就意味着Big Key阻塞Redis的可能性很大,这样会造成客户端阻塞或者引起故障切换,有可能导致“慢查询”或其他连锁反应。

一般而言,下面这两种情况可以被称为Big Key:

  • String 类型的 key 对应的value超过 10 MB。
  • list、set、hash、zset等集合类型,集合元素个数超过 5000个。

以上对Big Key的判断标准并不唯一,只是一个大体的标准。在实际业务开发中,对Big Key的判断是需要根据具体的使用场景做不同的判断。比如操作某个 key 导致请求响应时间变慢,那么这个 key 就可以判定成 Big Key。

在Redis中,Big Key通常是由以下几种原因导致的:

  • 对象序列化后的大小过大。
  • 存储大量数据的容器,如set、list等。
  • 大型数据结构,如bitmap、hyperloglog等。

如果不及时处理这些大key,它们会逐渐消耗Redis服务器的内存资源,最终导致Redis崩溃。

Big Key问题排查

当出现Redis性能急剧下降的情况时,很可能是由于存在大key导致的。在排除大key问题时,可以考虑采取以下几种方法:

BIGKEYS命令

Redis自带的 BIGKEYS 命令可以查询当前Redis中所有key的信息,对整个数据库中的键值对大小情况进行统计分析。

比如说,统计每种数据类型的键值对个数以及平均大小。

此外,这个命令执行后,会输出每种数据类型中最大的 big key 的信息,对于 String 类型来说,会输出最大 big key 的字节长度,对于集合类型来说,会输出最大 big key 的元素个数。

BIGKEYS命令会扫描整个数据库,这个命令本身会阻塞Redis,找出所有的大键,并将其以一个列表的形式返回给客户端。

命令格式如下:

$ redis-cli --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 'a' with 3 bytes
[05.14%] Biggest list   found so far 'b' with 100004 items
[35.77%] Biggest string found so far 'c' with 6 bytes
[73.91%] Biggest hash   found so far 'd' with 3 fields-------- summary -------Sampled 506 keys in the keyspace!
Total key length in bytes is 3452 (avg len 6.82)Biggest string found 'c' has 6 bytes
Biggest   list found 'b' has 100004 items
Biggest   hash found 'd' has 3 fields504 strings with 1403 bytes (99.60% of keys, avg size 2.78)
1 lists with 100004 items (00.20% of keys, avg size 100004.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
1 hashs with 3 fields (00.20% of keys, avg size 3.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)

解读下返回结果,从这个结果中可以看出:

  • Redis中样本了506个键。
  • 这506个键总共占用了3452字节,平均每个键占用6.82字节。
  • 最大的字符串键是’c’,值有6字节。
  • 最大的列表键是’b’,有100004个元素。
  • 最大的哈希键是’d’,有3个字段。
  • 有504个字符串键,总共1403字节,占所有键的99.60%,平均每个字符串键大小为2.78字节。
  • 有1个列表键,包含100004个元素,占所有键的0.20%,平均每个列表键大小为100004个元素。
  • 没有集合(set)键。
  • 有1个哈希键,包含3个字段,占所有键的0.20%,平均每个哈希键大小为3个字段。
  • 没有有序集合(zset)键。

这些信息可以帮助你理解Redis数据库的使用状态,以便进行相应的优化或调整。

需要注意的是,由于BIGKEYS命令需要扫描整个数据库,所以它可能会对Redis实例造成一定的负担。在执行这个命令之前,请确保你的Redis实例有足够的资源来处理它,建议在从节点执行

Debug Object

如果我们找到了Big Key,就需要对其进行进一步的分析。我们可以使用命令debug object key查看某个key的详细信息,包括该key的value大小等。这时候你就可以“窥探”Redis的内部,看看到底是哪个key太大导致的问题。

Debug Object 命令是一个调试命令,当 key 存在时,返回有关信息。 当 key 不存在时,返回一个错误。

redis 127.0.0.1:6379> DEBUG OBJECT key
Value at:0xb6838d20 refcount:1 encoding:raw serializedlength:9 lru:283790 lru_seconds_idle:150redis 127.0.0.1:6379> DEBUG OBJECT key
(error) ERR no such key

第一次运行命令时,返回了 key 对应的具体信息。这些值的意思如下:

  • Value at:0xb6838d20:key 所在的内存地址。
  • refcount:1:引用计数,表示该对象被引用的次数。
  • encoding:raw:编码类型,这里是 raw ,表示这个字符串对象的编码类型。
  • serializedlength:9:序列化后的长度。
  • lru:283790:LRU (Least Recently Used)信息,即最近最少使用算法的相关信息,在内存淘汰策略中会用到。
  • lru_seconds_idle:150:该 key 已空闲多久(单位为秒),也就是自从最后一次访问已经过去多少秒。

第二次运行命令时,返回了 (error) ERR no such key,说明在 Redis 中没有找到名为 ‘key’ 的键。

memory usage

在Redis4.0之前,只能通过DEBUG OBJECT命令估算key的内存使用(字段serializedlength),但DEBUG OBJECT命令是存在误差的。

4.0版本及以上,更推荐使用memory usag命令。

memory usage命令使用非常简单,格式为:memory usage key

如果当前key存在,则返回key的value实际使用内存估算值,如果key不存在,则返回nil。

127.0.0.1:6379> set k1 value1
OK
127.0.0.1:6379> memory usage k1    //这里k1 value占用57字节内存
(integer) 57
127.0.0.1:6379> memory usage aaa  // aaa键不存在,返回nil.
(nil)

对于除String类型之外的类型,memory usage命令采用抽样的方式,默认抽样5个元素,所以计算是近似值,我们也可以手动指定抽样的个数。

示例说明:生成一个100w个字段的hash键:hkey,每字段的value长度是从1~1024字节的随机值。

127.0.0.1:6379> hlen hkey    // hkey有100w个字段,每个字段的value长度介于1~1024个字节
(integer) 1000000
127.0.0.1:6379> MEMORY usage hkey   //默认SAMPLES为5,分析hkey键内存占用521588753字节
(integer) 521588753
127.0.0.1:6379> MEMORY usage hkey SAMPLES  1000 //指定SAMPLES为1000,分析hkey键内存占用617977753字节
(integer) 617977753
127.0.0.1:6379> MEMORY usage hkey SAMPLES  10000 //指定SAMPLES为10000,分析hkey键内存占用624950853字节
(integer) 624950853

要想获取key较精确的内存值,就指定更大抽样个数。但是抽样个数越大,占用cpu时间分片就越大。

redis-rdb-tools

redis-rdb-tools 是一个 python 的解析 rdb 文件的工具,在分析内存的时候,我们主要用它生成内存快照。可以把 rdb 快照文件生成 CSV 或 JSON 文件,也可以导入到 MySQL 生成报表来分析。

使用 PYPI 安装

pip install rdbtools

生成内存快照

rdb -c memory dump.rdb > memory.csv

在生成的 CSV 文件中主要有以下几列:

  • database key在Redis的db
  • type key类型
  • key key值
  • size_in_bytes key的内存大小
  • encoding value的存储编码形式
  • num_elements key中的value的个数
  • len_largest_element key中的value的长度

可以在MySQL中新建表然后导入进行分析,然后可以直接通过SQL语句进行查询分析。

CREATE TABLE `memory` (`database` int(128) DEFAULT NULL,`type` varchar(128) DEFAULT NULL,`KEY` varchar(128),`size_in_bytes` bigint(20) DEFAULT NULL,`encoding` varchar(128) DEFAULT NULL,`num_elements` bigint(20) DEFAULT NULL,`len_largest_element` varchar(128) DEFAULT NULL,PRIMARY KEY (`KEY`));

例如,查询内存占用最高的3个 key:

mysql> SELECT * FROM memory ORDER BY size_in_bytes DESC LIMIT 3;
+----------+------+-----+---------------+-----------+--------------+---------------------+
| database | type | key | size_in_bytes | encoding  | num_elements | len_largest_element |
+----------+------+-----+---------------+-----------+--------------+---------------------+
|        0 | set  | k1  |        624550 | hashtable |        50000 | 10                  |
|        0 | set  | k2  |        420191 | hashtable |        46000 | 10                  |
|        0 | set  | k3  |        325465 | hashtable |        38000 | 10                  |
+----------+------+-----+---------------+-----------+--------------+---------------------+
3 rows in set (0.12 sec)

Big Key问题解决思路

当发现存在Big Key问题时,我们需要及时采取措施来解决这个问题。下面列出几种可行的解决思路:

分割大key

将Big Key拆分成多个小key。这个方法比较简单,但是需要修改应用程序的代码。就像是把一个大蛋糕切成小蛋糕一样,有点费力,但是可以解决问题。

或者尝试将Big Key转换成Redis的其他数据结构。例如,将Big Key转换成Hash,List或者Set等数据结构。

对象压缩

如果大key的产生原因主要是由于对象序列化后的体积过大,我们可以考虑使用压缩算法来减小对象的大小。需要在客户端使用一些压缩算法对数据进行压缩和解压缩操作,例如LZF、Snappy等。

直接删除

如果你使用的是Redis 4.0+的版本,可以直接使用 unlink命令去异步删除大key。4.0以下的版本 可以考虑使用 scan命令,分批次删除。

无论采用哪种方法,日常使用中都需要注意以下几点:

  1. 避免使用过大的value。如果需要存储大量的数据,可以将其拆分成多个小的value。就像是吃饭一样,一口一口的吃,不要贪多嚼不烂。

  2. 避免使用不必要的数据结构。例如,如果只需要存储一个字符串,就不要使用Hash或者List等数据结构。

  3. 定期清理过期的key。如果Redis中存在大量的过期key,就会导致Redis的性能下降。就像是家里的垃圾,需要定期清理。

  4. 对象压缩。

最后,结束本文时,我们要明确的是,Redis Big Key问题是所有使用Redis作为数据存储方案的开发者都需要密切关注的重要话题。大Key可能会对Redis的性能产生严重影响,或者导致意外的内存问题。

因此,开发者应该充分利用现有的工具和策略来检测和避免Big Key。在使用Redis时,需要注意避免使用过大的value和不必要的数据结构,以及定期清理过期的key。

另外,我们还应持续探索更高效、更可靠的解决方案,来优化我们的Redis实例,使其更稳定地为我们的应用提供服务。最后,不断学习和实践才是提高我们对Redis使用的理解,并准确处理Redis Big Key问题的最佳方式。

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

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

相关文章

PlantUML 绘图

官网 https://plantuml.com/zh/ 示例 绘制时序图 USB 枚举过程 PlantUML 源码 startuml host <-- device : device insert host note right : step 1 host -> device : get speed, reset, speed check note right : step 2 host -> device …

LONGLORA: EFFICIENT FINE-TUNING OF LONGCONTEXT LARGE LANGUAGE MODELS

本文是LLM系列文章&#xff0c;针对《LONGLORA: EFFICIENT FINE-TUNING OF LONGCONTEXT LARGE LANGUAGE MODELS》的翻译。 Longlora:长上下文大型语言模型的高效微调 摘要1 引言2 相关工作3 LongLoRA4 实验5 结论 摘要 我们提出了LongLoRA&#xff0c;一种有效的微调方法&…

Premiere Elements 2024(PR简化版)直装版

Adobe Premiere Elements 2024 是一款由Adobe Systems推出的视频编辑软件&#xff0c;它结合了易用性和专业级的功能&#xff0c;帮助用户对视频进行剪辑、特效、色彩校正等处理。 主要功能和特点&#xff1a; 导入和组织视频&#xff1a;Premiere Elements 2024允许用户快速导…

JAVA设计模式-模板模式

一.概念 定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 ​ 使用了JAVA的继承机制&#xff0c;在抽象类中定义一个模板方法&#xff0c;该方法引用了若干个抽象方法&#xff0…

ESP8266 WiFi物联网智能插座—下位机软件实现

目录 1、软件架构 2、开发环境 3、软件功能 4、程序设计 4.1、初始化 4.2、主循环状态机 4.3、初始化模式 4.4、配置模式 4.5、运行模式 4.6、重启模式 4.7、升级模式 5、程序功能特点 5.1、日志管理 5.2、数据缓存队列 本篇博文开始讲解下位机插座节点的MCU软件…

虚拟机软件Parallels Desktop 19 mac功能介绍

Parallels Desktop 19 mac是一款虚拟机软件&#xff0c;它允许用户在Mac电脑上同时运行Windows、Linux和其他操作系统。Parallels Desktop提供了直观易用的界面&#xff0c;使用户可以轻松创建、配置和管理虚拟机。 PD19虚拟机软件具有快速启动和关闭虚拟机的能力&#xff0c;让…

Kelper.js 笔记 python交互

1 加载Kepler 地图 KeplerGl() 1.1 主要参数 height 可选 默认值&#xff1a;400 地图显示的高度 data 数据集 字典&#xff0c;键是数据集的名称 config地图配置字典 1.2 举例 from keplergl import KeplerGlmap_KeplerGl() map_ 默认的位置 1.3 添加自己的图 1.3.1 读…

ElementPlus Switch 开关基础使用

昨天开发用到开关组件 后台返回字段是 can_write 默认是0 or 1 但是Switch 组件绑定的默认值默认是 true or false 直接绑定会导致默认是关闭状态 在页面一加载 值发生变化时 会自己调用 查了文档 需要使用 active-value 和 inactive-value 来指定绑定的数据类型 …

23种经典设计模式:单例模式篇(C++)

前言&#xff1a; 博主将从此篇单例模式开始逐一分享23种经典设计模式&#xff0c;并结合C为大家展示实际应用。内容将持续更新&#xff0c;希望大家持续关注与支持。 什么是单例模式&#xff1f; 单例模式是设计模式的一种&#xff08;属于创建型模式 (Creational Pa…

RK3588平台产测之ArmSoM-W3 DDR带宽监控

1. 简介 专栏总目录 ArmSoM团队在产品量产之前都会对产品做几次专业化的功能测试以及性能压力测试&#xff0c;以此来保证产品的质量以及稳定性 优秀的产品都要进行多次全方位的功能测试以及性能压力测试才能够经得起市场的检验 2. 环境介绍 硬件环境&#xff1a; ArmSoM-W…

stm32(二十)IAP升级优化(双缓存,可恢复)

这次主要对STM32F103/Keil和LPC2478/IAR加了一个IAP在线升级功能&#xff0c; 主要记录一下自己的思路&#xff0c;无代码&#xff0c;实在是代码感觉没啥写的&#xff0c;都是一些网上很多流传的东西。 1、开发环境 Keilstm32f103JLINK 2、程序思路 在升级中&#xff0c;必…

JS 图片的左右切换

图片的左右切换 <div class"slider"><img src"image1.jpg" alt"Image 1"><img src"image2.jpg" alt"Image 2"><img src"image3.jpg" alt"Image 3"> </div> <button …

网页游戏的开发流程

网页游戏的开发流程可以根据项目的规模和复杂性而有所不同&#xff0c;但通常包括以下一般步骤&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.需求分析&#xff1a; 确定游戏的概念、目标受众和核…

手写 分页

子组件&#xff1a;TimePage.vue 效果图 <template><div class"click-scroll-X"><!-- 上 --><!-- eslint-disable-next-line --><span class"left_btn" :disabled"pageNo 1" click"leftSlide"><&…

PanoFlow:学习360°用于周围时间理解的光流

1.摘要&#xff1a; 光流估计是自动驾驶和机器人系统中的一项基本任务&#xff0c;它能够在时间上解释交通场景。自动驾驶汽车显然受益于360提供的超宽视野&#xff08;FoV&#xff09;◦ 全景传感器。 然而&#xff0c;由于全景相机独特的成像过程&#xff0c;为针孔图像设计…

python输出奇数:如何使用Python输出奇数?

Python输出奇数的方法有很多种&#xff0c;下面给出一种使用for循环的实现方式&#xff1a;上述代码的输出结果为&#xff1a; Python输出奇数的方法有很多种&#xff0c;下面给出一种使用for循环的实现方式&#xff1a; # 定义一个变量n&#xff0c;表示要输出的奇数的最大值…

NSIC2050JBT3G 车规级120V 50mA ±15% 用于LED照明的线性恒流调节器(CCR) 增强汽车安全

随着汽车行业的巨大变革&#xff0c;高品质的汽车氛围灯效、仪表盘等LED指示灯效已成为汽车内饰设计中不可或缺的元素。深力科安森美LED驱动芯片系列赋能智能座舱灯效充满艺术感和科技感——NSIC2050JBT3G LED驱动芯片&#xff0c;实现对每路LED亮度和颜色进行细腻控制&#xf…

SLAM从入门到精通(launch文件学习)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 大家应该还记得我们在一开始学习ros的时候&#xff0c;如果需要启动一个节点的话&#xff0c;需要首先打开roscore&#xff0c;接着用rosrun打开对…

shiro550复现环境搭建

前言 Shiro反序列化漏洞指的是Apache Shiro安全框架中的一个潜在漏洞&#xff0c;该漏洞可能导致攻击者能够通过精心构造的恶意序列化对象来执行任意代码或进行拒绝服务&#xff08;DoS&#xff09;攻击。 这种漏洞的根源是在Shiro的RememberMe功能中&#xff0c;当用户选择“…

C# 实体类转换的两种方式

以下提供两种方式&#xff0c;一种是序列化&#xff0c;一种是泛型反射&#xff1b; 实现功能&#xff1a; 两个实体类数据转换赋值 //学生类 private class Student {public string name { get; set; }public int age { get; set; }public string className { get; set;…