redis出现过多command 慢查询slowlog出现command命令

大家好,我是烤鸭:

今天分享一个问题,一个关于redis slowlog,执行过多 command命令的问题。

 

问题来源

所有走redis 的接口tp99和平均耗时是原来的两倍不止,运维说redis 的qps也翻倍了。查了下slowlog,发现command 命令占大多数,除了两条业务请求,其他都是command。

 

command命令返回的是当前redis所能执行的命令和对应的账号权限,也就不超过200条数据吧。(但频繁执行会增加qps,影响集群性能)

这个command命令是确实由业务服务发起的(ip符合),但是代码里也没有显示的调用(第一时间感觉是sdk有问题)。由于问题最开始出现在5天前,让运维查了一周前的记录,发现command命令也存在,只是没那么明显,比例大概1/20(调20次get命令,会出现一次command)。

 

源码查看,找蛛丝马迹

项目框架用的是 springboot的版本2.0.4.RELEASE,对应 spring-boot-starter-data-redis的版本2.0.4.RELEASE

对应 lettuce-core 版本 5.0.4.RELEASE。

分别从这几个包搜 command 命令,搜不到。

代码里用的比较多的有 redisTemplate.executePipelined 方法,跟这个代码进去看一下。

以get方法为例,由于默认调用的是 lettuce,RedisStringCommands.get ——> LettuceStringCommands.getConnection(getAsyncConnection) —>

LettuceConnection.getConnection()—>

而 LettuceConnection中的变量 asyncSharedConn 会是null,所以每次都得尝试重新连接

 

LettuceConnection.getDedicatedConnection()—> ClusterConnectionProvider.getConnection (配置连接池的话走的是 LettucePoolingConnectionProvider.getConnection,所以每次不需要再次创建连接 )

 

而LettucePoolingConnectionProvider.getConnection会先判断连接池是否存在,是否不存在,会先去创建。

ClusterConnectionProvider.getConnection 和 LettucePoolingConnectionProvider.getConnection 创建连接池时调用的都是 LettuceConnectionProvider.getConnection

 

LettuceConnectionProvider.getConnection(每次创建连接都会执行 command命令)

 

RedisClusterClient.connect—> RedisClusterClient.connectClusterImpl

这个方法里的调用了 connection.inspectRedisState();

command() 方法进入到了 ClusterFutureSyncInvocationHandler.handleInvocation

 

这里能看到每一次调用的命令,打开debug日志也能看到。

 

原因清楚了,就是每次执行命令都会检查 LettuceConnection asyncDedicatedConn是否为空, 如果为空,就会再次连接,再次连接就会执行command命令。为啥呢?连接没有池化。看下配置类。 ​

package com.my.maggie.demo.config;
​
​
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
​
import java.util.HashSet;
import java.util.List;
import java.util.Set;
​
​
@Configuration
public class RedisConfigration {
​@Bean@ConfigurationProperties(prefix="spring.redis-one")@Primarypublic RedisProperties redisPropertiesCache() {return new RedisProperties();}
​
​@Bean@Primarypublic LettuceConnectionFactory redisConnectionFactoryOne() {List<String> clusterNodes = redisPropertiesCache().getCluster().getNodes();Set<RedisNode> nodes = new HashSet<RedisNode>();clusterNodes.forEach(address -> nodes.add(new RedisNode(address.split(":")[0].trim(), Integer.parseInt(address.split(":")[1]))));RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();clusterConfiguration.setClusterNodes(nodes);if (!StringUtils.isEmpty(RedisPassword.of(redisPropertiesCache().getPassword()))) {clusterConfiguration.setPassword(RedisPassword.of(redisPropertiesCache().getPassword()));}return new LettuceConnectionFactory(clusterConfiguration);}
​@Bean(name="redisTemplateOne")public StringRedisTemplate redisTemplateCache(@Qualifier("redisConnectionFactoryOne") RedisConnectionFactory redisConnectionFactory){return new StringRedisTemplate(redisConnectionFactory);}
​
}

