Redis交互速度慢,CPU占用100%,集群方案,报错等问题

文章探讨了Redis中大量使用key*查询导致的性能瓶颈,指出哈希索引限制了范围查询效率。作者提到通过建立Redis集群和提高资源配置来降低单点压力,但对速度提升影响有限,主要问题在于单线程设计和并发处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

后续补充结论

仔细查看前辈们堆的代码中发现居然调用了大量key*查询,导致走的遍历非常慢!因为这相当与全部数据量遍历,即这个原因导致了查询速度与数据量成正比,推测也是CPU占用高的元凶;即使加上key前缀再匹配*也会走全部遍历的逻辑,因为reids是用的哈希做索引,不给出完整key是无法确定范围的;后面再写一篇文章详细讲一下这个吧

在Redis中,获取一个key的操作复杂度为O(1),即常数时间复杂度。这意味着无论集合的大小如何增加,获取单个元素的时间都是相同的,非常高效。这是因为Redis使用了哈希表(hash table)这种数据结构。


Redis交互速度很慢,达到几十到一百毫秒一次

问题描述:

执行top命令发现redis占用达到100%
redis交互速度慢,一次要几十到一百毫秒一次;原因查看上面补充结论

解决思路

查看redis数据量,比如我这里达到了30万
经过本地测试,redis交互的速度跟redis交互量成正比,也就是说redis没数据时交互在10ms以内,数据量大的话一次可能花费更久的时间

集群方案

我在本地虚拟机建立了3个主节点3个从节点的redis集群,经过压力测试单节点情况cpu占到30%;改为集群模式redis每个节点占用在10%以下

可以得出结论集群方案确实能降低单节点cpu压力大的问题

**速度测试:**我这测试里单节点速度要比集群方案快,数据量增加后依然是单节点速度比集群快,目前看到集群的优势仅仅是降低了单节点cpu的负载(当然这是在只考虑速度,不考虑容错的情况下)

并发问题

我的程序中开了多线程跟redis做压力测试交互,但是由于redis内部是单线程处理的,所以增加线程数量对速度没有提升,且太多线程数还可能造成时间片竞争;但是多个线程确实比单线程在单位时间内交互次数多一些,我猜测是利用上了程序内部的执行时间,但也没快很多,1.5倍左右?

虽然我的环境是多核心处理器,但是关于redis:
Redis本身是一个单线程的数据库服务器,它使用一个事件循环来处理所有的客户端请求和操作。这意味着在Redis服务器内部,所有的操作都是按顺序处理的,一个接一个地执行。

然而,Redis支持多个并发客户端连接。这些客户端连接可以同时发送请求给Redis服务器。虽然Redis在内部是单线程的,但它使用了非阻塞的I/O操作和事件驱动的模型来实现高并发。这意味着Redis可以同时处理多个客户端请求,而不会阻塞其他客户端。

当多个客户端同时连接到Redis时,每个客户端都有自己的线程或进程来处理Redis通信。这样,多个客户端可以并发地发送请求和接收响应,而不会相互干扰。

测试下经常报错:RedisSystemException: RedisException: Connection closed

