記一次誤用JedisPool引起的系統假死問題排查

最近一直在搞公司Ai云平臺的服務網關,項目涉及到了一個Oauth2的認證系統。實現認證系統的時候,用了Spring Security Oauth2框架,然后通過redis來實現用戶的token等信息的存儲。
在進行壓測的時候,發現系統經常會出現假死狀態,出現假死狀態的時候,所有請求都會被掛起不返回。發現這種情況時,我起初猜測是死鎖引起的,就用jconsole連到測試服務器來檢測死鎖,不過并沒有檢測到死鎖。
發現沒有死鎖,我就登上服務器,用jstack命令dump下當前線程的堆棧信息。拿到堆棧信息之后,我發現大量的線程都被阻塞在從JedisPool獲取Jedis資源上,具體堆棧信息貼在下面:


部分堆棧信息

再結合JedisPool的源碼發現,線程都阻塞在從資源隊列中獲取資源這步。這是什么鬼?怎么會這樣?起初我懷疑是Jedis對象創建失敗了,所以資源隊列中沒有Jedis對象,于是我dump下了堆信息,使用VisualVM分析堆信息,但是我發現,堆中是有Jedis對象的,而且Jedis對象個數正好和JedisPool設置的最大對象個數一致。看來又猜錯了!!!難道是使用JedisPool的時候有地方忘記歸還資源了???我檢查了一遍代碼,使用jedispoll的時候清一色的try()語句:

  try (Jedis jedis = jedisPool.getResource()){
  ...
  }

我這就納悶了,這是怎么回事,資源也都釋放了,為什么會這樣?靜下心來再去看線程堆棧信息,我發現一個問題:


堆信息

這兩個方法,在一個線程調用鏈中,方法實現如下:

    @Override
    public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
        String key = ACCESS_KEY + authentication.getOAuth2Request().getClientId();
        try (Jedis jedis = redisSource.getConnect();) {
            String accessToken = jedis.get(key);
            if (accessToken != null) {
                return readAccessToken(accessToken);
            }
        }
        return null;

    }

    @Override
    public OAuth2AccessToken readAccessToken(String tokenValue) {
        String key = TOKEN_PREFIX + tokenValue;
        try (Jedis jedis = redisSource.getConnect();) {
            List<String> result = jedis.hmget(key, "access_token", "access_key_id", "access_key", "refresh_token", "user_id");
            if (result != null && result.size() > 0 && result.get(0) != null) {
                DefaultOAuth2AccessToken auth2AccessToken = new DefaultOAuth2AccessToken(tokenValue);
                auth2AccessToken.setRefreshToken(new DefaultOAuth2RefreshToken(result.get(3)));
                Map<String, Object> map = new HashMap<>();
                map.put("accessKeyId", result.get(1));
                map.put("userId", result.get(4));
                long expire = jedis.ttl(key);
                auth2AccessToken.setExpiration(new Date(System.currentTimeMillis() + expire * 1000));
                auth2AccessToken.setAdditionalInformation(map);
                if (logger.isDebugEnabled()) {
                    logger.debug("讀取到accessToken:" + MoreObjects.toStringHelper(auth2AccessToken).toString());
                }
                return auth2AccessToken;
            }
        }
        return null;
    }

細心的朋友肯定能發現,在獲取Jedis對象的時候有一個問題:重入了!!!沒錯,就是重入了。當并發高的時候,請求一起打過來,多個線程同時執行getAccessToken(OAuth2Authentication authentication)方法的時候,獲取了Jedis對象,然后進入readAccessToken(String tokenValue)方法,這個時候,Jedis對象都被外部的getAccessToken(OAuth2Authentication authentication)方法持有,所以就被阻塞了,而外部的getAccessToken(OAuth2Authentication authentication)等不到readAccessToken(String tokenValue)執行完成,所以永遠都不會釋放自己持有的Jedis對象!!!而這種情況是檢測不到死鎖的。竟然是因為這個原因!!!能發現這個錯誤也是運氣好呀。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容

  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,339評論 11 349
  • 一、多線程 說明下線程的狀態 java中的線程一共有 5 種狀態。 NEW:這種情況指的是,通過 New 關鍵字創...
    Java旅行者閱讀 4,721評論 0 44
  • layout: posttitle: 《Java并發編程的藝術》筆記categories: Javaexcerpt...
    xiaogmail閱讀 5,858評論 1 19
  • 欠缺太多,迷茫中努力,越努力越迷茫!思考致勝!在忙不忘學習,切記!
    榮海田閱讀 170評論 0 0
  • 總算平穩度過手術后的第一周,視力算是穩定在1.0了。答應小伙伴的飛秒小攻略總算是出了。 1基本概述。 26歲,近視...
    胖胖迪閱讀 589評論 0 0