记一次用Arthas排查Redis连接数增加问题(附:redis连接池优化)

news2024/10/6 12:22:24

有一次生产环境发包后,发现redis连接数变多了,由于改的代码比较多,不确定是哪里出了问题。因此用Arthas来进行了一次排查。

项目比较多,有用到 jedislettuceredisson 3种客户端。

项目用到的 SpringContextHolder 代码如下:

package com.aop.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component("springContextHolder")
public class SpringContextHolder implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);

    private static ApplicationContext applicationContext;

    /**
     * 实现ApplicationContextAware接口, 注入Context到静态变量中.
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        logger.info("ServletContextUtil is init");
        SpringContextHolder.applicationContext = applicationContext;
    }

    /**
     * 获取静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        assertContextInjected();
        return applicationContext;
    }


    /**
     * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        assertContextInjected();
        return (T) applicationContext.getBean(name);
    }

    /**
     * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
     */
    public static <T> T getBean(Class<T> requiredType) {
        assertContextInjected();
        return applicationContext.getBean(requiredType);
    }


    public static <T> Map<String, T> getBeansOfType(Class<T> requiredType) {
        assertContextInjected();
        return applicationContext.getBeansOfType(requiredType);
    }


    /**
     * 检查ApplicationContext不为空.
     */SpringContextHolder
    private static void assertContextInjected() {
        if (applicationContext == null) {
            throw new IllegalStateException("Application Context Have Not Injection");
        }
    }

    /**
     * 清除SpringContextHolder中的ApplicationContext为Null.
     */
    public static void clearHolder() {
        applicationContext = null;
    }

    /**
     * 打印对应Class的Bean是否注入到容器
     */
    public static <T> void printBean(Class<T> requiredType) {
        assertContextInjected();
        T instance = null;
        try {
            instance = SpringContextHolder.getBean(requiredType);
        } catch (Exception ex) {
            logger.warn("bean:" + requiredType.getSimpleName() + " is null");
        }
        logger.info(requiredType.getSimpleName() + ":{}", instance != null ? instance.toString() : "null");
    }
}

第一步:看项目中启动类使用到了哪些客户端

启动arthas,怎么启动,网上有资料,可以搜一下。

使用 sc 命令

sc -d com.aop.util.SpringContextHolder

可以看到 classLoaderHash 值 : 33d512c1   

[arthas@1]$ sc -d com.aop.util.SpringContextHolde
 class-info        com.aop.util.SpringContextHolde                                                                                                                  
 code-source       /opt/cloud/tomcat/appstore%23file%23api/WEB-INF/classes/                                                                                                                    
 name              com.aop.util.SpringContextHolde                                                                                                                  
 isInterface       false                                                                                                                                                                       
 isAnnotation      false                                                                                                                                                                       
 isEnum            false                                                                                                                                                                       
 isAnonymousClass  false                                                                                                                                                                       
 isArray           false                                                                                                                                                                       
 isLocalClass      false                                                                                                                                                                       
 isMemberClass     false                                                                                                                                                                       
 isPrimitive       false                                                                                                                                                                       
 isSynthetic       false                                                                                                                                                                       
 simple-name       SpringContextHolde                                                                                                                                                    
 modifier          public                                                                                                                                                                      
 classLoaderHash   33d512c1   

执行 ognl 的 getContext() 测试一下,有输出则成功

ognl -c 33d512c1 '#conetex=@com.aop.util.SpringContextHolde@getContext()'

执行getBeanDefinitionNames()查看有哪些bean

ognl -c 33d512c1 '@com.aop.util.SpringContextHolde@getContext().getBeanDefinitionNames()'

可以看到输出的bean中只有

...
org.springframework.boot.autoconfigure.data.redis.JedisConnectionConfiguration
...

我们确定,我们项目是引入了 lettuce ,为什么没有有看到相关的Bean,"org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration" ?

通过查看文档:在 Spring Boot 中整合、使用 Redis - spring 中文网

我们发现

 注意如果用到

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

默认是使用  lettuce,如果要用 jedis 或者 redisson 务必,排除

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

我们项目有人提交代码的时候,把lettuce排除了,导致我们用到了 jedis 客户端。

第二步:查看客户端的连接池、连接串配置

继续看 JedisConnectionConfiguration 的连接池配置

ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde @getContext(),#context.getBean("org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration")'

 输出如下:

@JedisConnectionConfiguration[
    COMMONS_POOL2_AVAILABLE=@Boolean[true],
    properties=@RedisProperties[org.springframework.boot.autoconfigure.data.redis.RedisProperties@24d30f55],
    standaloneConfiguration=null,
    sentinelConfiguration=null,
    clusterConfiguration=null,
]

继续看,我们用下面命令,查看配置,我们发现

ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("org.springframework.boot.autoconfigure.data.redis.JedisConnectionConfiguration").getProperties().getJedis().getPool()'

输出:

@Pool[
    enabled=null,
    maxIdle=@Integer[100],
    minIdle=@Integer[100],
    maxActive=@Integer[200],
    maxWait=@Duration[PT0.002S],
    timeBetweenEvictionRuns=null,
]

 问题就出在这里,我们 minIdle 设置太大,redis 又是集群部署了 6个 节点,因此连接数增加了 600个。之前用的  lettuce 客户端,minIdle=0,maxIdle=8,远远小于 jedis 的配置。

第三步:解决

修改jedis minIdle 配置

Arthas线程池调优(重点)

第一步:查看当前连接池配置

查看所有bean

ognl -c 33d512c1 '@com.aop.util.SpringContextHolde@getContext()'
ognl -c 33d512c1 '#conetex=@com.aop.util.SpringContextHolde@getContext()'
ognl -c 33d512c1 '@com.aop.util.SpringContextHolde@getContext().getBeanDefinitionNames()'

Redisson连接池配置

先查看配置的模式 ,例如下面是看集群的配置。我们项目中的RedissonClient

    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() {    
        ...
    }
ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("redisson").getConfig()'

 上面看出redisson是集群配置

ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("redisson").getConfig().getClusterServersConfig()'

Jedis连接池配置(spring-data-redis,redisTemplate,通过'redisConnectionFactory')

ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("org.springframework.boot.autoconfigure.data.redis.JedisConnectionConfiguration").getProperties().getJedis().getPool()'

 Lettuce连接池配置(spring-data-redis,redisTemplate,通过'redisConnectionFactory')

ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration").getProperties().getLettuce().getPool()'

JetCache连接池配置(默认Jedis客户端)

我们可以通过配置,搜索到配置Jetcache的源码:

com.alicp.jetcache.autoconfigure.RedisAutoConfiguration

com.alicp.jetcache.autoconfigure.RedisAutoConfiguration.RedisAutoInit

ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("autoConfigureBeans").customContainer

ognl -c 10163d6 '#context=@com.aop.util.SpringContextHolder@getContext(),#context.getBean("autoConfigureBeans").customContainer.get("jedisPool.remote.default").provider.cache.poolConfig'

第二步:查看当前连接池使用状态

Redisson 连接池使用情况

ognl -c 10163d6 '#context=@com.aop.util.SpringContextHolderr@getContext(),#context.getBean("redisson").getConnectionManager()'
ognl -c 10163d6 '#context=@com.aop.util.SpringContextHolderr@getContext(),#context.getBean("redisson").getConnectionManager().getEntrySet()'
ognl -c 10163d6 '#context=@com.aop.util.SpringContextHolderr@getContext(),#context.getBean("redisson").getConnectionManager().getEntrySet().toArray()[x].masterEntry.allConnections'
ognl -c 10163d6 '#context=@com.aop.util.SpringContextHolderr@getContext(),#context.getBean("redisson").getConnectionManager().getEntrySet().toArray()[x].masterEntry.allConnections.size'

 Jedis 连接池使用情况(spring-data-redis,redisTemplate,通过'redisConnectionFactory')

ognl -c 4e0ae11f '#context=@com.aop.util.SpringContextHolder@getContext(),#context.getBean("redisConnectionFactory").topologyProvider.cluster.provider.cache'
ognl -c 4e0ae11f '#context=@com.aop.util.SpringContextHolder@getContext(),#context.getBean("redisConnectionFactory").topologyProvider.cluster.provider.cache.nodes.get("x.x.x.x:6379")'

 Lettuce 连接池使用情况(spring-data-redis,redisTemplate,通过'redisConnectionFactory')

 这个是过'redisConnectionFactory'

ognl -c 3d9c13b5 '#context=@com.aop.util.SpringContextHolder@getContext(),#context.getBean("redisConnectionFactory").connectionProvider.delegate.pools'
ognl -c 3d9c13b5 '#context=@com.aop.util.SpringContextHolder@getContext(),#context.getBean("redisConnectionFactory").connectionProvider.delegate.pools.values().toArray()[0]'

 不知道为什么,lettuce设置了minIdle=20,理论上来说allObjects应该大于等于20才对。如果有同学知道原因,还望指正!

 

