乐趣区

关于redis:真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 应用集群模式进行部署。

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

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));

找到了代码地位后,剖析其业务流程:

1.3 告警起因

综合上图剖析,此次占用率过高的起因能够分为间接起因与根本原因:

1.3.1 间接起因

查看经营后盾的确发现有用户在此前三天创立了大量的跑批工作,导致缓存中样本与后果数量减少,从而导致缓存使用率过高。

1.3.2 根本原因

剖析代码后,依据上文形容缓存中次要有两块数据:样本与后果

  • 首先是样本在缓存中存了一下随机又取出,本操作毫无意义,只会占用缓存容量。
  • 后果分批分片存储,此步骤有意义,次要是为了避免在多任务并行处理时,如果不将数据分片存入缓存,很有可能导致数据在 JVM 中占用大量空间,进而导致 FULL GC 的问题。(之前文章已剖析)
  • 跑批完结后,两头数据失常来说曾经无用,然而业务流程并没有被动删除无用数据,而是期待超时后主动删除,本操作会导致数据在缓存中额定存储较长时间。

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

二、问题解决

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

2.1 间接起因

2.1.1 起因剖析

正值 618 前夕,最好不思考操作会对系统产生的影响,因而只能先思考让对应的用户临时进行创立跑批,免得持续占用内存导致影响线上业务。

此时察看监控图又发现:

用户是从三天前就开始创立跑批工作的(对应缓存开始增长的工夫点),然而缓存的有效期只有一天,按情理来说从第二天开始每天的缓存都应该降落不少才对(因为前一天的曾经过期了),为什么看监控图这三天的缓存使用率近乎直线回升呢?

此处能够思考 30s,与 Redis 个性无关。

依据之前刚零碎的学完 Redis 的相干个性,关注到此问题点后,开始思考有没有可能是 尽管咱们设置了超时工夫是一天,然而实际上数据并没有被物理删除呢(Redis 的缓存淘汰策略)?

随后查看 R2M 相干文档:

其中:

如果带有生存工夫的键十分多的话,那么在键的生存工夫变为0,直到键真正被删除这两头,可能会有一段比较显著的工夫距离。

这不就是咱们的个性吗,从刚刚的咱们搜寻大 key 的图中能够看到,咱们有很多带超时的 key 并且 size 都很大,很有可能尽管曾经超时了(即 TTL 变为 0)但该数据并没有拜访,并且因为 R2M 渐进式删除,某一个 Key 可能会在超时后很久才会被真正的物理删除

至此,间接起因的根本原因曾经找到了。

2.1.2 解决

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

留神:

Redis 应用以下两种形式删除过期的键

  • 当一个键被拜访时,程序会对这个键进行查看,如果键曾经过期,那么该键将被删除。
  • 底层零碎会在后盾渐进地查找并删除那些过期的键,从而解决那些曾经过期、然而不会被拜访到的键。

首先通过拜访的模式去删除数据必定是愚昧且没必要的(都能拜访并且晓得要过期了不如间接删除),那么能够抉择进步渐进的查找速率。从而将那些超时的数据物理删除

于是咱们分割了 R2M 对应运维:

根据上述聊天记录可知,的确有参数能够调整渐进式物理删除的频率,而咱们的缓存集群则之前因为不出名起因(我的项目团队做过更换)被调整为了 10,大概升高了六倍,此后果也合乎咱们的预期,从侧面印证了咱们的猜测是正确的。

过后处于 618 前夕,咱们没有并没有批改该参数,在 618 之后,咱们随即提了工单批改该参数,将该参数从 10 进步到 80:

审批通过之后,咱们察看 r2m 的降落速率:

能够看到,在 6.20 号咱们调整了参数后,在没有大批量数据增加后,r2m 使用率的降落速率显著变快

至此,缓存使用率告警的间接起因曾经解决结束,真正的起因就是有大量的 key 过期后并没有被删除,察看后续缓存使用率都没有太高。此外,即时有大量的跑批工作,如果不是在同一天内间接增加,个别不会造成使用率过高的问题。

2.2 根本原因

上文在调整参数后,根本能够满足用户的日常业务需要,然而如果用户的确有一天之内有大量跑批工作的需要,那么此计划仍不能解决基本问题,还会造成使用率过高有可能影响线上业务的危险。

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

  1. 样本就曾经齐全没有必要存储在缓存中,所以在代码中间接采纳参数传递的形式传入给下一步流程。
  2. 后果分片必定是有意义的,起因上文中也提到了,然而 redis 缓存的空间(即内存)是比拟贵重的,而 oss 的空间老本(硬盘)则是比拟便宜的,并且思考自身业务就是离线业务,时效性以及查问速率并不是最要害的因素,因而综合思考将跑批的后果分片数据存储至 oss
  3. 在跑批流程完结后,被动删除 oss 中的后果分片数据,防止数据无用后仍占用存储空间。此外在 oss 端设置 7 天主动删除,避免零碎起因异样导致数据未删除而永恒存在

综上,联合以上的优化思维,从新设计的流程图如下:

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

2.3 优化率

上线实现后的缓存应用状况:

能够看到简直是断崖式降落。

缓存优化率:

革新前

革新后

(8.35-0.17)/8.35≈97.96%

三、总结

本文次要通过一封告警邮件,由浅入深的将零碎中存在的缓存问题与流程优化。在解决完理论问题后,咱们应该都会有一些心得与总结,从而下次本人在开发过程中防止再犯这样的问题,也可能本人对本人再做一次总结与归档。要做到可能 知其然更要知其所以然。以下总结是本人的由浅入深的一点点心得。

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

“韩信点兵,多多益善”,一名好的将军就是能将不同的士兵调配不同的职责,从而让士兵可能在本人善于的畛域内各尽其职。对咱们研发来说,抉择不同的中间件实现不同的性能则是可能反馈咱们研发的技术水平。

像本文来说,可供存储两头数据的有好多中间件,除了 Redis、Oss,还有 Mysql、Hive、ES、CK 等,咱们须要依据不同的业务需要抉择不同的中间件实现对应的性能。本案例中很显著数据的个性为 大量的、不要求速度 的,而 Redis 的存储个性为 大量的、疾速的,很显著这两个是南辕北辙的需要与业务,因而咱们在选用时应该抉择正确的中间件。

3.2 学习技术细节有没有用

其实之前也有学了很多的技术、框架的实现细节,然而绝大多数都是学完就学完了,并没有太多实际的环节。而这次案例剖析正好处于之前刚刚学完 Redis 的相干细节,没隔多久就可能利用到本次的实际环节,算是实践与实际联合。此外这次案例也可能很大水平上晋升本人的学习趣味。

作者:京东科技 韩国凯

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

退出移动版