日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java redis使用卡死_记一次找因 redis 使用不当导致应用卡死 bug 的过程

發布時間:2025/3/20 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java redis使用卡死_记一次找因 redis 使用不当导致应用卡死 bug 的过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原標題:記一次找因 redis 使用不當導致應用卡死 bug 的過程

作者:小木

my.oschina.net/xiaomu0082/blog/2990388

首先說下問題現象:內網sandbox環境API持續1周出現應用卡死,所有api無響應現象

剛開始當測試抱怨環境響應慢的時候 ,我們重啟一下應用,應用恢復正常,于是沒做處理。但是后來問題出現頻率越來越頻繁,越來越多的同事開始抱怨,于是感覺代碼可能有問題,開始排查。

首先發現開發的本地ide沒有發現問題,應用卡死時候數據庫,redis都正常,并且無特殊錯誤日志。開始懷疑是sandbox環境機器問題(測試環境本身就很脆!_!)

于是ssh上了服務器 執行以下命令

top

這時發現機器還算正常,于是打算看下jvm 堆棧信息

先看下問題應用比較耗資源的線程

執行top -H -p 12798

找到前3個相對比較耗資源的線程

jstack 查看堆內存

jstack12798|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.

*

* @returnJedis instance ready for wrapping into a {@linkRedisConnection}.

*/

protectedJedis fetchJedisConnector{

try{

if(usePool && pool != null) {

returnpool.getResource;

}

Jedis jedis = newJedis(getShardInfo);

// force initialization (see Jedis issue #82)

jedis.connect;

returnjedis;

} catch(Exception ex) {

thrownewRedisConnectionFailureException( "Cannot get Jedis connection", ex);

}

}

上面pool.getResource后線程開始wait

publicT getResource{

try{

returninternalPool.borrowObject;

} catch(Exception e) {

thrownewJedisConnectionException( "Could not get a resource from the pool", e);

}

}

return internalPool.borrowObject; 這個代碼應該是一個租賃的代碼,接著跟

publicT borrowObject(longborrowMaxWaitMillis)throwsException{

this.assertOpen;

AbandonedConfig ac = this.abandonedConfig;

if(ac != null&& ac.getRemoveAbandonedOnBorrow && this.getNumIdle < 2&& this.getNumActive > this.getMaxTotal - 3) {

this.removeAbandoned(ac);

}

PooledObject p = null;

booleanblockWhenExhausted = this.getBlockWhenExhausted;

longwaitTime = 0L;

while(p == null) {

booleancreate = false;

if(blockWhenExhausted) {

p = (PooledObject) this.idleObjects.pollFirst;

if(p == null) {

create = true;

p = this.create;

}

if(p == null) {

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 == null) {

thrownewNoSuchElementException( "Timeout waiting for idle object");

}

其中有段代碼

if(p == null) {

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

publicE takeFirstthrowsInterruptedException{

this.lock.lock;

Object var2;

try{

Object x;

while((x = this.unlinkFirst) == null) {

this.notEmpty.await;

}

var2 = x;

} finally{

this.lock.unlock;

}

returnvar2;

}

到這邊 發現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 = newJedisConnectionFactory;

.......

JedisPoolConfig config = newJedisPoolConfig;

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 fr

om 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( newRedisCallback {

@Override

publicCursor doInRedis(RedisConnection connection)throwsDataAccessException{

returnconnection.scan(options);

}

});

來執行,

或者使用完connection后 ,用

RedisConnectionUtils.releaseConnection(conn, factory);

來釋放connection.

同時,redis中也不建議使用keys命令,redis pool的配置應該合理配上,否則出現問題無錯誤日志,無報錯,定位相當困難。返回搜狐,查看更多

責任編輯:

總結

以上是生活随笔為你收集整理的java redis使用卡死_记一次找因 redis 使用不当导致应用卡死 bug 的过程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美一级免费在线 | a免费观看 | 亚洲毛片视频 | 好吊色在线视频 | 一区二区三区在线看 | 一区二区三区久久精品 | 日日干日日草 | 欧美69久成人做爰视频 | 欧美性色a | 午夜视频在线播放 | 男人的影院 | 日本在线一本 | 国产高清中文字幕 | 午夜精品一区二区三 | 中文字幕第315页 | 探花系列在线观看 | 亚洲依依 | 瑟瑟视频在线观看 | 青青导航 | av青青草原 | www.com在线观看 | 香蕉视频首页 | av最新天| 亚洲老老头同性老头交j | free性中国hd国语露脸 | 三级视频久久 | 91福利在线导航 | 色欲无码人妻久久精品 | 国产欧美一区二区精品性色 | 97在线视频免费观看 | www.日本色 | 天天看天天色 | 激情视频激情小说 | 成人一级片 | 无码人妻aⅴ一区二区三区日本 | 国产激情视频在线观看 | 热の国产| 欧美激情性生活 | 日本大乳奶做爰 | 黄色中文 | 久久丫精品忘忧草西安产品 | 欧美黄色xxx| 精品久久久久久中文字幕人妻最新 | 禁久久精品乱码 | 欧美裸体xxxx | a级小视频 | 人人超碰人人 | 一级片在线 | 超碰人人艹 | 久久网伊人 | 在线视频资源 | 天天色天天射综合网 | 成人在线影片 | 日韩av免费在线播放 | 色姑娘久 | 温柔女教师在线观看 | 浮力影院草草 | 黄色免费片 | 精品视频一区二区三区在线观看 | 日韩av一区二区在线 | 午夜精品久久久久久久99黑人 | 殴美毛片 | 国产精品久久久久久久久免费桃花 | 欧美做受69 | 成人夜夜| 亚洲av第一成肉网 | 视频一区二区欧美 | 福利一区三区 | 欧美日韩不卡一区二区三区 | 成人一级网站 | 亚洲综合图片区 | 99精品视频在线 | 爱情岛亚洲品质自拍极速福利网站 | 中国老头性行为xxxx | 日韩欧美国产综合 | 中文av一区二区 | 男人亚洲天堂 | 国产欧美网站 | av免费成人 | 全部免费毛片在线播放高潮 | 男人插女人下面视频 | 日本一级吃奶淫片免费 | 久久综合中文 | 午夜天堂视频 | 成人av影视在线观看 | 91久久精品国产91性色tv | 精品国语对白 | 日韩精品视频免费播放 | 欧美日韩一区二区三区四区五区六区 | 亚洲精品电影院 | 99爱在线视频| 日本中文字幕观看 | 国产www在线 | 日韩中文字幕一区二区三区 | 天天干免费视频 | 欧美天天视频 | 亚洲av无码国产精品久久久久 | 精品国产一区二区三区久久久久久 | 亚洲一区二区三区91 |