redis命令大量超时 连接数突增

news2024/9/20 14:52:08

大家好,我是烤鸭:
     今天分享一个线上线上redis命令大量超时,连接数突增的问题。由于不是我这边的业务,只能根据事后的一些客观数据进行分析。

配置:

​ redis 4.0 3主3从,总内存36G。

​ 业务服务7台。

​ 框架 j2cache-2.8

现象

由于有一个需求需要向redis刷入大量数据,在内存刷到一定量时出的问题。

17:20左右 redis 内存达到95%后,触发内存报警。停写后key和内存下降,内存碎片升高。

在这里插入图片描述

在这里插入图片描述

18:20有两个redis节点连接数缓慢增加。

18:50 连接数增长明显,最高为原来的7倍,此时超时明显。

在这里插入图片描述

执行redis命令超时,一个get操作耗时几百耗时甚至几秒。

在这里插入图片描述

重启业务服务后连接数下降,业务恢复。

原因猜测

平时redis内存使用在70%以下,这次刷了很多数据,导致redis升至95%,在停写之后部分key过期或者可能触发了lru,产生了大量的内存碎片。

redis 碎片率记计算公式:

Redis 内存碎片率的计算公式:mem_fragmentation_ratio (内存碎片率)= used_memory_rss (操作系统实际分配给 Redis 的物理内存空间大小)/ used_memory(Redis 内存分配器为了存储数据实际申请使用的内存空间大小)
意思大概是 redis 总申请内存(包含连接等占用的) / redis 数据内存

所以会出现两种情况

  • 申请大内存时候 ,过期清理的内存不够支撑 会向系统申请新的内存 导致 总内存/数据内存=碎片率 升高
  • 数据过期后 内存正常情况下申请的内存空间是不会回收的, 导致数据内存变小,总内存不变, 所以 总内存/数据内存 =碎片率 升高

我们的系统redis使用是没有大key的,所以倾向于第二种情况。

内存碎片的产生时间和停大量写redis的时间一致,但是连接数大概40分钟后开始增长趋势。

后来就一直在想2个问题:

  • 连接数增长的原因?和内存碎片是否有关系?
  • 连接数达到峰值,大量的超时的真实原因是什么?重启业务服务后连接数下降,业务恢复。

问题分析

第一个问题,我们只能从业务源码上进行分析,最近提交的代码和操作。

  • 回源:在一些场景增加了回源写入redis的操作,原来是如果redis没有,就查库。现在是查库后多了一次redis写入,过期时间2小时。

  • 刷数据:有一些别的业务线刷入数据,过期时间30天。

在内存达到90%,刷数据停止写入。内存达标95%,回源停止写入。

项目也是几年没动过了,操作redis的框架:J2Cache,一款国产框架。

由于我们配置了一级缓存和二级缓存,一级本地和二级redis。

操作一级缓存(新增、修改、删除)的时候会通过redis的广播通知其他节点。

后来查了资料,看到有人提过类似issue。跟我们的现象很类似,https://gitee.com/ld/J2Cache/issues/I14IHH。

还有这个,https://gitee.com/ld/J2Cache/issues/I566PG,恰好我

们也开启了拓扑刷新,而且时间更短。

分析到这,感觉连接数增加应该和内存碎片的产生没有关系。

第二个问题,连接数达到峰值,大量的超时的真实原因应该是redis端口号被耗尽,而大量的连接状态是time_waiting,恰好这个数据没有在promethus上采集。重启业务服务,原有连接强制断掉,一切恢复。

端口号被耗尽是怎么发生的。

再回顾一下,其中2个主节点发生连接激增,另一个主节点一点反应都没有。

业务服务有2台在18:08出现超时,其余正常,流量没有增加。后来陆续其他服务也有超时。

redis这边,2个主节点18:08以后连接数有所上升,命令耗时和QPS有所增加,19:10 连接数达到高点。

源码分析

先看下J2Cache的J2CacheBuilder.initFromConfig

一级缓存失效会发送pubsub消息通知redis,由于之前刷了很多短期缓存,导致大量的key短时间过期。

/**
 * 加载配置
 *
 * @return
 * @throws IOException
 */
private void initFromConfig(J2CacheConfig config) {
    SerializationUtils.init(config.getSerialization(), config.getSubProperties(config.getSerialization()));
    //初始化两级的缓存管理
    this.holder = CacheProviderHolder.init(config, (region, key) -> {
        //当一级缓存中的对象失效时,自动清除二级缓存中的数据
        Level2Cache level2 = this.holder.getLevel2Cache(region);
        level2.evict(key);
        if (!level2.supportTTL()) {
            //再一次清除一级缓存是为了避免缓存失效时再次从 L2 获取到值
            this.holder.getLevel1Cache(region).evict(key);
        }
        log.debug("Level 1 cache object expired, evict level 2 cache object [{},{}]", region, key);
        if (policy != null)
            policy.sendEvictCmd(region, key);
    });

    policy = ClusterPolicyFactory.init(holder, config.getBroadcast(), config.getBroadcastProperties());
    log.info("Using cluster policy : {}", policy.getClass().getName());
}

