真·Redis缓存优化—97%的优化率你见过嘛? | 京东云技术团队

本文通过一封618前的R2M(公司内部缓存组件,可以认为等同于Redis)告警,由浅入深的分析了该告警的直接原因与根本原因,并根据原因提出相应的解决方法,希望能够给大家在排查类似问题时提供相应的思路。

一、问题排查

1.1 邮件告警

正值618值班前夕,某天收到了邮件告警,告警内容如下:

您好,R2M监控报警,请您及时追踪一下! 报警信息:告警ID:6825899, 应用:zr_credit_portal, 负责人:zhangsan, 告警类型:内存使用率, 时间:2023-06-15 16:00:04。实例:(10.0.0.0:5011-slave), 当前:9212MB 超过警戒值:8748MB 实例最大内存:10800 MB,内存使用率:85 % ;实例:(10.0.0.0:5023-master), 当前:9087MB 超过警戒值:8748MB 实例最大内存:10800 MB,内存使用率:84 % ;实例:(10.0.0.0:5017-master), 当前:9214MB 超过警戒值:8748MB 实例最大内存:10800 MB,内存使用率:85 % ;

大概内容是说,R2M集群使用率已经达到85%,需要紧急处理下。

我们的缓存集群配置如下,总共32400MB容量,三主三从,每个主节点10800M容量,目前使用最高的已经达到9087M。R2M使用集群模式进行部署。

image-20230713164727082

首先的思路就是使用大key统计,查看是哪些缓存占用了容量。因为大key统计是从节点进行扫描,所以不用担心会影响线上主流程。

image-20230713170916595

1.2 代码分析

大key主要分为两类,一类是xxx_data,一类是xxx_interfacecode_01,按照此规律去代码中寻找存放key的地方

String dataKey = task.getTaskNo() + "_data";
cacheClusterClient.setex(dataKey.getBytes(), EXPIRATION, DataUtil.objectToByte(paramList));key = task.getTaskNo() + "_" + item.getInterfaceCode() + "_" + partCount;
cacheClusterClient.setex(key.getBytes(), EXPIRATION,DataUtil.objectToByte(dataList));

找到了代码位置后,分析其业务流程:

伏羲运营后台插入数据优化-第 3 页.drawio

1.3 告警原因

综合上图分析,此次占用率过高的原因可以分为直接原因与根本原因:

1.3.1 直接原因

查看运营后台确实发现有用户在此前三天创建了大量的跑批任务,导致缓存中样本与结果数量增加,从而导致缓存使用率过高。

1.3.2 根本原因

分析代码后,根据上文描述缓存中主要有两块数据:样本与结果

  • 首先是样本在缓存中存了一下随机又取出,本操作毫无意义,只会占用缓存容量。

  • 结果分批分片存储,此步骤有意义,主要是为了防止在多任务并行处理时,如果不将数据分片存入缓存,很有可能导致数据在JVM中占用大量空间,进而导致FULL GC的问题。(之前文章已分析)

  • 跑批结束后,中间数据正常来说已经无用,但是业务流程并没有主动删除无用数据,而是等待超时后自动删除,本操作会导致数据在缓存中额外存储较长时间。

至此,已经分析出了本次缓存使用率过高的原因(其实还没有,直接原因只分析出了表象,直接原因的“根本原因”还未有结论)。

二、问题解决

上文分析了本次告警的排查过程,以下是如何解决问题,也是分为如何解决直接原因与解决根本原因。

2.1 直接原因

2.1.1 原因分析

正值618前夕,最好不考虑操作会对系统产生的影响,因此只能先考虑让对应的用户暂时停止创建跑批,以免继续占用内存导致影响线上业务。

此时观察监控图又发现:
image.png

用户是从三天前就开始创建跑批任务的(对应缓存开始增长的时间点),但是缓存的有效期只有一天,按道理来说从第二天开始每天的缓存都应该下降不少才对(因为前一天的已经过期了),为什么看监控图这三天的缓存使用率近乎直线上升呢?

