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” 拼接

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

    @Test
    public 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”

代码

    @Test
    public 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.mfbz.cn/a/485729.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧农业害虫性诱监测专用设备-稻飞虱测报仪

TH-DF122随着科技的飞速发展和智慧农业的兴起&#xff0c;传统农业正在迎来一场革命性的变革。在这场变革中&#xff0c;智慧农业害虫性诱监测专用设备——稻飞虱测报仪&#xff0c;以其独特的魅力和高效的功能&#xff0c;正成为现代农业的得力助手。它不仅提升了农业生产的智…

Vue2(十):全局事件总线、消息订阅与发布、TodoList的编辑功能、$nextTick、动画

一、全局事件总线&#xff01;&#xff01; 任意组件间通信 比如a想收到别的组件的数据&#xff0c;那么就在a里面给x绑定一个demo自定义事件&#xff0c;所以a里面就得有一个回调函数吧&#xff0c;然后我要是想让d组件给a穿数据&#xff0c;那就让d去触发x的自定义事件&…

el-tree 使用按钮切换当前选中的节点(上一节点,下一节点)

<!-- 选择树上下切换 --> <template><div><el-tree:data"treeData":props"defaultProps"node-key "id"ref"tree"node-click"handleNodeClick"></el-tree><div><el-button click&qu…

Github Action Auto build docker Auto deploy

简介 整个流程比较清晰&#xff0c;实现的是基于Github 定向的往ECS做发布 探索 自动化打包发布一般流程&#xff1a; 本地环境打镜像 CI/CD 环境打镜像 以上的流程使用于比较大的项目&#xff0c;受限于环境&#xff0c;打算对上面流程做简化&#xff0c;使用github acti…

SpringBoot3+Vue3项目的阿里云部署--将后端以及前端项目打包

一、后端&#xff1a;在服务器上制作成镜像 1.准备Dockerfile文件 # 基础镜像 FROM openjdk:17-jdk-alpine # 作者 MAINTAINER lixuan # 工作目录 WORKDIR /usr/local/lixuan # 同步docker内部的时间 RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ…

Path MTU(路径最大传输单元)

目录 前言&#xff1a; IPV6不支持中间设备分片原因&#xff1a; IPV6报文分片使用的扩展报头&#xff08;44&#xff09;所包含的参数 IPv6报文分片过程 源节点分片数据包 前言&#xff1a; 在IPv4网络中&#xff0c;报文如果过大&#xff0c;则需要分片进行发送&#xf…

网络核心知识点 - 网络通信技术 XHR(XMLHttpRequest) 和 Fetch

一、关于 AJAX&#xff08;一种思想和方法&#xff09; 浏览器本身就具备网络通信的能力&#xff0c;但在早期&#xff0c;浏览器并没有把这个能力开放给JS。最早是微软在IE浏览器中把这一能力向JS开放&#xff0c;让JS可以在代码中实现发送请求&#xff0c;并不会刷新页面。Aj…

MS5910PA——10到16bit、内置参考振荡器 R/D转换器,替代AD2S1210

产品简述 MS5910PA 是一款可配置 10bit 到 16bit 分辨率的旋 变数字转换器。片上集成正弦波激励电路&#xff0c;正弦和余弦 允许输入峰峰值幅度为 2.3V 到 4.0V &#xff0c;频率范围为 2kHz 至 20kHz 。 转换器可并行或串行输出角度和速度对应的 数字量。 MS…

计算机软件安全

一、软件安全涉及的范围 1.1软件本身的安全保密 软件的本质与特征&#xff1a; 可移植性 寄生性 再生性 可激发性 攻击性 破坏性 …… 知识产权与软件盗版 软件商品交易形式不透明&#xff0c;方式多样&#xff0c;传统商标标识方法不适用&#xff1b; 盗版方法简捷…

IntelliJ IDEA集成git配置账号密码

1 背景说明 刚使用IDEA&#xff0c;本地也安装Git&#xff0c;在提交和拉取代码的时候&#xff0c;总提示登录框&#xff0c;而且登录框还不能输入账号密码&#xff0c;只能输入登录Token。如下&#xff1a; 从而无法正常使用IDEA的Git功能&#xff0c;很苦恼。 2 解决方法 …

C语言数据结构易错知识点(5)(插入排序、选择排序)

插入排序&#xff1a;直接插入排序、希尔排序 选择排序&#xff1a;直接选择排序、堆排序 上述排序都是需要掌握的&#xff0c;但原理不会讲解&#xff0c;网上有很多详尽地解释&#xff0c;本文章主要分享一下代码实现上应当注意的事项 1.直接插入排序&#xff1a; 代码实…

FastWiki(增强AI对话功能)企业级智能客服功能介绍

知识库对话功能 什么是知识库对话&#xff1f; 我们需要找到AI的知识能力是有限的他们的知识都截止于他们训练数据的时间&#xff0c;你提问他们更新的数据的时候他们就会出现乱回复。而知识库则是利用Prompt给于AI更多的知识从而让他回复更准确&#xff0c; 以下就是知识库的…

如何通过idea搭建一个SpringBoot的Web项目(最基础版)

通过idea搭建一个SpringBoot的Web项目 文章目录 通过idea搭建一个SpringBoot的Web项目一、打开idea&#xff0c;找到 create new project二、创建方式三、配置项目依赖四、新建项目模块五、总结 一、打开idea&#xff0c;找到 create new project 方式1 方式2 二、创建方式 新…

更换 Jenkins 插件下载源(解决 Jenkins 插件安装失败)【图文详细教程】

Jenkins 插件安装失败的情况 这里提一下&#xff0c;Jenkins 插件安装失败&#xff0c;不一定是下载源的问题&#xff0c;还有可能你下载的 Jenkins 的版本与插件的版本不匹配&#xff0c;Jenkins 的版本较低&#xff0c;而安装的插件是为新的 Jenkins 版本准备的&#xff0c;此…

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

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

牛客题霸-SQL篇(刷题记录三)

本文基于前段时间学习总结的 MySQL 相关的查询语法&#xff0c;在牛客网找了相应的 MySQL 题目进行练习&#xff0c;以便加强对于 MySQL 查询语法的理解和应用。 由于涉及到的数据库表较多&#xff0c;因此本文不再展示&#xff0c;只提供 MySQL 代码与示例输出。 以下内容是…

笔试总结01

1、spring原理 1、spring原理 spring的最大作用ioc/di,将类与类的依赖关系写在配置文件中&#xff0c;程序在运行时根据配置文件动态加载依赖的类&#xff0c;降低的类与类之间的藕合度。它的原理是在applicationContext.xml加入bean标记,在bean标记中通过class属性说明具体类…

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的特性一&#…

天软高频因字库——委托订单因子及资金流向因子发布

天软始终致力于构建完善而丰富的因子库服务体系&#xff0c;陆续推出了股票因子、基金因子、指数因子等众多因子数据及评价数据。 本月天软推出高频委托订单&资金流向相关因子&#xff0c;继续补充和完善天软高频特色因子库&#xff0c;至此该因子库已包含36个因子表单&…

基于SpringBoot+Vue共享客栈管理系统(源码+部署说明+演示视频+源码介绍+lw)

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