成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

記一次線程池使用不當觸發(fā)死鎖導致RocketMQ消費停滯

開發(fā) 前端
線程池的使用還是要盡量消息,要避免出現(xiàn)線程池中的任務繼續(xù)使用該線程池去執(zhí)行任務,出現(xiàn)死鎖。也可以考慮對線程池進行監(jiān)控,避免出現(xiàn)大量任務阻塞。

背景

團隊小伙伴突然找到我們團隊說,不得了了,線上的RocketMQ又出現(xiàn)了消費停滯,怎么辦? 要不要我們先重啟一下

其實早在之前也出現(xiàn)過一次,當時為了快速恢復業(yè)務的,就直接重啟解決的。

這次因為堆積量不多,所以想對運行環(huán)境進行一些環(huán)境快照保留。所以就和業(yè)務方溝通是否看見接受短暫的消息延時

得到肯定答案后就是放手干吧!

問題定位

首先我們要確定業(yè)務反饋的是否屬實,所以需要去RocketMQ dashboard上看看具體的消費進度。

圖片圖片

可以看到consumer中并不是全部的queue消費都堆積了,只有一個queuq消息堆積了。

這個消費者訂閱的topic是分區(qū)有序的,正常來說分區(qū)有序,如果某個分區(qū)的消息單條消息出現(xiàn)了消費異常,必須要等這條消息消費成功(或者是重試結束)后才能繼續(xù)消費后面的消息。

有時候會因為這個原因出現(xiàn)消息堆積是正常的,但是業(yè)務對消息重試進行了合理的設置,設置的重試次數(shù)比較合理,不會出現(xiàn)長時間的堆積。

RocketMQ的消費線程

一般出現(xiàn)這種問題很明顯就是線程出現(xiàn)了死鎖或者僵死之類的情況。

熟悉RocketMQ的都知道RocketMQ消費消息主要是依賴1個線程1個線程池。

  1. 以PullMessageService開頭的線程, 主要用來拉去消息

圖片圖片

  1. 以ConsumeMessageThread開頭的線程(實際是一個線程池),主要用來執(zhí)行消費邏輯。

圖片圖片

直到了RocketMQ的消費線程模型后我們就好解決了。我們直接通過jstack命令查看線程的堆棧信息。

線程快照分析

我們直接通過jstack命令生成線程快照。

jstack <pid> > thread_dump_$(date +%Y%m%d_%H%M%S).txt


pid 和后面的 thread_dump_$(date +%Y%m%d_%H%M%S).txt自己隨便取個名字就行。自己記得就行。

由于應用運行在pod中,生成了我們就下載到本地。

我們自己看還是比較難分析出分體。這里我們直接使用一個在線的網(wǎng)站進行線程快照的分析。

fastthread

fastthread是一個在線的線程快照分析工具,可以直接將線程快照上傳到這個網(wǎng)站進行分析。

圖片圖片

我們上傳我們下載的線程快照文件。

然后進行線程分析:

圖片圖片

很快定位到阻塞其他線程的代碼。

這里的代碼被我打碼了。

arhtas

如果我們使用arthas也可以很方便的找到阻塞的線程。

thread -b

arthas 提供了thread -b, 一鍵找出那個罪魁禍首。

問題元兇找到

通過阻塞代碼我們很快定位到是由于線程池使用不當導致的阻塞。

線程池使用不當

什么情況下會出現(xiàn)線程池使用不當導致的"死鎖"呢?

我們看看下面的demo:

public class XiaoZouExample {

    public static void main(String[] args) {

        ExecutorService executor = new ThreadPoolExecutor(2, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());


        // 提交兩個外部任務
        for (int i = 0; i < 2; i++) {
            executor.submit(new OuterTask(executor));
        }

        // 等待一段時間后關閉線程池
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executor.shutdown();

    }

    static class OuterTask implements Runnable {

        private final ExecutorService executor;

        public OuterTask(ExecutorService executor) {
            this.executor = executor;
        }

        @Override
        public void run() {
            System.out.println("小奏技術 Outer task started by thread: " + Thread.currentThread().getName());

            // 創(chuàng)建一個Future來等待內(nèi)部任務的結果
            Future<?> future = executor.submit(new InnerTask());

            try {
                // 等待內(nèi)部任務完成
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }

            System.out.println("小奏技術 Outer task finished by thread: " + Thread.currentThread().getName());
        }
    }