此处可以思考30s,与Redis特性有关。

根据之前刚系统的学完Redis的相关特性,关注到此问题点后,开始思考有没有可能是虽然我们设置了超时时间是一天,但是实际上数据并没有被物理删除呢(Redis的缓存淘汰策略)?

随后查看R2M相关文档:

image-20230907145129672

其中:

如果带有生存时间的键非常多的话, 那么在键的生存时间变为0, 直到键真正被删除这中间, 可能会有一段比较显著的时间间隔。

这不就是我们的特性吗,从刚刚的我们搜索大key的图中可以看到,我们有很多带超时的key并且size都很大,很有可能虽然已经超时了(即TTL变为0)但该数据并没有访问,并且由于R2M渐进式删除,某一个Key可能会在超时后很久才会被真正的物理删除

至此,直接原因的根本原因已经找到了。

2.1.2 解决

那么如何解决呢?根据一个Key过期时被物理删除的两种策略:

注意:

Redis 使用以下两种方式删除过期的键

  • 当一个键被访问时,程序会对这个键进行检查,如果键已经过期,那么该键将被删除。

  • 底层系统会在后台渐进地查找并删除那些过期的键,从而处理那些已经过期、但是不会被访问到的键。

首先通过访问的形式去删除数据肯定是愚蠢且没必要的(都能访问并且知道要过期了不如直接删除),那么可以选择提高渐进的查找速率。从而将那些超时的数据物理删除

于是我们联系了R2M对应运维:

image.png

根据上述聊天记录可知,确实有参数可以调整渐进式物理删除的频率,而我们的缓存集群则之前因为不知名原因(项目团队做过更换)被调整为了10,大约降低了六倍,此结果也符合我们的预期,从侧面印证了我们的猜想是正确的。

当时处于618前夕,我们没有并没有修改该参数,在618之后,我们随即提了工单修改该参数,将该参数从10提高到80:

image-20230713183643785

审批通过之后,我们观察r2m的下降速率:

image-20230713183917668

可以看到,在6.20号我们调整了参数后,在没有大批量数据添加后,r2m使用率的下降速率明显变快

至此,缓存使用率告警的直接原因已经解决完毕,真正的原因就是有大量的key过期后并没有被删除,观察后续缓存使用率都没有太高。此外,即时有大量的跑批任务,如果不是在同一天内直接添加,一般不会造成使用率过高的问题。

2.2 根本原因

上文在调整参数后,基本可以满足用户的日常业务需求,但是如果用户确实有一天之内有大量跑批任务的需求,那么此方案仍不能解决根本问题,还会造成使用率过高有可能影响线上业务的风险。

那么要从根本上解决此问题,就需要对跑批流程进行优化,按照1.2中流程示意以及原因分析:

  1. 样本就已经完全没有必要存储在缓存中,所以在代码中直接采用参数传递的方式传入给下一步流程。

  2. 结果分片肯定是有意义的,原因上文中也提到了,但是redis缓存的空间(即内存)是比较宝贵的,而oss的空间成本(硬盘)则是比较廉价的,并且考虑本身业务就是离线业务,时效性以及查询速率并不是最关键的因素,因此综合考虑将跑批的结果分片数据存储至oss

  3. 在跑批流程结束后,主动删除oss中的结果分片数据,避免数据无用后仍占用存储空间。此外在oss端设置7天自动删除,防止系统原因异常导致数据未删除而永久存在

综上,结合以上的优化思想,重新设计的流程图如下:

伏羲运营后台插入数据优化-第 4 页.drawio

至此,即时后续用户数据量再大,也无论是分一天创建还是多天创建,都不会导致缓存使用率告警而有可能带来的线上业务问题。

2.3 优化率

上线完成后的缓存使用情况:

image-20230911155108232

可以看到几乎是断崖式下降。

