前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >日常Bug排查-系统失去响应-Redis使用不当日常Bug排查-系统失去响应-Redis使用不当

日常Bug排查-系统失去响应-Redis使用不当日常Bug排查-系统失去响应-Redis使用不当

作者头像
无毁的湖光-Al
发布于 2021-12-24 06:30:18
发布于 2021-12-24 06:30:18
33600
代码可运行
举报
文章被收录于专栏:解Bug之路解Bug之路
运行总次数:0
代码可运行

日常Bug排查-系统失去响应-Redis使用不当

前言

日常Bug排查系列都是一些简单Bug排查,笔者将在这里介绍一些排查Bug的简单技巧,同时顺便积累素材^_^。

Bug现场

开发反应线上系统出现失去响应的现象,收到业务告警已经频繁MarkAndSweep(Full GC)告警。于是找到笔者进行排查。

看基础监控

首先呢,当然是看我们的监控了,找到对应失去响应的系统的ip,看下我们的基础监控。

机器内存持续上升。因为我们是java系统,堆的大小一开始已经设置了最大值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
--XX:Xms2g -Xmx2g

所以看上去像堆外内存泄露。而FullGC告警只是堆外内存后一些关联堆内对象触发。

看应用监控

第二步,当然就是观察我们的应用监控,这边笔者用的是CAT。观察Cat中对应应用的情况,很容易发现,其ActiveThread呈现不正常的现象,竟然达到了5000+多个,同时和内存上升曲线保持一致。

jstack

java应用中遇到线程数过多的现象,首先我们考虑的是jstack,jstack出来对应的文件后。我们less一下,发现很多线程卡在下面的代码栈上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"Thread-1234
	java.lang.Thread.State: WAITING (parking)
		at sun.misc.Unsafe.park
		......
		at org.apache.commons.pool2.impl.LinkedBlockingQueue.takeFirst
		......
		at redis.clients.util.Pool.getResource

很明显的,这个代码栈值得是没有获取连接,从而卡住。至于为什么卡这么长时间而不释放,肯定是由于没设置超时时间。那么是否大部分线程都卡在这里呢,这里我们做一下统计。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cat jstack.txt | grep 'prio=' | wc -l 
======> 5648
cat jstack.txt | grep 'redis.clients.util.Pool.getResource' 
======> 5242

可以看到,一共5648个线程,有5242,也就是92%的线程卡在Redis getResource中。

看下redis情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
netstat -anp | grep 6379 
tcp 0 0 1.2.3.4:111 3.4.5.6:6379 ESTABLISHED
......

一共5个,而且连接状态为ESTABLISHED,正常。由此可见他们配置的最大连接数是5(因为别的线程正在得到获取Redis资源)。

Redis连接泄露

那么很自然的想到,Redis连接泄露了,即应用获得Redis连接后没有还回去。这种泄露有下面几种可能: 情况1:

情况2:

情况3: 调用Redis卡住,由于其它机器是好的,故排除这种情况。

如何区分

我们做个简单的推理: 如果是情况1,那么这个RedisConn肯定可以通过内存可达性分析和Thread关联上,而且这个关联关系肯定会关联到某个业务操作实体(例如code stack or 业务bean)。那么我们只要观察其在堆内的关联路线是否和业务相关即可,如果没有任何关联,那么基本断定是情况2了。

可达性分析

我们可以通过jmap dump出应用内存,然后通过MAT(Memory Analysis Tool)来进行可达性分析。

首先找到RedisConn

将dump文件在MAT中打开,然后运行OQL:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from redis.clients.jedis.Jedis (RedisConn的实体类)

搜索到一堆Jedis类,然后我们执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Path To GCRoots->with all references

可以看到如下结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis.clients.jedis.Jedis
	|->object 
		|->item
			|->first
				|->...
					|->java.util.TimerThread
				|->internalPool

由此可见,我们的连接仅仅被TimerThread和internalPool(Jedis本身的连接池)持有。所以我们可以判断出大概率是情况2,即忘了归还连接。翻看业务代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
伪代码
void lock(){
	conn = jedis.getResource()
	conn.setNx()
	// 结束,此处应该有finally{returnResource()}或者采用RedisTemplate
}

最后就是很简单的,业务开发在执行setNx操作后,忘了将连接还回去。导致连接泄露。

如果是情况1如何定位卡住的代码

到此为止,这个问题时解决了。但是如果是情况1的话,我们又该如何分析下去呢?很简单,我们如果找到了jedis被哪个业务线程拥有,直接从heap dump找到其线程号,然后取Jstack中搜索即可知道其卡住的代码栈。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
jmap:
redis.clients.jedis.Jedis
	|->Thread-123

jstack:

Thread-123 prio=...
	at xxx.xxx.xxx.blocked

总结