Jetcache 连接池使用情况(默认redis客户端)

ognl -c 10163d6 '#context=@com.aop.util.SpringContextHolderr@getContext(),#context.getBean("autoConfigureBeans").customContainer.get("jedisPool.remote.default").provider.cache.nodes'
ognl -c 10163d6 '#context=@com.aop.util.SpringContextHolderr@getContext(),#context.getBean("autoConfigureBeans").customContainer.get("jedisPool.remote.default").provider.cache.nodes.get("x.x.x.x:6379")'

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

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

相关文章

视频剪辑大师:批量快进慢放,让你的视频瞬间生动起来!

在数字时代&#xff0c;视频已经成为我们生活中不可或缺的一部分。无论是工作中的演示、学习中的教程&#xff0c;还是娱乐中的短片、Vlog&#xff0c;我们都需要对视频进行精细的剪辑和处理&#xff0c;以呈现出最佳的效果。然而&#xff0c;面对大量的视频文件&#xff0c;如…

操作系统(1)——学习导论(Ⅲ)

目录 小程一言专栏链接: [link](http://t.csdnimg.cn/6grrU)本篇文章因内容需要&#xff0c;且依靠书中内容达不到小程想要的效果&#xff0c;so部分内容依赖其他网络资源 学习导论&#xff08;Ⅲ&#xff09;操作系统相关概念进程——Process线程——Thread调度——Scheduling…

【漏洞复现】Linksys E2000 position.js 身份验证绕过漏洞(CVE-2024-27497)

0x01 产品简介 Linksys E2000是一款由思科&#xff08;Cisco&#xff09;品牌推出的无线路由器&#xff0c;它是一款支持2.4GHz和5GHz双频段的无线路由器&#xff0c;用户可以避开拥挤的2.4GHz频段&#xff0c;独自享受5GHz频段的高速无线生活。 0x02 漏洞概述 Linksys E200…

编译Linux内核并修改版本号后缀为学号-Ubuntu22.04中编译安装Linux内核6.7.8

前言&#xff1a;实验课要求下载最新版本Linux内核并修改版本号&#xff0c;本人在Vmware中Ubuntu22.04中实现&#xff0c;花三天时间查阅大量网站资料。记录一下误打误撞成功的过程&#xff0c;希望对你们有帮助。 目录 一、常规安装步骤&猜想Ubuntu与gcc版本过低 二、安…

docker总结,一套搞定,常用命令,项目部署,jar包打包成镜像/容器

docker 归总 一、学习路线 1、学习视频&#xff08;黑马程序员&#xff09; &#xff08;https://www.bilibili.com/video/BV1HP4118797/?spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source6acc7ed97919d92de048f2b1e5803427&#xff09; 2、…

python爬虫反反爬之图片验证

文章目录 发现宝藏一、ddddOcr&#xff08;针对图形验证码&#xff09;1. 工具介绍2. 安装及环境支持3. 识别示例14. 识别示例2 二、Tesseract&#xff08;标准OCR识别&#xff09;1. 工具介绍2. 配置系统环境3. 识别示例14. 识别示例23. 识别示例3 发现宝藏 前些天发现了一个…

C++ 队列

目录 队列的应用场景 1、429. N 叉树的层序遍历 2、 103. 二叉树的锯齿形层序遍历 3、662. 二叉树最大宽度 4、515. 在每个树行中找最大值 队列的应用场景 广度优先搜索&#xff08;BFS&#xff09;&#xff1a;队列是广度优先搜索算法的核心数据结构。在BFS中&#xff…

如何将应用一键部署至多个环境?丨Walrus教程

在 Walrus 平台上&#xff0c;运维团队在资源定义&#xff08;Resource Definition&#xff09;中声明提供的资源类型&#xff0c;通过设置匹配规则&#xff0c;将不同的资源部署模板应用到不同类型的环境、项目等。与此同时&#xff0c;研发人员无需关注底层具体实现方式&…

Redis精讲

redis持久化 RDB方式 Redis Database Backup file (redis数据备份文件), 也被叫做redis数据快照. 简单来说就是把内存中的所有数据记录到磁盘中. 快照文件称为RDB文件, 默认是保存在当前运行目录. [rootcentos-zyw ~]# docker exec -it redis redis-cli 127.0.0.1:6379> sav…

02- 使用Docker安装RabbitMQ

使用Docker安装RabbitMQ 下载安装镜像 方式一: 启动docker服务,然后在线拉取 # 在线拉取镜像 docker pull rabbitmq:3-management# 使用docker images查看是否已经成功拉取方式二: 从本地加载 ,将RabbitMQ上传到虚拟机中后使用命令加载镜像即可 docker load -i mq.tar启动M…

你必须要知道外贸独立站的那些事

导语 独立站&#xff0c;顾名思义就是具有独立域名的网站。对于跨境电商来说&#xff0c;独立站就是让他们脱离第三方束缚的一个平台。 简单来说就是自己建立一个属于自己的电商平台&#xff0c;然后上传商品出售&#xff0c;但是需要自己去做营销、做推广。 一、自建独立站的好…

运维工具之ventoy安装及使用简介

一、Ventoy简介 简单来说&#xff0c;Ventoy是一个制作可启动U盘的开源工具。有了Ventoy你就无需反复地格式化U盘&#xff0c;你只需要把 ISO/WIM/IMG/VHD(x)/EFI 等类型的文件直接拷贝到U盘里面就可以启动了&#xff0c;无需其他操作。你可以一次性拷贝很多个不同类型的镜像文…

Redis核心数据结构之跳跃表

跳跃表 概述 跳跃表(skiplist)是一种有序数据结构&#xff0c;它通过在每个节点中维持多个指向其他节点的指针&#xff0c;从而达到快速访问节点的目的。跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找&#xff0c;还可以通过顺序性操作来批量处理节点。在大部分情况下&am…

基于PHP构建的HTML5点餐系统的设计13.91

随着互联网时代的发展&#xff0c;人们的生活方式正在发生改变。传统的餐饮行业也正在发生变革。人们不再满足过去的点餐方式&#xff0c;需要更好的体验。本课题旨在结合点餐系统的技术优势&#xff0c;设计一个能够方便顾客与商家&#xff0c;并且节约人力成本以及可以很好地…

访问一次网站的全过程

目录 流程图&#xff1a; 一、应用层开始 1. 在浏览器输入https://www.baidu.com 2. DNS获取IP地址 3. 根据HTTP协议生成HTTP请求报文 应用层结束 二、传输层开始 4. TCP三次握手 传输层结束 三、网络层开始 5. IP寻址 6. ARP协议获取MAC地址 网络层结束 四、数据…

Modified Bessel Function of the First Kind

Abstract 最近接触到 von Mises–Fisher distribution, 其概率密度如下: f p ( x ; μ , κ ) κ p 2 − 1 ( 2 π ) p 2 I p 2 − 1 ( κ ) e κ μ ⊺ x \begin{aligned} f_{p}(\bm{x}; \bm{\mu}, \kappa) \frac{\kappa^{\frac{p}{2}-1}} {(2\pi)^{\frac{p}{2}} I_{\frac…

linux系统下,配置开机自启脚本常见的5种方法

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 所属的专栏:linux基础与进阶,shell脚本编写实战 景天的主页:景天科技苑 文章目录 linux下设置开机自动运行脚本的5种方法一、编辑/etc/rc.d/rc.local文件1、在自己需要启动的文件目录中编写一个…

CPU独占内核运行方式实现,并指定线程到特定CPU上执行

CPU独占内核运行方式实现&#xff0c;并指定线程到特定CPU上执行1. 隔离指定的CPU,避免其余线程run在被隔离的CPU上2. 绑定所有的interrupts&#xff08;中断&#xff09;到非隔离的CPU上,避免被隔离的CPU收到interrupt.3. C绑定线程运行在指定CPU也可以通过taskset来使线程/进…

一文详解WebView,不好理解就想想iframe,类比后秒懂了。

Hi&#xff0c;我是贝格前端工场&#xff0c;又到了给大家做技术扫盲的时候&#xff0c;本文讲一讲webview&#xff0c;有些老铁觉得很难懂&#xff0c;其实借助iframe来中转一下&#xff0c;就好理解了。 WebView是一种用于在应用程序中显示Web内容的组件。它可以嵌入到应用程…

免费、好用、强大的轻量级笔记软件评测

在我们不断寻找能提高个人和团队效率的工具的过程中&#xff0c;优质的笔记软件扮演着至关重要的角色。本文将介绍几款经过精选的免费且功能强大的笔记应用&#xff0c;这些应用不仅适合个人记录和整理思维&#xff0c;也适合团队合作和信息共享。 Joplin —— 隐私保护的开源…