缓存优化率:

改造前

image-20230911155042608

改造后

image-20230911155540703

(8.35-0.17)/8.35≈97.96%

三、总结

本文主要通过一封告警邮件,由浅入深的将系统中存在的缓存问题与流程优化。在解决完实际问题后,我们应该都会有一些心得与总结,从而下次自己在开发过程中避免再犯这样的问题,也能够自己对自己再做一次总结与归档。要做到能够知其然更要知其所以然。以下总结是自己的由浅入深的一点点心得。

3.1 不同中间件应该负责不同的事

“韩信点兵,多多益善”,一名好的将军就是能将不同的士兵分配不同的职责,从而让士兵能够在自己擅长的领域内各尽其职。对我们研发来说,选择不同的中间件完成不同的功能则是能够反应我们研发的技术水平。

像本文来说,可供存储中间数据的有好多中间件,除了Redis、Oss,还有Mysql、Hive、ES、CK等,我们需要根据不同的业务需求选择不同的中间件完成对应的功能。本案例中很明显数据的特性为大量的、不要求速度的,而Redis的存储特性为少量的、快速的,很明显这两个是背道而驰的需求与业务,因此我们在选用时应该选择正确的中间件。

3.2 学习技术细节有没有用

其实之前也有学了很多的技术、框架的实现细节,但是绝大多数都是学完就学完了,并没有太多实践的环节。而这次案例分析正好处于之前刚刚学完Redis的相关细节,没隔多久就能够应用到本次的实践环节,算是理论与实践结合。此外这次案例也能够很大程度上提升自己的学习兴趣。

作者:京东科技 韩国凯

来源:京东云开发者社区 转载请注明来源

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

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

相关文章

将切分的图片筛选出有缺陷的

将切分的图片筛选出有缺陷的 需求代码 需求 由于之前切分的图像有一些存在没有缺陷,需要再次筛选 将可视化的图像更改后缀 更改为xml的 可视化代码 可视化后只有7000多个图像 原本的图像有1W多张 代码 # 按照xml文件删除对应的图片 # coding: utf-8 from P…

服务网关Gateway_微服务中的应用

没有服务网关 问题: 地址太多安全性管理问题 为什么要使用服务网关 网关是微服务架构中不可或缺的部分。使用网关后,客户端和微服务之间的网络结构如下。 注意: 网关统一向外部系统(如访问者、服务)提供REST API。在Sp…

DEV gridview多表头设计

先上图: 第一步转化gridview变成bandedGridview类型 一步步按照自己想要的格式添加,先把表头格式全部弄好,然后在拖拉对应的列。 注意:全部弄完后把列表头设置不可见

基于微信小程序的快递配送管理平台系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能:具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

建议阿里、百度、华为们,不要着急抢行业大模型的“饭碗”!

大数据产业创新服务媒体 ——聚焦数据 改变商业 近几个月,国内大模型领域一个很明显的发展态势,就是大家扎堆行业大模型。不仅各个垂直领域的企业发布多个行业大模型,而且百度、阿里巴巴、华为、腾讯、京东等头部巨头,也把行业大…

面试打底稿⑤ 项目一的第一部分

简历原文 抽查部分 项目描述 该项目旨在服务广州地区的快递物流,实现了下单、快递员取派件、订单转运单、线路规划、网点设置等功能。 责任描述 登录系统优化,双token三验证模式实现设置token状态、提高登录安全性的效果 模拟问答 1.能简单介绍一下…

当网络设置为自动获取dns时而实际nds是8.8.8.8,1.1.1.1的解决方法

笔记本换网络环境后,网络设置的是自动获取IP和自动获取dns。但使用命令:config/all命令时发现dns总是8.8.8.8,1.1.1.1。导致csdn上不了。 8.8.8.8,1.1.1.1:是谷歌的dns。 解决办法: 在支行中输入regedit打开注册表后&#xff0…