这是一个很简单的问题,知道套路之后排查起来完全不费事。虽然最后排查出来是个很低级的代码,但是这种分析方法值得借鉴。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【转载】记一次因 Redis 使用不当导致应用卡死 bug 的排查及解决!
首先说下问题现象:内网sandbox环境API持续1周出现应用卡死,所有api无响应现象
一枝花算不算浪漫
2019/09/23
6940
【转载】记一次因 Redis 使用不当导致应用卡死 bug 的排查及解决!
Jedis常见异常汇总
本文作者:carlosfu 原文链接:https://yq.aliyun.com/articles/236384 摘要: Jedis虽然使用起来比较简单,但是如果不能根据使用场景设置合理的参数(例如连接池参数),不合理的使用一些功能(例如Lua和事务)也会产生很多问题,本文对这些问题逐个说明。 一.无法从连接池获取到Jedis连接 1.异常堆栈 (1) 连接池参数blockWhenExhausted = true(默认) 如果连接池没有可用Jedis连接,会等待maxWaitMillis(毫秒),依然没有获
程序猿DD
2018/04/17
5.3K0
Jedis常见异常汇总
同事没正确使用redis,把我害苦了...
首先说下问题现象:内网sandbox环境API持续1周出现应用卡死,所有api无响应现象
良月柒
2019/11/07
1.2K0
日常Bug排查-消息不消费日常Bug排查-消息不消费总结
日常Bug排查系列都是一些简单Bug排查,笔者将在这里介绍一些排查Bug的简单技巧,同时顺便积累素材^_^。
无毁的湖光-Al
2021/12/24
8320
日常Bug排查-消息不消费日常Bug排查-消息不消费总结
redis服务又出现卡死,又是一次不当使用,这个锅你背定了!
首先说下问题现象:内网sandbox环境API持续1周出现应用卡死,所有api无响应。
java进阶架构师
2020/12/17
6260
redis服务又出现卡死,又是一次不当使用,这个锅你背定了!
线上问题排查思路、工具小结
本文总结了一些常见的线上应急现象和对应排查步骤和工具。分享的主要目的是想让对线上问题接触少的同学有个预先认知,免得在遇到实际问题时手忙脚乱。
公众号 IT老哥
2020/10/09
3.3K0
线上问题排查思路、工具小结
前京东陌陌高级架构师的直播笔记分享(Java 内存问题排查和解决:内存概览,内存问题出现的原因,问题代码,案例分析)
上一周我有幸观看了高级架构师李国讲师的直播,内容是关于 Java 内存问题排查和解决。
RendaZhang
2020/09/08
1.5K0
前京东陌陌高级架构师的直播笔记分享(Java 内存问题排查和解决:内存概览,内存问题出现的原因,问题代码,案例分析)
Executors使用不当引起的内存泄漏
这周刚上班突然有一个项目内存溢出了,排查了半天终于找到问题所在,在此记录下,防止后面再次出现类似的情况。
一个程序员的成长
2020/11/25
1.8K0
Executors使用不当引起的内存泄漏
解Bug之路-记一次JVM堆外内存泄露Bug的查找
前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤了Bug的源头。笔者将此Bug分析的过程写成博客,以飨读者。 由于物理内存定量分析部分用到了linux kernel虚拟内存管理的知识,读者如果有兴趣了解请看ulk3(《深入理解linux内核第三版》) 内存泄露Bug现场 一个线上稳定运行了三年的系统,从物理机迁移到docker环境后,运行了一段时间,突然被监控系统发出了某些实例不可用的报警。所幸有负载均衡,
用户1263954
2018/06/22
6540
大数据技术之_21_Redis学习_02_解析 Redis 配置文件 redis.conf + Redis 的持久化 + Redis 的事务 + Redis 的复制(Master/Slave)+ Re
1、配置大小单位,开头定义了一些基本的度量单位,只支持 bytes(字节),不支持 bit(位数)。 2、对大小写不敏感。
黑泽君
2019/05/15
4860
大数据技术之_21_Redis学习_02_解析 Redis 配置文件 redis.conf + Redis 的持久化 + Redis 的事务 + Redis 的复制(Master/Slave)+ Re
java实现redis分布式锁实例[通俗易懂]
特点:分布式锁、动态解决由redis宕机产生死锁的情况,基于wait()、notify()有效提高效率节省资源
全栈程序员站长
2022/07/28
4370
今咱们来聊聊JVM 堆外内存泄露的BUG是如何查找的前言内存泄露Bug现场查找线索总结
前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤了Bug的源头。笔者将此Bug分析的过程写成博客,以飨读者。 由于物理内存定量分析部分用到了linux kernel虚拟内存管理的知识,读者如果有兴趣了解请看ulk3(《深入理解linux内核第三版》) 内存泄露Bug现场 一个线上稳定运行了三年的系统,从物理机迁移到docker环境后,运行了一段时间,突然被监控系统发出了某些实例不可用的报警。所幸有负载均衡,可
美的让人心动
2018/06/14
2.1K0
体验了一把线上CPU100%及应用OOM的排查和解决过程
项目中默认使用 spring-cloud-sleuth-zipkin 依赖得到 zipkin-reporter。分析的版本发现是 zipkin-reporter版本是 2.7.3 。
全栈程序员站长
2022/07/20
5060
体验了一把线上CPU100%及应用OOM的排查和解决过程
Redis进阶-JedisPool参数优化 & 如何合理估算核心参数 & redis连接池预热
如果我们选择Jedis作为客户端来操作Redis的话, 操作单节点的Redis,JedisPool & JedisPoolConfig 那肯定要好好地了解一番。 合理的JedisPool资源池参数设置能够有效地提升Redis性能。
小小工匠
2021/08/17
3.5K0
redis-cli sentinel_redis sentinel配置
RedisClient是一款纯java开发的开源客户端,原版本:https://github.com/caoxinyu/RedisClient,作者目前已经基本不再维护,最近想要使用一下,结果发现已经开始各种异常。应该是很久没更新的缘故。由于我们公司使用的哨兵模式,而且查看客户端的jedis版本确实有些古老并且发现使用的是单机版的Jedis,难怪会出现异常。例如:ERR unknown command ‘AUTH’ 肿么办?看了下介绍代码是开源的并且是纯java开发,要不自己改一改?好吧,开始我们的趟坑之旅 本文修改后的RedisClient版本:https://github.com/GallantKong/RedisClient
全栈程序员站长
2022/11/04
1.4K0
redis-cli sentinel_redis sentinel配置
skywalking内存泄露排查
最近写的关于dubbo内存泄露稍微复杂了一点,很多人表示看不明白,想到之前遇到的比较简单的内存泄露问题,更容易入门,于是拿出来分享一下。
龟仙老人
2020/12/15
4.2K0
Java内存泄漏、性能优化、宕机死锁的N种姿势
导读 本文介绍Java诸多优化实例:第一,排查堆上、堆外内存泄露;第二,使用arthas、jaeger、tcpdump、jstack做性能优化;第三,排查进程异常退出的原因,如被杀、System.exit、Java调用的C++发生Crash、Java内Crash;第四,排查死锁的原因,如log4j死锁、封装不严谨导致的死锁 内存泄漏 内存泄露在C++里排查很简单,用钩子函数勾住内存分配和释放函数malloc和free,统计哪些malloc的内存没有free,就可以找出内存泄露的源头。但在Java
腾讯技术工程官方号
2020/08/04
2K0
线上CPU飙升100%问题排查,一篇足矣
对于互联网公司,线上CPU飙升的问题很常见(例如某个活动开始,流量突然飙升时),按照本文的步骤排查,基本1分钟即可搞定!特此整理排查方法一篇,供大家参考讨论提高。
Java_老男孩
2019/12/02
3.1K0
Redis突然报错,今晚又不能回家了...
今天在容器环境发布服务,我发誓我就加了一行日志,在点击发布按钮后,我悠闲地掏出泡着枸杞的保温杯,准备来一口老年人大保健......
猿天地
2020/09/22
3.5K0
Redis突然报错,今晚又不能回家了...
Redis之Java客户端Jedis
-------------------------------------" );      jedis.mset( "str1" , "v1" , "str2" , "v2" , "str3" , "v3" );      System. out .println(jedis.mget( "str1" , "str2" , "str3" ));       //list      System. out .println( "----------------------------------------" );       //jedis.lpush(" mylist ","v1","v2","v3","v4","v5");      List list = jedis.lrange( "mylist" ,0,-1);       for  (String element : list) {        System. out .println(element);      }       //set      jedis.sadd( "orders" , "jd001" );      jedis.sadd( "orders" , "jd002" );      jedis.sadd( "orders" , "jd003" );      Set set1 = jedis.smembers( "orders" );       for  ( Iterator  iterator = set1.iterator(); iterator.hasNext();) {        String string = (String) iterator.next();        System. out .println(string);      }      jedis.srem( "orders" , "jd002" );      System. out .println(jedis.smembers( "orders" ).size());       //hash      jedis.hset( "hash1" , "userName" , "lisi" );      System. out .println(jedis.hget( "hash1" , "userName" ));      Map<String,String> map =  new  HashMap<String,String>();      map.put( "telphone" , "13811814763" );      map.put( "address" , "atguigu" );      map.put( "email" , "abc@163.com" );      jedis.hmset( "hash2" ,map);      List result = jedis.hmget( "hash2" ,  "telphone" , "email" );       for  (String element : result) {        System. out .println(element);      }       // zset      jedis.zadd( "zset01" ,60d, "v1" );      jedis.zadd( "zset01" ,70d, "v2" );      jedis.zadd( "zset01" ,80d, "v3" );      jedis.zadd( "zset01" ,90d, "v4" );      Set s1 = jedis.zrange( "zset01" ,0,-1);       for  ( Iterator  iterator = s1.iterator(); iterator.hasNext();) {        String string = (String) iterator.next();        System. out .println(string);      }
yuanshuai
2022/08/22
4540
推荐阅读
相关推荐
【转载】记一次因 Redis 使用不当导致应用卡死 bug 的排查及解决!
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验