Redis中的BigKey如何发现和处理

news2024/7/4 5:15:17

文章目录

      • 什么是BigKey?
        • 大键的存在通常被认为是不好的,主要原因:
        • 常见的bigkey原因:
      • BigKey危害?
        • 占用大量内存空间
        • 阻塞服务器进程
        • 加长持久化时间
        • 延长复制时间
        • 增加内存碎片
        • 加重AOF重写压力
        • 降低查找效率
      • 如何发现BigKey?
        • info命令
        • scan命令
        • Redis-cli
        • 第三方工具
        • 日志监控
        • 定期主动扫描
      • 如何删除BigKey?
        • DEL命令
        • 重新设计键
        • 使用UNLINK
        • 配合事务操作
        • 分段删除
        • 使用SCAN命令
        • 热重启
      • Hash类型Bigkey如何处理?
        • 拆分Bigkey
        • 使用Hash数据结构
        • 海量计数器转换为Bitmaps
        • 采用更紧凑的编码
        • 控制字段的数量
        • 使用内存优化参数
        • 海量小值分离
      • 写在最后

579a429daf314744b995f37351b46548

什么是BigKey?

通常来说,如果一个键值对大于一定阈值(例如 1MB),它就可以被认为是一个大键或 bigkey。

大键的存在通常被认为是不好的,主要原因:

​ 1.占用大量内存,可能导致内存不足
​ 2.增加内存碎片,降低内存利用效率
​ 3.增加SAVE和复制时间
​ 4.增加AOF重写时间
​ 5.压缩列表元素过多,降低查找效率

所以在使用 Redis 时,应该尽量避免 bigkey 的产生。

常见的bigkey原因:

​ 1.一个 Hash 类型键值对字段过多
​ 2.一个 Set 类型包含了过多的成员
​ 3.一个 List 类型包含了过多的元素
​ 4.一个 Bitmaps 类型映射了过大的内容
​ 5.一个 Zset 类型包含了过多的成员

一般建议 bigkey 的大小控制在 1MB 以内为宜。


BigKey危害?

Redis 中存在的BigKey会带来以下几个方面的危害:

image-20231014225057908

占用大量内存空间

BigKey由于值过于庞大,会占用Redis sehr大比例的内存,从而对Redis的内存使用造成浪费和压力。

阻塞服务器进程

当需要对BigKey进行操作如删除、更改值时,这些操作需要花费较长时间,会造成Redis主进程阻塞,影响Redis的正常工作。

加长持久化时间

Redis需要进行持久化将数据写入磁盘保存,BigKey会因其数据量大而导致持久化过程非常缓慢。

延长复制时间

当Redis进行主从复制时,同步BigKey也会非常慢,可能导致从服务器的数据同步效率下降。

增加内存碎片

BigKey的大值会导致Redis内存中产生大量不连续的碎片,降低内存利用效率。

加重AOF重写压力

BigKey会导致AOF文件过大,当Redis进行AOF重写时,需要处理大量数据,加重服务器压力。

降低查找效率

对于一些集合性的数据结构如Hash、List等,BigKey中的数据量庞大,会降低查找效率。
所以,对于Redis来说,发现并解决BigKey问题是非常重要的。

如何发现BigKey?

在Redis中,可以通过以下几种方式发现BigKey:

image-20231014225207261

info命令

使用Redis的info命令,查看keyspace部分,观察biggest_key_size的大小,当biggest_key_size过大时,说明存在BigKey。

可以通过analyze命令的keyspace部分来观察biggest_key_size,判断是否存在BigKey。例如:

127.0.0.1:6379> info keyspace
# Keyspace
db0:keys=5,expires=0,avg_ttl=0
db1:keys=8,expires=0,avg_ttl=0
db2:keys=4,expires=0,avg_ttl=0
db3:keys=5,expires=0,avg_ttl=0
db4:keys=4,expires=0,avg_ttl=0
db5:keys=5,expires=0,avg_ttl=0
db6:keys=5,expires=0,avg_ttl=0
db7:keys=4,expires=0,avg_ttl=0
db8:keys=4,expires=0,avg_ttl=0
db9:keys=4,expires=0,avg_ttl=0
db10:keys=5,expires=0,avg_ttl=0
db11:keys=5,expires=0,avg_ttl=0
db12:keys=5,expires=0,avg_ttl=0
db13:keys=4,expires=0,avg_ttl=0
db14:keys=4,expires=0,avg_ttl=0
db15:keys=4,expires=0,avg_ttl=0

# ... 略

biggest_key_size:8192