业务服务 18:05的内存释放很多
在这里插入图片描述
业务服务 18:00-19:00的内存波动频繁
在这里插入图片描述

项目中关于拓扑的配置,自适应刷新超时时间10s,每隔15s刷新。

还有个默认配置是如果拓扑失败,自动重连, refreshTriggersReconnectAttempts,默认是5。

@Primary
@Bean("j2CahceRedisConnectionFactory")
public LettuceConnectionFactory lettuceConnectionFactory(net.oschina.j2cache.J2CacheConfig j2CacheConfig) {
    //... 获取配置

    //开启 自适应集群拓扑刷新和周期拓扑刷新
    ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
            // 开启全部自适应刷新
            .enableAllAdaptiveRefreshTriggers() // 开启自适应刷新,自适应刷新不开启,Redis集群变更时将会导致连接异常
            // 自适应刷新超时时间(默认30秒)
            .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(10)) //默认关闭开启后时间为30秒
            // 开周期刷新
            // 默认关闭开启后时间为60秒
            //  ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD 60
            // .enablePeriodicRefresh(Duration.ofSeconds(2))
            // .enablePeriodicRefresh().refreshPeriod(Duration.ofSeconds(2))
            .enablePeriodicRefresh(Duration.ofSeconds(15)) //每隔15秒回刷新
            .build();

    //https://github.com/lettuce-io/lettuce-core/wiki/Client-Options
    ClientOptions clientOptions = ClusterClientOptions.builder()
            .topologyRefreshOptions(clusterTopologyRefreshOptions)
            .build();


    LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder clientConfig = LettucePoolingClientConfiguration.builder();
    clientConfig.commandTimeout(Duration.ofMillis(CONNECT_TIMEOUT));
    clientConfig.poolConfig(getGenericRedisPool(l2CacheProperties, null));
    clientConfig.clientOptions(clientOptions);

	//... node相关信息

    connectionFactory = new LettuceConnectionFactory(clusterConfig, clientConfig.build());

    return connectionFactory;
}

有一些命令执行上的增长趋势。

在这里插入图片描述
del、cluster和publish执行增加。

在这里插入图片描述
原因主要是有2个叠加的:

  • 使用J2Cache框架,在短时间内写入了大量短期缓存数据,导致同时过期的数据增加,而一级缓存过期会发送pubsub消息。(pubilsh命令执行增加很少)
  • 由于redis性能问题,导致拓扑重试次数增加,从而导致后边的连接数激增。(cluster 命令执行次数倒是有所增加,不过很少,跟峰值比完全不是一个档次)

写完这俩结论自己都有点虚,数据上是没有体现的。但是从这出手优化是可以的。

改进:

  • 优化拓扑配置,增加超时时间和刷新周期时间。
  • J2Cache的广播方式由 lettuce改成 rabbitmq。

总结

这篇文章拖了3周没写出来,最后虽然给出了一个分析,但还是感觉不够说服力。毕竟出了问题、第一时间是解决问题,解决之后只能依靠历史的数据进行复盘、分析。一开始大家都说是由于redis内存刷到报警、内存碎片产生导致的,其实应该没啥关系。

由于是老项目,在框架使用上需要注意,可能用了很久的框架,不知道在一些场景上的性能怎么样。比如像这次大量刷入缓存,导致内存急速上、后来停刷之后的大量过期的场景并没有实际运行过。

还有就是出了问题,虽然第一时间找到运维那,不过大家也是一脸懵逼,后来查到有大量的time_waiting链接,ip是业务节点ip,重启业务服务后恢复。果然,出问题不要慌,找专业的人,重启大法牛的。

文章参考

https://blog.csdn.net/Zong_0915/article/details/126302182

https://juejin.cn/post/6844903967298682893

https://juejin.cn/post/6881470475395039239

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

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

相关文章

跨平台代码编写工具 Visual Studio Code

随着生产力的提高,生产工具也在不断的提高。 今天就介绍 目前最好用的工具 Visual Studio Code。 1. 入门 Visual Studio Code 是一款轻量级但功能强大的源代码编辑器,可在您的桌面上运行,适用于 Windows、macOS 和 Linux。它内置了对 Java…

蓝库云|制造业转型不可或缺的“PLM”的作用和真正价值

PLM是产品生命周期管理,是一种应用于在单一地点的企业内部、分散在多个地点的企业内部,以及在产品研发领域具有协作关系的企业之间的,支持产品全生命周期的信息的创建、管理、分发和应用的一系列应用解决方案,它能够集成与产品相关…

如何短期通过PMP考试?

PMP考试相比较其他考试,首先就是PMP是不卡通过率的,所以只要你做题的正确率上去了,那是有很大机会能通过考试的!想要短期通过PMP考试,就得每天安排具体的任务,规划好,按计划去做。抓紧时间&…

QFramework框架学习

主要学习内容TypeEventSystemActionKitTimer类1、TypeEventSystem-适用于一个条件触发,多个组件响应的情况例如:动物园系统中,点击肉食动物按钮,动物园中有肉食属性的动物都进行显示。步骤:1、动物自身脚本上进行判断是…