解决方案

  1. 配置类增加池化配置
     

    @Bean@Primarypublic LettuceConnectionFactory redisConnectionFactoryOne() {// 连接池配置GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();genericObjectPoolConfig.setMaxIdle(100);genericObjectPoolConfig.setMinIdle(10);genericObjectPoolConfig.setMaxTotal(5);genericObjectPoolConfig.setMaxWaitMillis(-1);genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis(100);LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(1000)).shutdownTimeout(Duration.ofMillis(1000)).poolConfig(genericObjectPoolConfig).build();// redis 配置List<String> clusterNodes = redisPropertiesCache().getCluster().getNodes();Set<RedisNode> nodes = new HashSet<RedisNode>();clusterNodes.forEach(address -> nodes.add(new RedisNode(address.split(":")[0].trim(), Integer.parseInt(address.split(":")[1]))));RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();clusterConfiguration.setClusterNodes(nodes);if (!StringUtils.isEmpty(RedisPassword.of(redisPropertiesCache().getPassword()))) {clusterConfiguration.setPassword(RedisPassword.of(redisPropertiesCache().getPassword()));}return new LettuceConnectionFactory(clusterConfiguration,clientConfig);}

     

  2. 使用springboot自带的 StringRedisTemplate (2.0 以上版本默认 lettuce ,会自动创建连接池)

  3. 升级springboot 版本(2.1.0.RELEASE 及以上)

总结

个人觉得这应该是算是 spring-data-redis 的一个bug吧。 升级版本确实可以解决这个问题。看下新版本怎么解决的。

2.1.0.RELEASE 以前

LettuceConnectionFactory,构造参数第一个是 asyncSharedConn,直接传的是 null

@Overridepublic RedisClusterConnection getClusterConnection() {
​if (!isClusterAware()) {throw new InvalidDataAccessApiUsageException("Cluster is not configured!");}
​return new LettuceClusterConnection(connectionProvider, clusterCommandExecutor,clientConfiguration.getCommandTimeout());}

LettuceClusterConnection

public LettuceClusterConnection(LettuceConnectionProvider connectionProvider, ClusterCommandExecutor executor,Duration timeout) {
​super(null, connectionProvider, timeout.toMillis(), 0);
​Assert.notNull(executor, "ClusterCommandExecutor must not be null.");
​this.topologyProvider = new LettuceClusterTopologyProvider(getClient());this.clusterCommandExecutor = executor;this.disposeClusterCommandExecutorOnClose = false;}

2.1.0.RELEASE 以后

LettuceConnectionFactory,asyncSharedConn 这个值是传入的,getOrCreateSharedConnection(),没有就创建,所以不会有null的情况

public RedisClusterConnection getClusterConnection() {
​if (!isClusterAware()) {throw new InvalidDataAccessApiUsageException("Cluster is not configured!");}
​RedisClusterClient clusterClient = (RedisClusterClient) client;
​return getShareNativeConnection()? new LettuceClusterConnection((StatefulRedisClusterConnection<byte[], byte[]>) getOrCreateSharedConnection().getConnection(),connectionProvider, clusterClient, clusterCommandExecutor, clientConfiguration.getCommandTimeout()): new LettuceClusterConnection(null, connectionProvider, clusterClient, clusterCommandExecutor,clientConfiguration.getCommandTimeout());}

 

 

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

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

相关文章

springcloud gateway 使用nacos 动态过滤器 记一次线上网关升级cpu升高的问题

大家好&#xff0c;我是烤鸭&#xff1a; ​ 网关升级&#xff0c;想使用 springcloud gateway nacos 动态过滤器配置(原来是硬编码的方式)&#xff0c;升级之后出了一些问题(cpu升高&#xff0c;ygc频繁)&#xff0c;记录一下。 关于 springcloud gateway 集成 nacos 可以看…

【1】生产者-消费者模型的三种实现方式

(手写生产者消费者模型&#xff0c;写BlockingQueue较简便 ) 1、背景 生产者生产数据到缓冲区中&#xff0c;消费者从缓冲区中取数据。 如果缓冲区已经满了&#xff0c;则生产者线程阻塞&#xff1b; 如果…

springboot mybatis-plus 配置 yml 、druid 配置 yml 、mybatis-plus 代码生成

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享一下 springboot mybatis-plus 和 druid 的yml 配置文件。 pom <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency…

实验吧Web-易-天网管理系统(php弱类型,==号)

打开网页&#xff0c;查看源码&#xff0c;看到 <!-- $test$_GET[username]; $testmd5($test); if($test0) --> 说明用户名需要加密之后为0。 对于PHP的号&#xff0c;在使用 运算符对两个字符串进行松散比较时&#xff0c;PHP会把类数值的字符串转换为数值进行比较&…

个人的博客搭建(持续更新)

最近的CSDN的博客阅读体验非常的糟糕&#xff0c;恰好自己也一直想搭建一个属于自己的网站&#xff0c;放下自己的技术心得情感体会&#xff0c;从零开始慢慢搭建项目磨练技术&#xff0c;以后也把自己新习得的技术放在里面增加自己的学习乐趣。 一&#xff0c;搭建基本的项目模…

用Java实现图片验证码功能

一、什么是图片验证码&#xff1f; 可以参考下面这张图&#xff1a; 我们在一些网站注册的时候&#xff0c;经常需要填写以上图片的信息。 1、图片生成实体类&#xff1a; 1 package com.hexianwei.graphic;2 3 import java.awt.Color;4 import java.awt.Font;5 import java.aw…

nacos配置刷新失败导致的cpu上升和频繁重启,nacos配置中心源码解析

大家好&#xff0c;我是烤鸭&#xff1a; nacos 版本 1.3.2&#xff0c;先说下结论&#xff0c;频繁重启的原因确实没有找到&#xff0c;跟nacos有关&#xff0c;日志没有保留多少&#xff0c;只能从源码找下头绪(出问题的版本 server用的是 nacos 1.1&#xff0c;nacos-client…

nova— 计算服务

一、nova介绍&#xff1a; Nova 是 OpenStack 最核心的服务&#xff0c;负责维护和管理云环境的计算资源。OpenStack 作为 IaaS 的云操作系统&#xff0c;虚拟机生命周期管理也就是通过 Nova 来实现的。用途与功能 :1) 实例生命周期管理2) 管理计算资源3) 网络和认证管理4)REST…

springcloud gateway 自定义 accesslog elk

大家好&#xff0c;我是烤鸭&#xff1a; ​ 最近用 springcloud gateway 时&#xff0c;想使用类似 logback-access的功能&#xff0c;用来做数据统计和图表绘制等等&#xff0c;发现没有类似的功能&#xff0c;只能自己开发了。 环境&#xff1a; <dependency><gr…

jenkins发布docker项目 harbor

大家好&#xff0c;我是烤鸭&#xff1a; ​ jenkins 部署k8s 项目还是比较流畅的&#xff0c;本身建立多流水线项目&#xff0c;在项目中添加jenkinsfile就好了&#xff0c;镜像需要额外的参数&#xff0c;还可以添加dokcerfile文件。由于我现在的问题是不能够修改原有的项…

saltstack部署java应用失败无日志——CICD 部署

大家好&#xff0c;我是烤鸭&#xff1a; ​   最近在搞公司的CICD&#xff0c;遇到各种问题。复盘总结一下。 CICD 架构 这篇文章写得很详细&#xff0c;可以看一下 https://linux.cn/article-9926-1.html 而这里只是结合现在的情况分析下&#xff1a; CI 持续集成&…

[css] 浏览器是怎样判断元素是否和某个CSS选择器匹配?

[css] 浏览器是怎样判断元素是否和某个CSS选择器匹配&#xff1f; 有选择器&#xff1a; div.ready #wrapper > .bg-red 先把所有元素 class 中有 bg-red 的元素拿出来组成一个集合&#xff0c;然后上一层&#xff0c;对每一个集合中的元素&#xff0c;如果元素的 parent i…

idea 插件开发 扫描sqlserver

大家好&#xff0c;我是烤鸭&#xff1a; 最近在搞sqlserver 升级 mysql/tidb&#xff0c;发现代码里的sql有很多地方需要改&#xff0c;想着能不能开发一个省点力。 官方的迁移指南&#xff1a; https://www.mysql.com/why-mysql/white-papers/sql-server-to-mysql-zh/ 方案…

VUE之文字跑马灯效果

1.效果演示 2.相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script src"js/vue-2.4.0.js"></script> </head> <body> <div id&…

PMP 错题记录

PMP 错题记录 大家好&#xff0c;我是烤鸭&#xff1a; 这次的PMP错题集本来想考前发&#xff0c;临时能看看&#xff0c;还是耽搁了&#xff0c;补发一下吧&#xff0c;不知道以后用不用的上&#xff0c;据说改版了&#xff0c;可能也用不上了。 变更题错题记录 9、一项…

nginx 配置 http/2(h2) 和 http 在同一端口的问题

nginx 配置 http/2(h2) 和 http 在同一端口的问题 大家好&#xff0c;我是烤鸭&#xff1a; ​ 这个完全是个采坑记录了。 场景说明 由于这边有个需求想加个支持 grpc 方式转发的域名。 正常的二级域名都是映射到80端口&#xff0c;所以也没想太多&#xff0c;按照这个…

FutureTask isDone 返回 false

大家好&#xff0c;我是烤鸭&#xff1a; ​ 今天看一下 FutureTask源码。好吧&#xff0c;其实遇到问题了&#xff0c;哪里不会点哪里。 伪代码 package src.executor;import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.sche…

为什么MySQL数据库要用B+树存储索引

A&#xff1a;为什么MySQL数据库要用B树存储索引&#xff1f; Hash的查找速度为O(1)&#xff0c;而树的查找速度为O(log2n)&#xff0c;为什么不用Hash作为数据库的存储索引呢&#xff1f; 树的话&#xff0c;无非就是前中后序遍历、二叉树、二叉搜索树、平衡二叉树&#xff0c…

lettuce 配置域名 dns 切换

大家好&#xff0c;我是烤鸭&#xff1a; 如果你也有类似的困扰&#xff0c;运维告诉你&#xff0c;redis连接配置域名&#xff0c;这样出问题了&#xff0c;直接改dns地址就行&#xff0c;不需要重启服务。。。梦想是美好的&#xff0c;现实是残酷的。如果你使用的是 let…

zuul 1.x 和gateway性能对比

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享下 zuul和gateway 网关压测。 环境&#xff1a; windows 10 jdk 8 压测工具&#xff1a; wrk jmeter 数据对比 场景是仅单独转发&#xff0c;接口 Thread.sleep(50) jmeter 12 线程&#xff0c;30s zuul&#xf…