从上面的biggest_key_size大小可以看出,目前存在value超过8KB的大键。

scan命令

使用scan命令迭代Redis中的键,同时利用Redis的debug object命令查看key对应的value大小,如果超过阈值即判定为BigKey。

可以通过SCAN命令迭代Redis中的键,并配合DEBUG OBJECT命令判断键值大小,来发现BigKey。例如:

127.0.0.1:6379> scan 0 match * count 10
1) "17"
2)  1) "key:1"
    2) "key:2"
    3) "key:3"
    4) "key:4" 
    5) "bigkey"

127.0.0.1:6379> debug object bigkey
Value at:0x7fdafb0258e0 refcount:1 encoding:raw serializedlength:1001927

上面先通过SCAN命令扫描出键,然后使用DEBUG OBJECT判断bigkey的值大小,结果显示serializedlength超过1MB。所以这是一个BigKey。我们可以编写一个循环使用SCAN的程序,设置一个大小阈值,所有值超过阈值的键都记录下来,从而扫描出所有BigKey。相比直接遍历键空间,SCAN实现渐进式扫描,可以避免命令阻塞,更安全的发现BigKey。

Redis-cli

使用redis-cli工具的–bigkeys参数,该参数会扫描Redis中的键并返回所有大小超过指定阈值的BigKey。

第三方工具

使用一些第三方Redis可视化管理工具,如Redis Enterprise、Astra等,这些工具提供了BigKey检测功能。

日志监控

分析Redis日志,关注slave缓慢或者持久化被block的情况,这可能与BigKey有关。

定期主动扫描

可以通过脚本等定期主动扫描Redis键值,当键值超过阈值则记录为BigKey。

下面写一个脚本示例

import redis
import time

# Redis连接
redis_client = redis.Redis(host='localhost', port=6379) 

# 大键阈值 - 100MB
BIG_KEY_THRESHOLD = 100 * 1024 * 1024

# 扫描间隔 - 1小时
SCAN_INTERVAL = 3600 

def scan_big_keys():
    cursor = '0'
    big_keys = []

    while cursor != 0:
        cursor, keys = redis_client.scan(cursor=cursor, count=100)

        for key in keys:
            size = redis_client.debug_object(key)['serializedlength']
            if size > BIG_KEY_THRESHOLD:
                big_keys.append({'key': key, 'size': size})

    return big_keys

while True:
    big_keys = scan_big_keys()

    if big_keys:
        print(f'Found {len(big_keys)} big keys')
        for bk in big_keys:
            print(f'  {bk["key"]} {bk["size"]}')

    time.sleep(SCAN_INTERVAL)

主要步骤包括:

​ 1.使用SCAN命令渐进式扫描键空间
​ 2.调用DEBUG OBJECT命令获取键值大小
​ 3.比较大小判断是否为大键
​ 4.定期循环扫描这个脚本可以灵活调整大键阈值、扫描间隔等参数。

你可以将它部署为持续运行的任务,自动发现Redis中的大键。

综合利用上述各种方式,可以有效发现Redis中存在的BigKey,作为后续优化的依据。


如何删除BigKey?

在Redis中删除BigKey可以通过以下几种方法:

DEL命令

直接使用DEL命令删除键即可快速删除单个BigKey,但是这会导致数据丢失。

DEL big_key
重新设计键

如果BigKey是由于键设计不当导致的,那么可以重新设计键结构,拆分BigKey。
例如将原来的一个Hash BigKey拆分为多个Hash小Key。

使用UNLINK

UNLINK可以异步删除键,不会堵塞服务器。但也存在数据丢失风险。

UNLINK big_key 
配合事务操作

可以先用MULTI开启事务,再使用GET、DEL等命令处理BigKey,最后用EXEC提交事务。这样可以避免阻塞服务器。

分段删除

对于List、Hash等结构的BigKey,可以通过区间查找、分段删除的方式进行分批删除,避免一次性删除耗时太长。

使用SCAN命令

可以通过SCAN命令渐进式地扫描并删除BigKey。

热重启

可以考虑停止Redis服务,并删除持久化文件(rdb、aof),然后重启,这样可以直接清除所有BigKey,但会损失全部数据。

可以根据实际情况选择最佳方案删除BigKey。

Hash类型Bigkey如何处理?

对于Redis中的Hash类型Bigkey,可以通过以下几种方式进行优化:

拆分Bigkey

最直接的方法是将一个大的Hash Key拆分为多个小的Hash Key,防止单个键值对过大。例如