产品的可持续发展

如今,产品的可持续性对于取得商业成功至关重要。越来越多的政府提出了相关的合规性要求,普通消费者也在翘首期待符合可持续性发展理念的产品上市。然而,许多企业面临的首要问题是如何确定他们的产品是否满足可持续性发展的要求。 毕竟&#x…

后量子 KEM 方案:LAC

参考文献: Lyubashevsky V, Peikert C, Regev O. On ideal lattices and learning with errors over rings[J]. Journal of the ACM (JACM), 2013, 60(6): 1-35.Lu X, Liu Y, Zhang Z, et al. LAC: Practical ring-LWE based public-key encryption with byte-leve…

java -数据结构,List相关基础知识,ArrayList的基本使用,泛型的简单、包装类介绍

一、 预备知识-泛型(Generic) 1.1、泛型的引入 比如:我们实现一个简单的顺序表 class MyArrayList{public int[] elem;public int usedSize;public MyArrayList(){this.elem new int[10];}public void add(int key){this.elem[usedSize] key;usedSize;}public …

Ethercat系列(4)Twcat3激活配置过程的协议分析

广播设置ESC的4个端口环路设置从-》主广播读从站状态机实际状态主-》从从-》主广播清除接收错误计数器0x300且读应用层状态从-》主顺序读从站基本信息,链路层配置与状态从-》主广播读从站状态机状态主-》从从-》主顺序写ESC控制模式,广播读从站状态主-》…

一、图机器学习导论【CS224W】(Datawhale组队学习)

开源内容:https://github.com/TommyZihao/zihao_course/tree/main/CS224W 子豪兄B 站视频:https://space.bilibili.com/1900783/channel/collectiondetail?sid915098 斯坦福官方课程主页:https://web.stanford.edu/class/cs224w 文章目录前…

C++中的标准输入和输出

一、 C 输入输出的含义 在C语言中我们的输入和输出都是以printf和scanf进行操作的。他们都是函数。在C中的我们的输入输出都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上。从操作系统(Linux)的角度看,每一个与主机相连的输…

RKE2部署高可用Rancher v2.7.1

先决条件 注意修改主机名,不要有冲突 第一个server节点安装 官方文档的描述感觉对于新手来说太不友好了,建议以下链接都看一下。Rancher新老文档都建议看一下,不然刚刚入门很蒙。 RKE2快速开始:https://docs.rke2.io/zh/install…

html+css综合练习一

文章目录一、小米注册页面1、要求2、案例图3、实现效果3.1、index.html3.2、style.css二、下午茶页面1、要求2、案例图3、index.html4、style.css三、法国巴黎页面1、要求2、案例图3、index.html4、style.css一、小米注册页面 1、要求 阅读下列说明、效果图,进行静…

由浅入深,聊聊OkHttp的那些事(很长,很细节)

引言 在 Android 开发的世界中,有一些组件,无论应用层技术再怎么迭代,作为基础支持,它们依然在那里。 比如当我们提到网络库时,总会下意识想到一个名字,即 OkHttp 。 尽管对于大多数开发者而言&#xff0…

spark02-内存数据分区分配原理

代码:val conf: SparkConf new SparkConf().setMaster("local[*]").setAppName("wordcount") val scnew SparkContext(conf) //[1] [2,3] [4,5] val rdd: RDD[Int] sc.makeRDD(List(1,2,3,4,5),3) //将处理的数据保存分区文件 rdd.saveAsText…

【Apifox Helper】自动生成接口文档,IDEA+Apifox懒人必备

文章目录前言🍊缘由接口文档对接爽,整理起来真费脑⏲️本文阅读时长约10分钟🥮前置条件1. IDEA开发工具2. Apifox(不必要)🎯主要目标一秒生成接口文档🍩水图IDEA中项目接结构图生成到Apifox接口文档图👨‍&…

Django框架之模板系列

模板 思考 : 网站如何向客户端返回一个漂亮的页面呢? 提示 : 漂亮的页面需要html、css、js.可以把这一堆字段串全都写到视图中, 作为HttpResponse()的参数,响应给客户端. 问题 : 视图部分代码臃肿, 耦合度高.这样定义的字符串是不会出任何效果和错误的.效果无法及时…

论文投稿指南——中文核心期刊推荐(矿业工程)

【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…

springMVC概念(第一个入门案例)

目录 一、概念 1.什么是mvc? 2.mvc的工作流程? 3.什么是springMVC? 4.springMVC的特点 二、入门案例 准备工作: 正式代码例子 : 一、概念 1.什么是mvc? 答:MVC是一种软件架构的思想&a…

leaflet 上传包含shp的zip文件,在map上解析显示图形(059)

第059个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中本地上传包含shp的zip文件,利用shapefile读取shp数据,并在地图上显示图形。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果 文章目录 示例效果加载shapefile.js方式安装引用jszip(…

大数据框架之Hadoop:HDFS(四)HDFS的数据流(面试重点)

4.1HDFS写数据流程 4.1.1 剖析文件写入 HDFS写数据流程,如下图所示。 1)客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。 2)NameNode 返回是否可…