Java 面试宝典:什么是大 key 问题?如何解决?

大家好,我是大明哥,一个专注「死磕 Java」系列创作的硬核程序员。
本文已收录到我的技术网站:https://skjava.com。有全网最优质的系列文章、Java 全栈技术文档以及大厂完整面经


回答

Redis 大 key 问题是指某个 key 对应的 value 值很大(注意,不是 key 很大)。大 key 会导致 Redis 性能降低、数据倾斜以及主从同步等问题。一般来说我们应该杜绝大 key,如果遇到了我们就需要对其进行处理,处理过程分为这两个步骤:

  1. 发现大 key。比如利用 redis-cli --bigkeys 或者 Redis RDB Tools
  2. 大 key 的治理方案一般分为两种:
    1. 可删除:使用 UNLINK 命令可以安全地删除大 key。
    2. 不可删除:不可删除的话就将大 key 拆分为多个小 key,或者对 value 进行压缩处理

详解

什么是大 key

首先大 key 不是 key 很大,而是 key 所对应的 value 很大。如果 value 超过某个阈值,那么此时存储这个 value 所对应的 key 就是大 key。

那 value 多大才算大 key 呢?这个阈值没有一个衡量的标准,需要根据具体场景来确定,比如有些场景及时 KB 是大 key,而有些场景需要几十 MB。

通常情况下,Redis 官方提到的大 key 阈值是基于经验值,例如:

  • 对于列表、集合、有序集合、 哈希表,在超过 1 万个元素时被认为是大 key。
  • 对于字符串,当它的大小达到几百 KB 时可能被认为是大 key。

为了后面演示,我们通过程序向 Redis 中插入一批数据,表格如下:

  • 字符串
key数据量
bigkey-0130 个 “skjava” 拼接
bigkey-02300 个 “skjava” 拼接
bigkey-033000 个 “skjava” 拼接
bigkey-0430000 个 “skjava” 拼接
bigkey-0560000个 “skjava” 拼接
bigkey-0690000 个 “skjava” 拼接
bigkey-07120000个 “skjava” 拼接

