Reids的BigKey和HotKey

news2024/12/26 15:20:11

1.什么是BigKey和HotKey

1.1.Big Key

Redis big key problem,实际上不是大Key问题,而是Key对应的value过大,因此严格来说是Big Value问题,Redis value is too large (key value is too large)。

到底多大的value会导致big key问题,并没有统一的标准。

例如,对于String类型的value,有时候超过5M属于big key,有时候稳妥起见,超过10K就可以算作Bigey。

Big Key会导致哪些问题呢?

1、由于value值很大,序列化和反序列化时间过长,网络时延也长,从而导致操作Big Key的时候耗时很长,降低了Redis的性能。

2、在集群模式下无法做到负载均衡,导致负载倾斜到某个实例上,单实例的QPS会比较高,内存占用比较多。

3、由于Redis是单线程,如果要对这个大Key进行删除操作,被操作的实例可能会被block住,从而导致无法响应请求。

Big Key是如何产生的呢?

一般是程序设计者对于数据的规模预料不当,或设计考虑遗漏导致的Big Key的产生。

在某些业务场景下,很容易产生Big Key,例如KOL或者流量明星的粉丝列表、投票的统计信息、大批量数据的缓存,等等。

1.2.Hot Key

Hot Key,也叫Hotspot Key,即热点Key。如果某个特定Key突然有大量请求,流量集中到某个实例,甚至导致这台Redis服务器因为达到物理网卡上线而宕机,这个时候其实就是遇到了热点Key 问题。

热点key会导致很多系统问题:

1、流量过度集中,无法发挥集群优势,如果达到该实例处理上限,导致节点宕机,进而冲击数据库,有导致缓存雪崩,让整个系统挂掉的风险。

2、由于Redis是单线程操作,热点Key会影响所在示例其他Key的操作。

2.如何发现BigKey和HotKey

2.1.发现BigKey

1、通过Redis命令查询BigKey。

以下命令可以扫描Redis的整个Key空间不同数据类型中最大的Key。-i 0.1 参数可以在扫描的时候每100次命令执行sleep 0.1 秒。

Redis自带的bigkeys的命令可以很方便的在线扫描大key,对服务的性能影响很小,单缺点是信息较少,只有每个类型最大的Key。

$ redis-cli -p 999 --bigkeys -i 0.1
复制代码

2、通过开源工具查询BigKey。

使用开源工具,优点在于获取的key信息详细、可选参数多、支持定制化需求,后续处理方便,缺点是需要离线操作,获取结果时间较长。

比如,redis-rdb-tools 等等。

$ git clone https://github.com/sripathikrishnan/redis-rdb-tools 
$ cd redis-rdb-tools
$ sudo python setup.py install 
$ rdb -c memory dump-10030.rdb > memory.csv
复制代码

2.2.发现HotKey

1、hotkeys 参数

Redis 在 4.0.3 版本中添加了 hotkeys (github.com/redis/redis…)查找特性,可以直接利用 redis-cli --hotkeys 获取当前 keyspace 的热点 key,实现上是通过 scan + object freq 完成的。

2、monitor 命令

monitor 命令可以实时抓取出 Redis 服务器接收到的命令,通过 redis-cli monitor 抓取数据,同时结合一些现成的分析工具,比如 redis-faina,统计出热 Key。

3.BigKey问题的解决方法

发现和解决BigKey问题,可以参考以下思路:

1、在设计程序之初,预估value的大小,在业务设计中就避免过大的value的出现。

2、通过监控的方式,尽早发现大Key。

3、如果实在无法避免大Key,那么可以将一个Key拆分为多个部分分别存储到不同的Key里。

下面以List类型的value为例,演示一下拆分解决大Key问题的方法。

有一个User Id列表,有1000万数据,如果全部存储到一个Key下面,会非常大,可以通过分页拆分的方式存取数据。

下面是存取数据的代码实现:

