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

手打不易,如果转摘,请注明出处!

注明原文:https://zhangxiaofan.blog.csdn.net/article/details/136493572

前言

有一次生产环境发包后,发现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")'

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

下载、安装并配置 Node.js

文章目录 1. 下载2. 自定义安装3. 添加环境变量4. 验证5. 修改下载位置6. npm 换源7. 测试 ➡️➡️➡️来源&#xff1a;Simplilearn.com Node.js 是一个开源、跨平台的 JavaScript 运行时环境和库&#xff0c;用于在客户端浏览器之外运行 web 应用程序。 Ryan Dahl 在2009年开…

2024.3.11 C++作业

1、提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C风格字符串完成 #include <iostream>using namespace std;int main() {char str[20];cout << "please enter the str:";gets(str);in…

YoloV7改进策略:Block改进|自研Block,涨点超猛|代码详解|附结构图

涨点效果 参考模型 参考的Block,如下图: 我对Block做了修改,修改后的结构图如下: 代码详解 from timm.models.layers import DropPathfrom torch import Tensor def channel_shuffle(x: Tensor, groups:

5G CA频段组合与带宽的射频标准

先来复习一下我们前面学习过的章节后缀所代表的含义&#xff1a; None Single CarrierA Carrier Aggregation (CA)B Dual-Connectivity (DC)C Supplement Uplink (SUL)D UL MIMOE V2XF Shared spectrum channel accessG Tx Diversity (TxD)I …

docker容器启动rabbitmq

docker容器启动rabbitmq 一、RabbitMQ部署1.1.在线拉取mq镜像1.2.运行mq容器1.3.访问mq 二、RabbitMQ的集群2.1.集群分类2.1.设置 /etc/hosts文件 endl 一、RabbitMQ部署 1.1.在线拉取mq镜像 # 在线拉取 docker pull rabbitmq:3-management1.2.运行mq容器 docker run \ -e R…

【Python】Python中的正则表达式

Python中的正则表达式 1.re模块使用入门 1.1 re.match 函数 函数定义&#xff1a; re.match 尝试从字符串的起始位置匹配一个模式&#xff0c;如果不是起始位置匹配成功的话&#xff0c;match() 就返回 none。 函数语法&#xff1a; re.match(pattern, string, flags0) …

全网最最最详细DataEase-V1部署前后端分离教程

前端代码准备 按照前端官方的介绍&#xff0c;推荐使用node.js 16版本左右的&#xff0c;由于V1的DataEase是使用的Vue2的项目工程&#xff0c;DataEase部署&#xff0c;前端node相关不应该太新。要是不知道如何去做的小伙伴可以看我的其中一篇博客文章&#xff0c; 如何使用…

Java源码项目基于springboot的江理工文档管理系统的设计与实现

大家好我是程序员阿存&#xff0c;在java圈的辛苦码农。辛辛苦苦板砖&#xff0c;今天要和大家聊的是一款Java源码项目基于springboot的江理工文档管理系统的设计与实现&#xff0c;项目源码以及部署相关请联系存哥&#xff0c;文末附上联系信息 。 项目源码&#xff1a;Java基…

103. Go单测系列3---mockey与convey综合实战

文章目录 前言断言mock整体使用方式&#xff1a;具体示例mock结构体方法mock普通函数序列化mock MySQL和Redis单测go-sqlmockminiredis F&Q1. 如何禁用内联和编译优化 前言 工作中&#xff0c;随着业务的快速发展&#xff0c;代码量级和复杂度也会随之快速增长&#xff0c…

GeoPy1.1 地理数据处理入门

原作者&#xff1a;Damon 高校教师&#xff0c;中科院 GIS 博士 本文为原文章基础上&#xff0c;加上自己以及GPT4.0的总结整理而来 原活动链接 目录 前言小练习&#xff1a;求一周的平均温度小练习&#xff1a;将文件夹下的文件路径都打印出来&#xff1a;小练习&#xff1a…

【微信小程序页面出现onReachBottom不触发的情况】

微信小程序页面出现onReachBottom不触发的情况 源代码的情况是 /** * 页面上拉触底事件的处理函数 */ onReachBottom() {console.log("-------"); },.page {height: 100vh;width: 100vw;overflow-x: hidden; }无法触发的原因是&#xff1a;height设置为100vh,会导…

轻松掌握锁冲突问题的排查方法——《OceanBase诊断系列》之八

1. 前言 OceanBase数据库通过两阶段封锁机制确保读写事务并发控制的正确性。在高冲突场景下&#xff0c;事务处理中经常会遇到行锁冲突的问题。然而&#xff0c;许多OceanBase用户对于何时发生锁冲突&#xff0c;锁冲突的表现如何&#xff0c;以及如何排查锁冲突的原因&#x…

Anaconda 的一些配置

Anaconda 安装及修改环境默认位置 https://blog.csdn.net/qq_54562136/article/details/128932352 最重要的一步&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;改文件夹权限 Anaconda创建、激活、退出、删除虚拟环境 修改pip install 默认安装路径

【❤️算法笔记❤️】-(每日一刷-876、单链表的中点)

文章目录 题目思路解法 题目 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个中间…

数学与简单dp

1205. 买不到的数目 - AcWing题库 import java.util.*;public class Main{public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();int m sc.nextInt();System.out.print((n - 1) * (m - 1) - 1);} } 1211. 蚂蚁感冒 - AcWing题库…

告别“死记硬背”,坐席助手让客服新手秒变大咖

在客服行业&#xff0c;新手客服人员常常面临着两大难题&#xff1a;一是需要死记硬背大量的标准答案&#xff0c;二是培训时间长&#xff0c;上岗速度慢。然而&#xff0c;随着科技的发展&#xff0c;这些问题正逐渐得到。今天&#xff0c;我们要为大家介绍一款革命性的客服工…

【考研数学】张宇《1000题》做不下来怎么办?

张宇1000题其实非常考察基础知识&#xff0c;如果你基础没有打好就直接开始刷的话会发现挺难刷下来的 1000题还是更适合在强化阶段来刷&#xff0c;刷早了把心态刷崩掉也没什么用... 基础不好或者0基础的还是建议从简单的1800开始刷起来 同时也要非常注意刷题方法&#xff0…

二叉树——501.二叉搜索树中的众数、 236. 二叉树的最近公共祖先

二叉搜索树中的众数 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 BST …

网络、网络协议模型、UDP编程——计算机网络——day01

今天来到了网络编程&#xff0c;主要讲了网络、网络协议模型以及UDP编程 网络 网络主要是进行&#xff1a;数据传输和数据共享 网络协议模型 OSI协议模型应用层 实际发送的数据表示层 发送的数据是否加密会话层 是否建立会话连接传…

2024暑期实习八股笔记

文章目录 自我介绍MySQL索引索引种类、B树聚簇索引、非聚簇索引联合索引、最左前缀匹配原则索引下推索引失效索引优化 日志、缓冲池redo log&#xff08;重做日志&#xff09;刷盘时机日志文件组 bin log&#xff08;归档日志&#xff09;记录格式写入机制 两阶段提交undo log&…