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.rhkb.cn/news/290420.html

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

相关文章

路由的完整使用

多页面和单页面 多页面是指超链接等跳转到另一个HTML文件,单页面是仍是这个文件只是路由改变了页面的一部分结构. 路由的基本使用 使用vue2,则配套的路由需要是第3版. 1)下载vue-router插件 2)引入导出函数 3)new 创建路由对象 4)当写到vue的router后只能写路由对象,因此只…

Webpack常见插件和模式

目录 目录 目录认识 PluginCleanWebpackPluginHtmlWebpackPlugin自定义模版 DefinePlugin的介绍 ( 持续更新 )Mode 配置 认识 Plugin Loader是用于特定的模块类型进行转换&#xff1b; Plugin可以用于执行更加广泛的任务&#xff0c;比如打包优化、资源管理、环境变量注入等 …

国内IP切换软件:解锁网络世界的新钥匙

在数字化快速发展的今天&#xff0c;互联网已成为我们生活中不可或缺的一部分。然而&#xff0c;伴随着网络使用的深入&#xff0c;许多用户逐渐意识到&#xff0c;不同的IP地址可能会带来截然不同的网络体验。为了应对这一问题&#xff0c;国内IP切换软件应运而生&#xff0c;…

Java与Go:字符串转IP

在本文中&#xff0c;我们将了解如何将简单的对比Java和Go是如何将字符串解析为IP地址。 Java 在Java中&#xff0c;将字符串转换为IP地址最无脑的一个方法&#xff1a; import java.net.InetAddress; import java.net.UnknownHostException;public class Main {public stat…

深圳区块链交易所app系统开发,撮合交易系统开发

随着区块链技术的迅速发展和数字资产市场的蓬勃发展&#xff0c;区块链交易所成为了数字资产交易的核心场所之一。在这个快速发展的领域中&#xff0c;区块链交易所App系统的开发和撮合交易系统的建设至关重要。本文将探讨区块链交易所App系统开发及撮合交易系统的重要性&#…

数据库系统概论(超详解!!!) 第四节 关系数据库标准语言SQL(Ⅱ)