org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is io.lettuce.core.RedisException: Connection closed
	at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:74)
	at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
	at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
	at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
	at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:277)
	at org.springframework.data.redis.connection.lettuce.LettuceConnection.await(LettuceConnection.java:1085)
	at org.springframework.data.redis.connection.lettuce.LettuceConnection.lambda$doInvoke$4(LettuceConnection.java:938)
	at org.springframework.data.redis.connection.lettuce.LettuceInvoker$Synchronizer.invoke(LettuceInvoker.java:673)
	at org.springframework.data.redis.connection.lettuce.LettuceInvoker$DefaultSingleInvocationSpec.get(LettuceInvoker.java:589)
	at org.springframework.data.redis.connection.lettuce.LettuceKeyCommands.exists(LettuceKeyCommands.java:79)
	at org.springframework.data.redis.connection.DefaultedRedisConnection.exists(DefaultedRedisConnection.java:81)
	at org.springframework.data.redis.core.RedisTemplate.lambda$hasKey$7(RedisTemplate.java:782)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:191)
	at org.springframework.data.redis.core.RedisTemplate.hasKey(RedisTemplate.java:782)
	at com.bestdata.em.drs.util.RedisUtil.hasKey(RedisUtil.java:98)
	at com.bestdata.em.drs.receive.serivce.impl.HasMoreBusinessServiceImpl.insertFormulaValueToMongoDB(HasMoreBusinessServiceImpl.java:180)
	at com.bestdata.em.drs.receive.serivce.impl.HasMoreBusinessServiceImpl.moreBusinessOperations(HasMoreBusinessServiceImpl.java:113)
	at com.bestdata.em.drs.receive.serivce.FormulaDataProcessingService.sensorFormulaCalculation(FormulaDataProcessingService.java:264)
	at com.bestdata.em.drs.receive.serivce.FormulaDataProcessingService.run(FormulaDataProcessingService.java:167)
	at java.lang.Thread.run(Thread.java:750)
16:18:33.404 [FormulaThreadPoll-9] ERROR c.b.e.d.r.s.i.HasMoreBusinessServiceImpl - Unite Alarm Exception:Redis exception; nested exception is io.lettuce.core.RedisException: Connection closed

问题排查:

服务端和redis是否在同一网段?
是内网,没问题

Redis资源占用
执行top命令
Redis CPU占用一直高达50%~100%,3到5秒就跳一次(此时生产环境有其他程序和redis交互,但是没有特别大)
Redis数据量占用很高,且这是单点部署非集群模式
执行压力测试程序:Redis CPU占用一直高达100%

结论

看到redis的cpu占用100%我本以为是这个导致的RedisSystemException:Connection closed,但是后来反复测试发现报错原因不是这个,而是我在测试过程中强行kill进程,导致出现了连接关闭的报错(这是我在idea中停止运行程序后弹了一下这个异常后发现的)

再经过测试redis cpu占用100%确实会引发异常,但却是超时的问题:org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException:

提高Redis服务器资源配置确实可以降低单点压力;但是对速度的提升不明显,甚至经过本地压力测试还慢了

### Redis集群启动报错解决方案 当尝试创建Redis集群时遇到`Connection refused`错误,这通常意味着客户端无法与指定地址上的服务器建立TCP连接。此问题可能由多种原因引起。 #### 检查防火墙设置 确保所有涉及的机器之间的网络通信畅通无阻。如果存在防火墙,则需确认端口未被阻止。对于本案例中的情况,应该允许7001至7006这些端口间的访问[^2]。 #### 验证实例状态 另一个常见的原因是目标主机上并没有正在监听该端口号的服务进程。可以通过执行如下命令验证各个节点是否正常运行: ```bash ps aux | grep redis-server ``` 上述命令会列出当前系统内所有的Redis服务及其对应的配置文件路径。若发现缺少预期中的某些实例,则可能是由于它们未能成功启动所致;此时应查阅日志文件以获取更多信息[^3]。 #### 清理已有数据 有时即使表面上看起来一切正常,但如果之前已经有过一次失败的安装过程或是实验性的部署操作残留下来的数据可能会干扰新的初始化流程。因此建议先清理掉旧有的数据库记录再重试: ```bash rm -rf /var/lib/redis/* ``` 注意备份重要资料后再做删除动作! #### 修改配置参数 最后还有一种可能性是因为默认情况下Redis仅绑定到本地回环接口(`127.0.0.1`)而非外部网卡IP地址,从而使得远程连接变得不可能实现。编辑每台设备上的`/etc/redis.conf`文档,在其中找到关于bind字段的部分将其更改为实际使用的静态公网IPv4数值即可解决问题[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摘星喵Pro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值