将user:{uid} 拆分为 user:{uid}:info、user:{uid}:data等。
使用Hash数据结构

Redis的Hash相比字符串可以大幅度减少内存使用。可以考虑将字符串值转换为Hash结构,字段由字符串改为Hash。

海量计数器转换为Bitmaps

如果Hash中的字段是简单的计数器,可以考虑用Bitmaps替代,由于Bitmaps有压缩特性,可以减少内存使用。

采用更紧凑的编码

对于Hash的值,如果是数字,可以选择更紧凑的编码方式,如整形float编码转为整数int编码。

控制字段的数量

对Hash字段数量进行限制,避免单个Hash过多字段,导致结构过大。

使用内存优化参数

调整Redis的ziplist、hash-max-ziplist-value等参数,优化内存使用。

redis>config get hash-max-ziplist-entries
1) "hash-max-ziplist-entries"
2) "512"  --默认原来是512

redis>config set hash-max-ziplist-entries 1000
"OK"
redis>config get hash-max-ziplist-entries
1) "hash-max-ziplist-entries"
2) "1000" --调整为1000,但是不建议调整超过1000
海量小值分离

如果Hash中存在大量小值字段,可以将这些小值字段拆分出去,单独用一个Hash Key存储。

假设我们有一个 user:{uid} 的 hash 类型 bigkey,里面存储了用户的名称、年龄、手机号等信息。其中手机号字段的值都是数字且较小。
我们可以这样进行海量小值的分离:

  1. 为手机号创建新的 hash key

    user:{uid}:phone
    
  2. 遍历 user:{uid} 的 hash,提取所有手机号字段和值,存入 user:{uid}:phone

    HGETALL user:{uid} # 遍历获取所有字段
    ...
    HSET user:{uid}:phone {phone_field} {phone_value} # 存储到新key
    
  3. 从 user:{uid} 删除这些手机号字段

    HDEL user:{uid} {phone_field_1} {phone_field_2} ... # 删除手机号字段
    

这样我们就将海量的手机号小值从大key中分离出来,单独用一个 hash 存储。

分离后的优点:

1.原来的 user:{uid} 键值对会缩小,不再存在大量小值

2.由于是小值,在新 key 中可以使用更紧凑的内存编码存储

3.查找手机号等小值时,只需要操作 user:{uid}:phone 即可,避免遍历全量大key

综合使用这些优化策略,可以有效减小Hash类型Bigkey的内存占用。


写在最后

感谢您的支持和鼓励! 😊🙏

如果大家对相关文章感兴趣,可以关注公众号"架构殿堂",会持续更新AIGC,java基础面试题, netty, spring boot, spring cloud等系列文章,一系列干货随时送达!

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

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

相关文章

002数据安全传输-多端协议传输平台:配置Oracle数据库-19c及导入数据信息

002多端协议传输平台:配置Oracle数据库-19c及导入数据信息 文章目录 002多端协议传输平台:配置Oracle数据库-19c及导入数据信息1. 数据库准备2. 导入sql脚本2.1 原版Oracle-11g脚本2.2 新版Oracle-19c脚本2.3 命令行导入脚本 3. 删除系统中数据库信息sql…

在雷电模拟器9上安装magisk并安装LSPosed模块以及其Manager管理器(二)之LSPosed的使用

上一篇已经安装好LSPosed模块及其Manager管理器,参考文章 在雷电模拟器9上安装magisk并安装LSPosed模块以及其Manager管理器(一)-CSDN博客 安装完成后,在模拟器上出现图标如下: 一、运行LSPosed 二、仓库模块 内容非…

《向量数据库指南》——Milvus Cloud和Elastic Cloud 特性对比

随着以 Milvus 为代表的向量数据库在 AI 产业界越来越受欢迎,诸如 Elasticsearch 之类的传统数据库和检索系统也开始行动起来,纷纷在快速集成专门的向量检索插件方面展开角逐。 例如,在提供类似插件的传统数据库中,Elasticsearch 8.0 首屈一指,推出了包括向量插入和最相似…

蓝桥杯 第 1 场算法双周赛 第1题 三带一 c++ map 巧解 加注释

题目 三带一【算法赛】https://www.lanqiao.cn/problems/5127/learning/?contest_id144 问题描述 小蓝和小桥玩斗地主,小蓝只剩四张牌了,他想知道是否是“三带一”牌型。 所谓“三带一”牌型,即四张手牌中,有三张牌一样&#…

字符串进行 URL 编码处理