    static class InnerTask implements Runnable {
        @Override
        public void run() {
            System.out.println("小奏技術 Inner task started by thread: " + Thread.currentThread().getName());
            try {
                // 模擬長時間運行的任務
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("小奏技術 Inner task finished by thread: " + Thread.currentThread().getName());
        }
    }

}
  • 運行結果

圖片圖片

可以看到?jīng)]有任何任務執(zhí)行完成,線程池一直處于被阻塞狀態(tài)。

核心原因就是首先線程池的核心線程數(shù)是2,核心線程用來執(zhí)行2個任務,用完了所有線程。

然后在核心線程執(zhí)行的2個任務中又用原來的線程池進行執(zhí)行任務,這時候因為沒有線程可以去執(zhí)行任務了,所以會添加到阻塞隊列中等待核心線程執(zhí)行完任務后再執(zhí)行。

但是核心線程想要釋放任務又必須等待這兩個子任務執(zhí)行完,這樣就形成了一個死鎖。

解決方案

解決方式有多種,最簡單的方式可以考慮不要使用隊列,直接使用SynchronousQueue。

ExecutorService executor = new ThreadPoolExecutor(2, 5, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());

讓多的任務直接通過主線程執(zhí)行或者丟棄任務。

當然最好的方式就是避免這種情況的發(fā)生,合理的使用線程池,不要線程池中的任務還要使用這個線程池去執(zhí)行任務。

這種情況是比較難避免的,因為現(xiàn)在大部分業(yè)務開發(fā)都是隱式使用線程池,自己也不知道自己用的哪個線程池。

比如spring的@Async注解,@Scheduled注解等等。

總結

線程池的使用還是要盡量消息,要避免出現(xiàn)線程池中的任務繼續(xù)使用該線程池去執(zhí)行任務,出現(xiàn)死鎖。

也可以考慮對線程池進行監(jiān)控,避免出現(xiàn)大量任務阻塞。

這個問題想要復現(xiàn)需要大量任務并且超過核心線程數(shù)才能復現(xiàn),還是比較難復現(xiàn)的,只有線上大流量的時候才能復現(xiàn)。

責任編輯:武曉燕 來源: 小奏技術
相關推薦

2024-06-28 10:01:04

2019-10-10 15:40:17

redisbug數(shù)據(jù)庫

2020-11-16 12:35:25

線程池Java代碼

2021-09-11 19:00:54

Intro元素MemoryCache

2022-10-25 18:00:00

Redis事務生產(chǎn)事故

2022-06-21 11:24:05

多線程運維

2024-02-04 08:26:38

線程池參數(shù)內(nèi)存

2023-10-11 22:24:00

DubboRedis服務器

2021-06-10 06:59:34

Redis應用API

2009-12-17 14:53:52

VS2008程序

2021-05-20 10:02:50

系統(tǒng)Redis技巧

2021-04-13 08:54:28

dubbo線程池事故排查

2021-08-26 14:26:25

Java代碼集合

2020-10-22 07:09:19

TCP網(wǎng)絡協(xié)議

2017-12-19 14:00:16

數(shù)據(jù)庫MySQL死鎖排查

2019-03-15 16:20:45

MySQL死鎖排查命令

2010-01-06 10:56:47

華為交換機使用

2021-07-11 09:34:45

ArrayListLinkedList

2023-04-06 10:52:18

2011-08-18 13:49:32

筆記本技巧
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: www.日本精品 | 日本三级全黄三级a | 香蕉久久a毛片 | 日韩 欧美 二区 | 91在线导航| 亚洲网站观看 | 一区二区三区欧美在线 | 久久久久久久久久久久久久av | 日日夜夜草 | 在线观看亚洲专区 | 久久99精品久久久久婷婷 | 91n成人| 国产精品污污视频 | www在线视频 | 在线资源视频 | 黄色片a级 | 日韩高清www | 日韩一区在线播放 | 国产乱码精品一区二三赶尸艳谈 | 欧美精三区欧美精三区 | 香蕉视频黄色 | 久久久.com | 久久婷婷国产麻豆91 | 国产精品区二区三区日本 | 欧美成人激情 | 自拍偷拍第一页 | 99精品一级欧美片免费播放 | 国产成人精品一区二 | 国产一区不卡 | 一区二区电影 | 日韩手机在线看片 | 国产精品毛片 | 精品一区二区久久久久久久网精 | 国产一区二区三区久久久久久久久 | 国产视频二区 | 欧美一级二级在线观看 | 国产不卡在线 | 久色视频在线观看 | 免费看a | 日本一区二区三区在线观看 | 欧美寡妇偷汉性猛交 |