/**
 * 将用户数据写入Redis缓存
 *
 * @param userIdList
 */
public void pushBigKey(List<Long> userIdList) {
    // 将数据1000个一页进行拆分
    int pageSize = 1000;
    List<List<Long>> userIdLists = Lists.partition(userIdList, pageSize);

    // 遍历所有分页,每页数据存到1个Key中,通过后缀index进行区分
    Long index = 0L;
    for (List<Long> userIdListPart : userIdLists) {
        String pageDataKey = "user:ids:data:" + (index++);
        // 使用管道pipeline,减少获取连接次数
        redisTemplate.executePipelined((RedisCallback<Long>) connection -> {
            for (Long userId : userIdListPart) {
                connection.lPush(pageDataKey.getBytes(), userId.toString().getBytes());
            }
            return null;
        });
        redisTemplate.expire(pageDataKey, 1, TimeUnit.DAYS);
    }

    // 存完数据,将数据的页数存到一个单独的Key中
    String indexKey = "user:ids:index";
    redisTemplate.opsForValue().set(indexKey, index.toString());
    redisTemplate.expire(indexKey, 1, TimeUnit.DAYS);
}

/**
 * 从Redis缓存读取用户数据
 *
 * @return
 */
public List<Long> popBigKey() {
    String indexKey = "user:ids:index";
    String indexStr = redisTemplate.opsForValue().get(indexKey);
    if (StringUtils.isEmpty(indexStr)) {
        return null;
    }

    List<Long> userIdList = new ArrayList<>();

    Long index = Long.parseLong(indexStr);
    for (Long i = 1L; i <= index; i++) {
        String pageDataKey = "user:ids:data:" + i;
        Long currentPageSize = redisTemplate.opsForList().size(pageDataKey);
        List<Object> dataListFromRedisOnePage = redisTemplate.executePipelined((RedisCallback<Long>) connection -> {
            for (int j = 0; j < currentPageSize; j++) {
                connection.rPop(pageDataKey.getBytes());
            }
            return null;
        });
        for (Object data : dataListFromRedisOnePage) {
            userIdList.add(Long.parseLong(data.toString()));
        }
    }

    return userIdList;
}
复制代码

4.HotKey问题的解决方法

如果出现了HotKey,可以考虑以下解决方案:

1、使用本地缓存。比如在服务器缓存需要请求的热点数据,这样通过服务器集群的负载均衡,可以避免将大流量请求到Redis。

但本地缓存会引入数据一致性问题,同时浪费服务器内存。

2、HotKey将复制多份,随机打散,使用代理请求。

/**
 * 将HotKey数据复制20份存储
 *
 * @param key
 * @param value
 */
public void setHotKey(String key, String value) {
    int copyNum = 20;
    for (int i = 1; i <= copyNum; i++) {
        String indexKey = key + ":" + i;
        redisTemplate.opsForValue().set(indexKey, value);
        redisTemplate.expire(indexKey, 1, TimeUnit.DAYS);
    }
}

/**
 * 随机从一个拷贝中获取一个数据
 *
 * @param key
 * @return
 */
public String getHotKey(String key) {
    int startInclusive = 1;
    int endExclusive = 21;
    String randomKey = key + ":" + RandomUtils.nextInt(startInclusive, endExclusive);
    return redisTemplate.opsForValue().get(randomKey);
}
复制代码

 

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

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

相关文章

各行业执法图传系统建设建议(华脉智联内参二)

各行业执法图传系统建设建议 让执法透明&#xff0c;不断提高执法工作效能 题记&#xff1a;为实现执法过程中的证据固定与执法场景记录&#xff0c;采用照相机、录音笔或固定监控等传统手段进行取证一直是最本源的需求。随着时代的变迁&#xff0c;传统的手段取证已无法满足完…

知识图谱构建:py2neo案例100个知识点应用