// URL_test.cpp : Defines the entry point for the console application. //#include "stdafx.h"#include <stdio.h> #include <stdlib.h> #include <string.h>// 判断字符是否需要进行 URL 编码 static bool needs_encoding(char c) {if ((c &g…

力扣第538题 把二叉搜索树转换为累加树 c++

题目 538. 把二叉搜索树转换为累加树 中等 相关标签 树 深度优先搜索 二叉搜索树 二叉树 给出二叉 搜索 树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&#xff08;Greater Sum Tree&#xff09;&#xff0c;使每个节点 node 的新值…

相似性搜索:第 3 部分--混合倒排文件索引和产品量化

接续前文&#xff1a;相似性搜索&#xff1a;第 2 部分&#xff1a;产品量化 SImilarity 搜索是一个问题&#xff0c;给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。 一、介绍 在数据科学中&#xff0c;相似性搜索经常出现在NLP领域&#xff0c;搜索引擎或推…

【RocketMQ系列二】通过docker部署单机RocketMQ

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

goland安装教程

安装版本&#xff1a; goland-2023.2.3.exe

(滑动窗口) 76. 最小覆盖子串 ——【Leetcode每日一题】

❓76. 最小覆盖子串 难度&#xff1a;困难 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找的子字符串…

C语言 sizeof

定义 sizeof是C语言的一种单目操作符。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。 使用方法 用于数据类型 sizeof(type) 数据类型必须用括号括住 用于变量 size…

C#,数值计算——数据建模Proposal的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class Proposal { public Normaldev gau { get; set; } null; private double logstep { get; set; } public Proposal(int ranseed, double lstep) { this.gau…

OpenRemote: Java 开源 IoT 物联网开发平台,匹配智慧城市、智能家居、能源管理

OpenRemote 是一个直观、用户友好的基于Java语言的开源 IoT 物联网设备管理平台&#xff0c;它包括从连接设备到构建应用程序和特定领域的智能应用程序的所有功能和特性。通过OpenRemote物联网平台&#xff0c;用户可以收集和处理来自不同设备的传感器数据&#xff0c;适用于智…

办理400电话客服中心的申请步骤及注意事项

引言&#xff1a; 在现代商业环境中&#xff0c;提供优质的客户服务是企业成功的关键之一。而办理400电话客服中心可以帮助企业建立一个高效、专业的客户服务团队&#xff0c;提升客户满意度和忠诚度。本文将介绍办理400电话客服中心的申请步骤及注意事项&#xff0c;帮助企业顺…

java: 无效的目标发行版: 11

第一步&#xff1a; 第二步&#xff1a; 第三步

BGP初解笔记

BGP&#xff08;公网用得多&#xff09;&#xff1a; 一、名词&#xff1a; 1、BGP speaker&#xff1a;启用了BGP进程的路由器 2、BGP对等体&#xff1a;双方建立BGP邻居关系的设备&#xff1a; a.IBGP对等体&#xff0c;AS号一致&#xff0c;为IBGP对等体&#xff0c;有水…

如何做好商品的库存管理?哪些指标是衡量库存的指标

如何做好商品的库存管理&#xff1f;哪些指标是衡量库存的指标&#xff1f;库存分析的方法繁杂且广泛&#xff0c;选择正确的方法才能更好的进行库存分析。 本文将为大家盘点一些常用的库存分析方法和监控指标&#xff0c;全程干货&#xff0c;建议收藏&#xff01; 01 如何进…

网络编程中的重难点:套接字的应用和理解

什么是网络编程 网络编程&#xff0c;指的是网络上的主机&#xff0c;通过不同的进程&#xff0c;以编程的方式实现网络通信&#xff08;或成为网络数据传输&#xff09;。 发送端和接收端 在一次网络数据传输时&#xff1a; 发送端&#xff1a;数据的发送方进程&#xff0…

GD32F103 ADC

1. 模拟量于数字量。 模拟量&#xff1a;反应真实世界中的物理量&#xff08;比如温度&#xff0c;压力&#xff0c;长度&#xff09;模拟量通常是通过电压&#xff0c;电流等信号来表示。 数字量&#xff1a;通常是0和1来表示某个物理量的变化。 2. ADC&#xff08;模拟量转…

通过HTTP发送大量数据的三种方法

在网络的早期时期&#xff0c;人们发送的文件大小仅为几KB。到了2023年&#xff0c;我们享受着高分辨率的MB级别图像&#xff0c;并在几GB的4K&#xff08;即将是8K&#xff09;视频中观看。 即使有良好的互联网连接&#xff0c;下载一个5GB的文件仍然需要一些时间。如果你拥有…