什么是Redux?它的核心概念有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是Redux?⭐ 它的核心概念有哪些?⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发…

【ACL2023】Event Extraction as Question Generation and Answering

论文题目:Event Extraction as Question Generation and Answering 论文来源:ACL2023 论文链接:Event Extraction as Question Generation and Answering - ACL Anthology 代码链接:GitHub - dataminr-ai/Event-Extraction-as-…

Java-day18(网络编程)

网络编程 1.概述 Java提供跨平台的网络类库,可以实现无痛的网络连接,程序员面对的是一个统一的网络编程环境 网络编程的目的:直接或间接地通过网络协议与其他计算机进行通信 网络编程的两个主要问题: 1.如何准确定位网络上一台…

基于SSM的保险业务管理系统设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

Kubernetes(K8s):未来云原生应用的引擎

文章目录 Kubernetes的核心概念和架构为什么K8s是构建云原生应用的首选工具?云原生应用的好处和挑战容器编排的重要性:Docker和KubernetesKubernetes生态系统:核心组件和附加工具实际应用:企业如何在生产环境中使用K8s未来展望&am…

【VUE复习·2】@click 之事件处理与函数(可传参);@click 阻止事件冒泡应用场景;@click 多修饰符应用场景(高级)

总览 1.“事件处理”是什么 2.click 函数参数传递应用 3.click 阻止事件冒泡应用场景 4.click 多修饰符应用场景(高级) 一、“事件处理”是什么 1.概念 我们在和页面进行交互时,进行点击或滑动或其他动作时,我们操作的是 DOM …

MR混合现实在军事课堂教学中的应用演示

战场模拟:利用MR技术可以创建逼真的战场模拟环境,将学生置身于真实的战场场景中,可以体验和学习各种作战技巧和战术策略。学生可以通过佩戴MR头盔或眼镜,观察虚拟的场景,并与虚拟对象进行互动,如操作武器、…

深度学习|如何确定 CUDA+PyTorch 版本

对于深度学习初学者来说,配置深度学习的环境可能是一大难题,因此本文主要讲解CUDA; cuDNN; Pytorch 三者是什么,以及他们之间的依赖关系。 CUDA CUDA(Compute Unified Device Architecture)是由NVIDIA开发的用于并行计…

【C/C++笔试练习】——printf在使用%的注意事项、for循环语句的三个条件、运算符优先级、删除公共字符

文章目录 C/C笔试练习1.%符号在printf用作格式说明符的注意事项(1)输出%5.3s(2)判断%中小数点含义 2.for循环语句的三个条件(3)判断循环次数(4)判断循环次数 3.运算符优先级&#xf…

独立站引流,如何在Reddit进行营销推广?

Reddit是目前最被忽视却最具潜力的社交媒体营销平台之一,它相当于国内的百度贴吧,是美国最大的论坛,也是美国第五大网站,流量仅次于Google、Youtube、Facebook以及亚马逊。 如果会玩,Reddit也可以跟其他的社交媒体营销…

Spring 学习(九)整合 Mybatis

1. 整合 Mybatis 步骤 导入相关 jar 包 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency>…

Django之初入门

一&#xff09;Django简介 1.简介 Django是一个开源的Python Web框架&#xff0c;它以简洁高效的方式帮助开发者构建复杂的Web应用程序。Django采用了MVC&#xff08;Model-View-Controller&#xff09;的架构模式&#xff0c;通过强大的工具和功能&#xff0c;提供了一套完整…

PHP 变动:PHP 8 版本下字符串与数值的弱比较

文章目录 参考环境声明弱比较隐式类型转换字符串连接数学运算布尔判断相等运算符 字符串与数值的弱比较字符串转化为数值的具体规则字符串与数值的弱比较一般情况科学计数法前缀 0E 与 0e PHP8 在字符串与数值的弱比较方面做出的改动数值字符串优化 参考 项目描述搜索引擎Bing…