首页 » Web前端 » phpcurlexec卡逝世技巧_记一次因 Redis 运用欠妥导致应用卡去世 bug 的排查及解决

phpcurlexec卡逝世技巧_记一次因 Redis 运用欠妥导致应用卡去世 bug 的排查及解决

访客 2024-11-07 0

扫一扫用手机浏览

文章目录 [+]

但是后来问题涌现频率越来越频繁,越来越多的同事开始抱怨,于是觉得代码可能有问题,开始排查。

首先创造开拓确当地ide没有创造问题,运用卡去世时候数据库,redis都正常,并且无分外缺点日志。
开始疑惑是sandbox环境机器问题(测试环境本身就很脆!_!)

phpcurlexec卡逝世技巧_记一次因 Redis 运用欠妥导致应用卡去世 bug 的排查及解决

于是ssh上了做事器 实行以下命令

phpcurlexec卡逝世技巧_记一次因 Redis 运用欠妥导致应用卡去世 bug 的排查及解决
(图片来自网络侵删)

top

这时创造机器还算正常,于是打算看下jvm 堆栈信息

先看下问题运用比较耗资源的线程

实行 top -H -p 12798

找到前3个相比拟较耗资源的线程

jstack 查看堆内存

jstack 12798 |grep 12799的16进制 31ff

没看出什么问题,高下10行也看看,于是实行

看到一些线程都是处于lock状态。
但没有涌现业务干系的代码,忽略了。
这时候没有什么头绪。
思考一番。
决定放弃这次卡去世状态的机器

为了保护事件现场 先 dump了问题进程所有堆内存,然后debug模式重启测试环境运用,打算问题再显时直接远程debug问题机器

第二天问题再现,于是关照运维nginx转发拿掉这台问题运用,自己远程debug tomcat。

自己随意找了一个接口,断点在接口入口地方,悲剧开始,什么也没有发生!
API等待做事相应,没进断点。

这时候有点懵逼,镇静了一会,在入口之前的aop地方下了个断点,再debug一次,这次进了断点,f8 N次后创造在实行redis命令的时候卡主了。

连续跟,末了在到jedis的一个地方创造问题:

/ Returns a Jedis instance to be used as a Redis connection. The instance can be newly created or retrieved from a pool. @return Jedis instance ready for wrapping into a {@link RedisConnection}. /protected Jedis fetchJedisConnector() {try {if (usePool && pool != ) {return pool.getResource(); } Jedis jedis = new Jedis(getShardInfo());// force initialization (see Jedis issue #82) jedis.connect();return jedis; } catch (Exception ex) {throw new RedisConnectionFailureException(\"大众Cannot get Jedis connection\公众, ex); }}

上面pool.getResource()后线程开始wait

public T getResource() {try {return internalPool.borrowObject(); } catch (Exception e) {throw new JedisConnectionException(\"大众Could not get a resource from the pool\公众, e); }}

return internalPool.borrowObject(); 这个代码该当是一个租赁的代码,接着跟

public T borrowObject(long borrowMaxWaitMillis) throws Exception {this.assertOpen(); AbandonedConfig ac = this.abandonedConfig;if (ac != && ac.getRemoveAbandonedOnBorrow() && this.getNumIdle() < 2 && this.getNumActive() > this.getMaxTotal() - 3) {this.removeAbandoned(ac); } PooledObject p = ;boolean blockWhenExhausted = this.getBlockWhenExhausted();long waitTime = 0L;while(p == ) {boolean create = false;if (blockWhenExhausted) { p = (PooledObject)this.idleObjects.pollFirst();if (p == ) { create = true; p = this.create(); }if (p == ) {if (borrowMaxWaitMillis < 0L) { p = (PooledObject)this.idleObjects.takeFirst(); } else { waitTime = System.currentTimeMillis(); p = (PooledObject)this.idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS); waitTime = System.currentTimeMillis() - waitTime; } }if (p == ) {throw new NoSuchElementException(\"大众Timeout waiting for idle object\"大众); }

个中有段代码

if (p == ) {if (borrowMaxWaitMillis < 0L) { p = (PooledObject)this.idleObjects.takeFirst(); } else { waitTime = System.currentTimeMillis(); p = (PooledObject)this.idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS); waitTime = System.currentTimeMillis() - waitTime; }}

borrowMaxWaitMillis<0会一贯实行,然后一贯循环了 开始疑惑这个值没有配置

找到redis pool配置,创造确实没有配置MaxWaitMillis,配置后else代码也是一个Exception 并不能办理问题

连续F8

public E takeFirst() throws InterruptedException {this.lock.lock(); Object var2;try { Object x;while((x = this.unlinkFirst()) == ) {this.notEmpty.await(); } var2 = x; } finally {this.lock.unlock(); }return var2;}

到这边 创造lock字眼,开始疑惑所有要求api都被壅塞了

于是再次ssh 做事器 安装 arthas ,(Arthas 是Alibaba开源的Java诊断工具)

实行thread命令

创造大量http-nio的线程waiting状态,http-nio-8083-exec-这个线程实在便是出来http要求的tomcat线程

随意找一个线程查看堆内存

thread -428

这是能确认便是api一贯转圈的问题,便是这个redis获取连接的代码导致的,

解读这段内存代码 所有线程都在等 @53e5504e这个工具开释锁。
于是jstack 全局搜了一把53e5504e ,没有找到这个工具所在线程。

自此。
问题缘故原由能确定是 redis连接获取的问题。
但是什么缘故原由造成获取不到连接的还不能确定

再次实行 arthas 的thread -b (thread -b, 找出当前壅塞其他线程的线程)

没有结果。
这边和想的不一样,该当是能找到一个壅塞线程的,于是看了下这个命令的文档,创造有下面的一句话

好吧,我们刚好是后者。



再次整理下思路。
这次修正redis pool 配置,将获取连接超时时间设置为2s,然后等问题再次复现时不雅观察运用末了正常时干过什么。

添加一下配置

JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();.......JedisPoolConfig config = new JedisPoolConfig();config.setMaxWaitMillis(2000);.......jedisConnectionFactory.afterPropertiesSet();

重启做事,等待。



又过一天,再次复现

ssh 做事器,检讨tomcat accesslog ,创造大量api 要求涌现500,

org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:140) at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:229) at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:57) at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128) at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:91) at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:78) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:177) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:152) at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:85) at org.springframework.data.redis.core.DefaultHashOperations.get(DefaultHashOperations.java:48)