1.数据查询 SELECT [ ALL | DISTINCT] <目标列表达式>[&#xff0c;<目标列表达式>] … FROM <表名或视图名>[&#xff0c; <表名或视图名> ] … [ WHERE <条件表达式> ] [ GROUP BY <列名1> [ HAVING <条件表达式> ] ] [ ORDER BY…

【数据结构 | 图论】如何用链式前向星存图(保姆级教程,详细图解+完整代码)

一、概述 链式前向星是一种用于存储图的数据结构&#xff0c;特别适合于存储稀疏图&#xff0c;它可以有效地存储图的边和节点信息&#xff0c;以及边的权重。 它的主要思想是将每个节点的所有出边存储在一起&#xff0c;通过数组的方式连接&#xff08;类似静态数组实现链表…

SpringCloudConfig 使用git搭建配置中心

一 SpringCloudConfig 配置搭建步骤 1.引入 依赖pom文件 引入 spring-cloud-config-server 是因为已经配置了注册中心 <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</…

Elasticsearch从入门到精通-07ES底层原理学习

Elasticsearch从入门到精通-07ES底层原理和高级功能 &#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是程序员行走的鱼 &#x1f4d6; 本篇主要介绍和大家一块学习一下ES底层原理包括集群原理、路由原理、分配控制、分配原理、文档分析原理、文档并发安全原理以及一些高…

SQL-CRUD-2数据库实验

目录 第一关任务描述 相关知识 插入完整内容的行 插入选定内容的行 编程要求 测试说明 第一关代码 第二关任务描述 相关知识 删除表中的指定行 删除表中的所有行 编程要求 测试说明 第二关代码 第三关任务描述 相关知识 更新表中的指定行 编程要求 测试说明…

【多线程系列】你先说说synchronized的实现原理

面试官&#xff1a;听说你精通多线程&#xff0c;那我就考考你吧 面试官&#xff1a;不用慌尽管说&#xff0c;错了也没关系&#x1f60a;。。。 以贴近现实的【面试官面试】形式来分享技术&#xff0c;本期是《多线程系列》&#xff0c;感兴趣就关注我吧❤️ 面试官&#xff1…

L2-047 锦标赛

这题没做出来&#xff0c;查了一些博客&#xff0c;下面是我比较能接受的理解和书写方式。 读完题可以发现这是一个满二叉树&#xff0c;并且可以得到每场比赛失败者的信息&#xff08;决赛是胜利者和失败者都可以得到&#xff09; 对于一场比赛&#xff0c;它的胜利者要么是左…

Typora结合PicGo + Github搭建个人图床

目录 一 、GitHub仓库设置 1、新建仓库 2、创建Token 并复制保存 二、PicGo客户端配置 1、下载 & 安装 2、配置图床 三、Typora配置 一 、GitHub仓库设置 1、新建仓库 点击主页右上角的 号创建 New repository 填写仓库信息 2、创建Token 并复制保存 点击右上角…

JAVA的NIO和BIO底层原理分析

文章目录 一、操作系统底层IO原理1. 简介2. 操作系统进行IO的流程 二、BIO底层原理1. 什么是Socket2. JDK原生编程的BIO 三、Java原生编程的NIO1. 简介2. NIO和BIO的主要区别3. Reactor模式4. NIO的三大核心组件5. NIO核心源码分析 一、操作系统底层IO原理 1. 简介 IO&#x…

Python工具箱系列(五十一)

九宫格与词云 对图片进行九宫格切割&#xff0c;并且放到微信朋友圈曾经风靡一时。对于python来说&#xff0c;这个也非常简单。 from PIL import Image import mathdef ninerectanglegrid(inputfilename):"""实现九宫格切割Args:inputfilename (string): 输入…

【Vue3进阶】- 第2学堂小商城实战课程前言

该教程为进阶教程&#xff0c;如果你还不了解Vue3的基础知识&#xff0c;可以先前往Vue3基础教程&#xff0c;从入门到实战。 学习时遇到的任何疑问都欢迎在相应课文页面下方的问答区进行提问哦 我能学到什么&#xff1f; 编程写法千千万&#xff0c;实现需求是第一。 教程中…

Python+Django+Yolov5路面墙体桥梁裂缝特征检测识别html网页前后端

程序示例精选 PythonDjangoYolov5路面墙体桥梁裂缝特征检测识别html网页前后端 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonDjangoYolov5路面墙体桥梁裂缝特征检测识别html网页前…

List操作add,clear,addall报错UnsupportedOperationException的解决办法

ArrayList和Arrays.ArrayList是两码事 ArrayList 支持 add&#xff0c;clear&#xff0c;addall Arrays.ArrayList不支持add&#xff0c;clear&#xff0c;addall 这个方法的使用时候&#xff0c;传递的数组必须是对象数组&#xff0c;而不是基本数据类型 JDK源码 /** *返回由…

Python-VBA编程500例-024(入门级)

字符串写入的行数(Line Count For String Writing)在实际应用中有着广泛的应用场景。常见的应用场景有&#xff1a; 1、文本编辑及处理&#xff1a;在编写或编辑文本文件时&#xff0c;如使用文本编辑器或文本处理器&#xff0c;经常需要处理字符串并确定其在文件中的行数。这…

Numpy 初体验

文章目录 第1关&#xff1a;Numpy 创建数组第2关&#xff1a;Numpy 数组的基本运算第3关&#xff1a;Numpy 数组的切片与索引第4关&#xff1a;Numpy 数组的堆叠第5关&#xff1a;Numpy 的拆分 第1关&#xff1a;Numpy 创建数组 编程要求 本关的任务是&#xff0c;补全右侧编辑…