程序如下(数字各位小伙伴就去改下):

    @Testpublic void bigKeyTest() {StringBuffer stringBuffer_01 = new StringBuffer();for (int i = 0; i < 30 ; i++) {stringBuffer_01.append("skjava-" + i + ";");}// 省略StringBuffer stringBuffer_07 = new StringBuffer();for (int i = 0; i < 120000 ; i++) {stringBuffer_07.append("skjava-" + i + ";");}Jedis jedis = new Jedis("127.0.0.1",6379);jedis.set("bigkey-01",stringBuffer_01.toString());//...jedis.set("bigkey-07",stringBuffer_07.toString());}

各个 key 大小如下图:

  • 列表
key数据量
bigkey-0830 个 “skjava”
bigkey-09300 个 “skjava”
bigkey-103000 个 “skjava”
bigkey-1130000 个 “skjava”
bigkey-1260000个 “skjava”
bigkey-1390000 个 “skjava”
bigkey-14120000个 “skjava”

代码

    @Testpublic void bigKeyTest() {List<String> list_08 = new ArrayList<>();for (int i = 0 ; i < 30 ; i++) {list_08.add("skjava-" + i);}// ...List<String> list_14 = new ArrayList<>();for (int i = 0 ; i < 120000 ; i++) {list_14.add("skjava-" + i);}Jedis jedis = new Jedis("127.0.0.1",6379);jedis.lpush("bigkey-08", list_08.toArray(new String[list_08.size()]));// ...jedis.lpush("bigkey-14", list_14.toArray(new String[list_14.size()]));}

列表长度及大小:

大 key 有什么危害

  • 数据倾斜

大 key 所在的 Redis 服务器,会比其他 Redis 服务器占用更多的内存,这种数据倾斜的现象明显违背 Redis-Cluster 的设计思想。

  • 占用内存过高

大 key 会占用更多的内存,可能会导致内存不足,甚至导致内存耗尽,Redis实例崩溃,影响系统的稳定性。

同时,频繁对大 key 进行修改可能会导致内存碎片化,进一步影响性能。

  • 性能下降

大 key 会占用大量的内存,导致内存碎片增加,进而影响Redis的性能。同时,对大 key 的读写操作消耗的时间都会比较长,这会导致单个操作阻塞 Redis 服务器,影响整体性能。

尤其是执行像 HGETALLSMEMBERSZRANGELRANGE 等命令时,如果操作的是大 key,可能会导致明显的延迟。

  • 主从同步延迟

如果配置了主从同步,大 key 会导致主从同步延迟,由于大 key 占用的内存比较大,当主节点上的大 key 发生变化时,同步到从库时,会导致网络和处理上的延迟。

如何找到大 key

1、–bigkeys

在使用redis-cli命令链接 Redis 服务的时候,加上 --bigkeys 参数,就可以找出每种数据类型的最大 key 及其大小。

bigkeys 使用的是 SCAN 来迭代 Redis 中所有的 key,对于每种数据类型(字符串、列表、集合、有序集合、哈希表),它都会记录下占用最多内存的 key。但是该操作是资源密集型的,不建议直接在生产上面执行,建议在从节点或者低流量时段执行。

这种方式对集合类型来说不是特别友好,因为它只统计集合元素的多少,而不是实际占用内存,但是集合元素多,并不代表占用内存大。

2、SCAN命令

SCAN 命令结合 MEMORY USAGESCAN 可以迭代数据库中的 key,然后结合 MEMORY USAGE 命令检查每个 key 的大小。

redis-cli --scan --pattern '*' | xargs -L 1 -I '{}' sh -c 'echo {} && redis-cli memory usage {}'

这个命令会显示每个 key 的内存使用量:

  • redis-cli --scan --pattern '*':遍历所有的 key。
  • xargs -L 1 -I '{}' sh -c 'echo {} && redis-cli memory usage {}':对于每个 key,首先打印 key 的名称(echo {}),然后打印其内存使用情况(redis-cli memory usage {}

3、Redis RDB Tools工具

RdbTools 是一个用于分析 Redis 数据库文件(.rdb 文件)的工具。它可以帮助我们理解 Redis 内存使用情况,找出大 key,并以此优化 Redis 实例。

例如,我们要找出占用内存最多的 5 个 key:

rdb --command memory --largest 5 dump.rdb

再如,获取字节数大于 10000 的 key:

rdb --command memory --bytes 10000 dump.rdb

关于Redis RDB Tools 的安装与使用:https://www.cnblogs.com/zyf98/p/15627047.html

如何处理大 key

如何处理大 key 呢?方案有如下两类:

1、可删除

如果这些大 key 可以删除,则我们可以使用 UNLINK 删除这些大 key。UNLINK 是异步的,不会像 DEL 命令一样会阻塞 Redis 服务,这种特性使得它比较适合大型的列表、集合、散列或有序集合的删除。

2、不可删除

对于不可删除的大 key,我们一般有两种方式出路:

  1. 分解。将大 key 拆分为多个小 key,降低单key的大小,读取可以用mget批量读取。
  2. 压缩。如果是 String 类型,我们可以采用压缩算法对其进行压缩处理。

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

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

相关文章

C语言——sizeof与strlen的对比

一.sizeof 我们在学习操作符的时候&#xff0c;就了解到了sizeof操作符&#xff0c;它的作用是求参数所占内存空间的大小&#xff0c;单位是字节。如果参数是一个类型&#xff0c;那就返回参数所占的字节数。 #include <stdio.h>int main() {int a 10;size_t b sizeo…

Mamba 基础讲解【SSM,LSSL,S4,S5,Mamba】

文章目录 Mamba的提出动机TransformerRNN Mama的提出背景状态空间模型 (The State Space Model, SSM)线性状态空间层 (Linear State-Space Layer, LSSL)结构化序列空间模型 &#xff08;Structured State Spaces for Sequences, S4&#xff09; Mamba的介绍Mamba的特性一&#…

美团2024届秋招笔试第二场编程真题

要么是以0开头 要么以1开头 选择最小的答案累加 import java.util.Scanner; import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和…

C# 右键快捷菜单(上下文菜单)的两种实现方式

在C#中&#xff0c;ContextMenuStrip是一种用于创建右键菜单的控件。它提供了一种方便的方式来为特定的控件或窗体添加自定义的上下文菜单选项。有两种实现方式&#xff0c;如下&#xff1a; 一.通过ContextMenuStrip控件实现 1.从工具箱中拖一个ContextMenuStrip控件到窗体上…

LLM - 大语言模型的分布式训练 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136924304 大语言模型的分布式训练是一个复杂的过程&#xff0c;涉及到将大规模的计算任务分散到多个计算节点上。这样做的目的是为了处…

领域、系统和组织-《实现领域驱动设计》中译本评点-第2章(4)

相关链接 DDD领域驱动设计批评文集>> 汪峰哭晕在厕所-《实现领域驱动设计》中译本评点-第2章&#xff08;1&#xff09; 可不是乱打的-《实现领域驱动设计》中译本评点-第2章&#xff08;2&#xff09; “领域”的错误定义-《实现领域驱动设计》中译本评点-第2章&…

Tomcat介绍,Tomcat服务部署

目录 一、Tomcat 介绍 二、Tomcat 核心技术和组件 2.1、Web 容器&#xff1a;完成 Web 服务器的功能 2.2、Servlet 容器&#xff0c;名字为 catalina&#xff0c;用于处理 Servlet 代码 2.3、JSP 容器&#xff1a;用于将 JSP 动态网页翻译成 Servlet 代码 Tomcat 功能组件…

Window全网解析网站下载视频

全网解析网站下载视频 介绍m3u8格式cbox格式 解析视频下载的方法方法一解析视频下载视频 方法二老王浏览器下载使用浏览器解析下载视频 总结 介绍 今天分享一下如何解析网页中的视频进行下载。通常情况下我们打开的某某网站的视频是不提供下载接口的&#xff0c;甚至说你下载了…

ClickHouse--11--物化视图

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.物化视图什么是物化视图? 1.1 普通视图1.2 物化视图1.3 优缺点1.4 基本语法1.5 在生产环境中创建物化视图1.6 AggregatingMergeTree 表引擎3.1 概念3.2 Aggregat…

面试算法-87-分隔链表

题目 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x …

【JAVA】通过JAVA实现用户界面的登录

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-wyCvaz0EBNwHcwsi {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

Linux系统——硬件命令

目录 一.网卡带宽 1.查看网卡速率——ethtool 网卡名 2.查看mac地址——ethtool -P 网卡名 二、内存相关 1.显示系统中内存使用情况——free -h 2.显示内存模块的详细信息——dmidecode -t memory 三、CPU相关 1.查看CPU架构信息——lscpu 2.性能模式 四、其他硬件命…

C语言字节对齐关键字#pragma pack(n)的使用

0 前言 在进行嵌入式开发的过程中&#xff0c;我们经常会见到对齐操作。这些对齐操作有些是为了便于实现指针操作&#xff0c;有些是为了加速对内存的访问。因此&#xff0c;学习如何使用对齐关键字是对于嵌入式开发是很有必要的。 1 对齐规则 1.0 什么叫做对齐 众所周知&a…

牛客NC170 最长不含重复字符的子字符串【高频 中等 map、滑动窗口 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/48d2ff79b8564c40a50fa79f9d5fa9c7 思路 用一个hashmap记录每个字母的index如果这个字母已经在map里了说明已经有重复了这样就更新看这个字母上次出现的index需要注意的是这种情况&#xff1a;“bacbca”这里的a…

PCB中常用电子器件封装学习——【一网打尽】

‘ 上图是这个世界上大概所有的封装种类&#xff0c;当然我们日常硬件电路设计肯定用不到这么多&#xff0c;接下来我将介绍几种工程上常用的封装&#xff0c;配以图片方便大家理解学习。在电子器件选型的时候&#xff0c;避免选择到一些非常难以焊接的封装电子器件。

使用amd架构的计算机部署其他架构的虚拟机(如:arm)

1 下载quem模拟器 https://qemu.weilnetz.de/w64/2 QEMU UEFI固件文件下载(引导文件) 推荐使用&#xff1a;https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd3 QEMU 安装 安装完成之后&#xff0c;需要将安装目录添加到环境变…

Jenkins的快速入门

文章目录 一、Jenkins是什么&#xff1f;二、Jenkins安装和持续集成环境配置1.持续集成流程说明2.Gitlab代码托管服务器安装Gitlab简介&#xff1a;Gitlab安装Gitlab的使用切换中文添加组创建用户将用户添加到组创建项目idea中代码上传Gitlab 3.Jenkins持续集成环境服务器安装J…

华为北向网管NCE开发教程(5)打包org.omg.CosNotification找不到

1问题描述 在IDE中&#xff0c;代码能正常运行&#xff0c;但是打包的时候&#xff0c;会抱不到一些类 2问题原因 导入的本地包中&#xff0c;能在IDE中找到&#xff0c;但是在使用maven打包时&#xff0c;maven找不到这些依赖包 3解决办法 将依赖包通过maven安装到maven…

通过 Socket 手动实现 HTTP 协议

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

[Python人工智能] 四十四.命名实体识别 (5)利用bert4keras构建Bert-CRF实体识别模型(实体位置)

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解如何实现中文命名实体识别研究,构建BiGRU-CRF模型实现。这篇文章将继续以中文语料为主,介绍融合Bert的实体识别研究,使用bert4keras和kears包来构建Bert+BiLSTM-CRF模型。然而,该代码最终结…