找到源头第一次涌现500地方,

创造以下代码

.......Cursor c = stringRedisTemplate.getConnectionFactory().getConnection().scan(options);while (c.hasNext()) {.....,, }

剖析这个代码,stringRedisTemplate.getConnectionFactory().getConnection()获取pool中的redisConnection后,并没有后续操作

也便是说此时redis 连接池中的链接被租赁后并没有开释或者退还到链接池中,虽然业务已处理完毕 redisConnection 已经空闲,但是pool中的redisConnection的状态还没有回到idle状态

正常应为

自此问题已经找到。

总结:spring stringRedisTemplate 对redis常规操作做了一些封装,但还不支持像 Scan SetNx等命令,这时须要拿到jedis Connection进行一些分外的Commands

利用

stringRedisTemplate.getConnectionFactory().getConnection()

是不被推举的

我们可以利用

stringRedisTemplate.execute(new RedisCallback() {@Overridepublic Cursor doInRedis(RedisConnection connection) throws DataAccessException {return connection.scan(options); } });

来实行,或者利用完connection后 ,用

RedisConnectionUtils.releaseConnection(conn, factory);

来开释connection.

同时,redis中也不建议利用keys命令,redis pool的配置该当合理配上,否则涌现问题无缺点日志,无报错,定位相称困难。

End

作者:小木-_-

来源:https://my.oschina.net/xiaomu0082/blog/2990388

标签:

相关文章

大数据BU,引领未来商业变革的新引擎

随着科技的飞速发展,大数据已经渗透到了各行各业,成为推动企业创新、提升竞争力的关键因素。大数据BU(大数据业务单元)作为企业数字化...

Web前端 2024-12-15 阅读0 评论0

若何把php文件技巧_php的文件上传

这里首先声明一下这一章的内容比较多,比较难,你要抱着和自己去世磕的态度。细微之处不放过,多敲多练是王道。 学习就像爬山,得一步一步...

Web前端 2024-12-15 阅读0 评论0

图章艺术,传承与创新的历史见证

图章,作为我国传统艺术的重要组成部分,承载着丰富的历史文化内涵。从古代的官印、私印到现代的签名章,图章在各个历史时期都扮演着举足轻...

Web前端 2024-12-15 阅读0 评论0

rabbitmq削峰php技巧_RabbitMQ 专题1 削峰限流

流量洪峰举个栗子:双11、618购物节,会涌现特定时间点抢购某种商品的情形,瞬时流量巨大。用户端发起下单操作,做事端包括库存检讨,...

Web前端 2024-12-15 阅读0 评论0