连接到 Neo4j 数据库执行一条简单的 Cypher 查询从查询结果中提取节点和关系插入一个新节点并与另一个节点建立关系根据标签查找节点根据属性查找节点根据关系查找节点在事务中执行多条查询使用索引查找节点使用约束确保唯一性删除节点和关系使用 py2neo.ogm 在 Python 中创建对…

访问学者申请要求及各国情况

访问学者申请要求及各国情况&#xff0c;下面就随知识人网小编一起来看一看。一、访问学者申请要求1、自身条件&#xff1a;访问学者主要是参看申请人当前的工作背景&#xff0c;专业背景以及科研背景等。在职群体申请访学需要具备本科学历和学位。此外&#xff0c;最重要的就是…

2023年,开挖电商这座金矿,有飞项这个协同工具就够了

2023年电商潜力怎样&#xff1f;据Morgan Stanley 研究&#xff0c;全球电商渗透还未见顶&#xff0c;物流发展、移动设备普及和市场拓展等因素仍然有利于电商发展&#xff0c;长期来看仍有增长空间&#xff0c;当前3.3万亿美元的电商市场规模有望在2026年增长到5.4万亿。 如何…

测试的准入准出

测试的准入准出 测试的准入住处是指什么情况下可以开始当前版本的测试工作&#xff0c;什么情况下可以结束当前版本的测试工作。不同项目、不同公司的测试准入准出标准都会有所不同。下面介绍一些通用的测试准入准出标准。 测试准入标准如下&#xff1a; (1)开发编码结束&#…

webpack概念

webpack概念webpackwebpack-概念webpack-使用准备webpack-基础使用webpack-更新打包webpack-配置修改webpack-打包流程图webpack 使用ES6模块化默认导出和导入 // 默认导出 export default {a: 10,b: 20 }// 默认导入 import Obj from js文件路径按需导出和导入 // 按需导出…

【每日一题】【LeetCode】【第三天】删除有序数组中的重复项

删除有序数组中重复项的解决之路 这个标签是简单&#xff0c;所以比较好过。 题干描述 根据题目描述&#xff0c;重点在于原地删除&#xff0c;也就是空间复杂度为O(1)。 测试案例&#xff08;部分&#xff09; 第一次 根据题目描述&#xff0c;重点在于原地删除。 class…

解决Linux【-bash: fork: retry: 没有子进程】

解决Linux【-bash: fork: retry: 没有子进程】问题发现问题解决设置Linux最大用户线程数设置单个用户可用最大进程数问题发现 日常工作中&#xff0c;服务器连不上&#xff0c;好在昨天登陆的服务器用户没有下线&#xff0c;然后执行任何命令时返回- bash: fork: retry: 没有子…

React(coderwhy)- 03(高阶组件+动画)

1.React性能优化SCU React更新机制 React的更新流程 ◼ React在props或state发生改变时&#xff0c;会调用React的render方法&#xff0c;会创建一颗不同的树。 ◼ React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI&#xff1a;  如果一棵树参考另外一棵树进行完…

可观测产品的最佳实践,涵盖端到端的可观测解决方案丨阿里云用户组深圳站

2022 年 9 月 28 日&#xff0c;阿里云在深圳举办了第 11 场阿里云用户组&#xff08;AUG&#xff09;活动&#xff0c;活动主题“可观测性实践”吸引了众多技术从业者及企业管理者来到现场。通过本次活动&#xff0c;参会企业了解到三块内容&#xff1a;1. Java 应用最佳实验&…

小蓝本 第一本 《因式分解技巧》 第八章 多项式的一次因式 笔记 (第八天)

小蓝本 第一本 《因式分解技巧》 第八章 多项式的一次因式 笔记 &#xff08;第八天&#xff09;前言余数定理有理根求法第一步第二步(可能有理根多的情况下&#xff0c;可以用)第三步快速识别特殊有理根情况1情况2求解注意习题8题目题解改错前言 坚持的第8天&#xff0c;因为…

