小工具知识网

当前位置: 首页 > 行业知识 > 记一次用Arthas排查Redis连接数增加问题(附:查看bean)

行业知识

记一次用Arthas排查Redis连接数增加问题(附:查看bean)

2026-11-10 02:25:43 来源:互联网转载

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

()

项目比较多,有用到 jedis、lettuce、redisson 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 getBean(String name) {        assertContextInjected();        return (T) applicationContext.getBean(name);    }    /**     * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.     */    public static  T getBean(Class requiredType) {        assertContextInjected();        return applicationContext.getBean(requiredType);    }    public static  Map getBeansOfType(Class 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  void printBean(Class 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 中文网

我们发现

 注意如果用到

    org.springframework.boot    spring-boot-starter-data-redis

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

                    org.springframework.boot            spring-boot-starter-data-redis                                                io.lettuce                    lettuce-core                                    

我们项目有人提交代码的时候,把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 配置

其他:用ognl查看连接池信息

// 查看有哪些 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()'

// 查看 redisConnectionFactory 连接信息

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

// redison 连接池信息

// 查看配置的模式 

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

// lettuce 连接池信息

 

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

// jedis 连接池信息

 

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

// jetcache(默认: jedis) 连接池信息

ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("globalCacheConfig")'ognl -c 33d512c1 '#context=@com.aop.util.SpringContextHolde@getContext(),#context.getBean("globalCacheConfig").getRemoteCacheBuilders().get("default").getConfig'

 

上一篇:设计怎么说服客户?

下一篇:服务器机柜底线怎么接?