北大陈斌Python算法笔记(一)

前言 &#x1f340;作者简介&#xff1a;被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 &#x1f341;个人主页&#xff1a;红中 &#x1f342;不就是蓝桥杯嘛&#xff0c;干他&#xff01;&#xff01;我堂堂 线性结构 线性结构是一种有序数…

优先级反转问题及解决办法

优先级反转问题及解决办法什么是优先级反转解决方法1&#xff1a;优先级继承解决方法2&#xff1a;优先级天花板总结什么是优先级反转 优先级反转&#xff0c;是指在多线程的环境下&#xff0c;并且使用了信号量时&#xff0c;可能会出现的这样一种不合理的现象&#xff0c;即…

@PostConstruct 和 @PreDestroy 使用

目录1.简介2.使用3.注意事项4.执行顺序5.测试6.测试结果1.简介 PostConstruct&#xff1a; Java 自带的注解&#xff0c;在方法上使用该注解&#xff0c;会在项目启动的时候执行被修饰的方法。 PreDestroy&#xff1a; Java 自带的注解&#xff0c;在方法上使用该注解&#xff…

element 日期选择器数据更改,第一次进入页面,页面上没有回显(数据格式问题导致)

需求 页面列表数据&#xff0c;默认是展示一个月的数据 遇到的问题 一进来页面&#xff0c;日期选择器上是空的&#xff0c;但绑定的值是有数据的&#xff0c;页面上并没正确回显&#xff0c;但是去手动选择日期&#xff0c;也是可以正常回显的 思考 其实&#xff0c;选择…

【MySQL进阶教程】 索引详细介绍

前言 本文为 【MySQL进阶教程】 索引 相关知识介绍&#xff0c;下边具体将对索引概述&#xff0c;索引结构&#xff08;包括&#xff1a;索引结构概述&#xff0c;二叉树&#xff0c;B-Tree&#xff0c;BTree&#xff0c;Hash&#xff09;&#xff0c;索引分类&#xff0c;索引…

leetcode练习之商品折扣后的最终价格(单调栈算法)

题目描述 给你一个数组 prices &#xff0c;其中 prices[i] 是商店里第 i 件商品的价格。 商店里正在进行促销活动&#xff0c;如果你要买第 i 件商品&#xff0c;那么你可以得到与 prices[j] 相等的折扣&#xff0c;其中 j 是满足 j > i 且 prices[j] < prices[i] 的 最…

JdbcUtils工具类的优化升级——通过配置文件连接mysql8.0,并对mysql8.0中的表进行[简单查询]操作

目录 一、在DogDao中新增查询的功能 二、在DogDaoImpl类中继承基类&#xff0c;并实现接口的功能 三、创建工具接口RowMapper 四、重新定义一个基类BaseDao2 五、新建一个DogDaoImpl2实现类&#xff0c;继承基类BaseDao2&#xff0c;实现DogDao接口的两个查询功能 六、在…

【Kotlin】函数 ⑧ ( 函数引用 作为函数参数 | ::函数名 | 函数类型 作为函数返回值类型 )

文章目录一、函数引用作为函数参数二、函数类型作为函数返回值一、函数引用作为函数参数 函数 作为参数 , 有两种方式 : 传递 Lambda 表达式 , 也就是 匿名函数 作为参数值 ;传递 函数引用 作为参数值 ; 函数引用 可以将 具名函数 转为 函数的参数值 , 只要可以使用 Lambda 表…

程序员真是越来越懒了,Api 文档都懒得写?程序员:Api工具惯的!

关于大多数程序员不爱写文档问题&#xff0c; 我觉得可以从两个方面去拆解&#xff1a;主观原因、客观原因。 1. 客观 - 时间紧任务重&#xff0c;需求变化快 需求方每次都是紧急需求&#xff0c;老板每次都要求敏捷开发&#xff0c;快速响应。 按时交付的压力已经让大多数程…