每日一博 - Review线程池_02
文章目錄
- Pre
- 使用場景
- 場景1:響應速度優先
- 場景2:吞吐量優先
- 線程池設置不合理發生的那些故障
- 線程池的參數如何評估和配置???
- 不用線程池?
- 萬能公式?
- 線程池參數動態化?
- 線程池的監控
Pre
每日一博 - Review線程池
使用場景
為了最大程度利用CPU的多核性能,并行運算的能力是不可或缺的。通過線程池管理線程獲取并發性是一個非常基礎的操作,讓我們來看兩個典型的使用線程池獲取并發性的場景。
場景1:響應速度優先
用戶發起的實時請求,服務追求響應時間。
使用線程池也是有考量的,這種場景最重要的就是獲取最大的響應速度去滿足用戶,所以應該不設置隊列去緩沖并發任務,調高corePoolSize和maxPoolSize去盡可能創造多的線程快速執行任務。
場景2:吞吐量優先
和上一個響應速度優先的場景區別在于, 這類場景任務量巨大,并不需要瞬時的完成,而是關注如何使用有限的資源,盡可能在單位時間內處理更多的任務,也就是吞吐量優先的問題。
所以應該設置隊列去緩沖并發任務,調整合適的corePoolSize去設置處理任務的線程數。在這里,設置的線程數過多可能還會引發線程上下文切換頻繁的問題,也會降低處理任務的速度,降低吞吐量。
線程池設置不合理發生的那些故障
【CASE 1】: 接口大量調用降級 -----------> 使用線程池做并行計算,由于沒有預估好調用的流量,導致最大核心數設置偏小,大量拋出RejectedExecutionException,觸發接口降級條件
【CASE 2】: 服務執行時間過長,作為上游服務整體超時,大量下游服務調用失敗 ------------> 內部邏輯使用線程池做資源隔離,由于隊列設置過長,最大線程數設置失效,導致請求數量增加時,大量任務堆積在隊列中,任務執行時間過長,最終導致下游服務的大量調用超時失敗
總結下:
- 核心線程過小,阻塞隊列過小,最大線程過小,導致接口頻繁拋出拒絕策略異常
- 核心線程過小,阻塞隊列過小,最大線程過大,導致線程調度開銷增大,處理速度下降
- 核心線程過小,阻塞隊列過大,導致任務堆積,接口響應或者程序執行時間拉長
- 核心線程過大,導致線程池內空閑線程過多,過多的占用系統資源,造成資源浪費
如果線程池的配置涉及到上述問題,那么就有可能需要修改代碼,重啟業務來解決;如果發布后參數仍不合理,繼續…
線程池的參數如何評估和配置???
不用線程池?
業務使用線程池是為了獲取并發性,對于獲取并發性,是否可以有什么其他的方案呢替代
萬能公式?
業界的一些線程池參數配置方案:
面試官:你是如何評估一個線程池需要設置多少個線程
設置多少個線程數量通常是根據應用的類型:IO密集型、CPU密集型。
- IO密集型通常設置為2n+1,其中n為CPU核數
- CPU密集型通常設置為 n+1。
實際情況往往復雜得多
其實對于IO密集型類型的應用,網上還有一個公式:線程數 = CPU核心數/(1-阻塞系數)
引入了阻塞系數的概念,一般為0.8~0.9之間,
在我們的業務開發中,基本上都是IO密集型,因為往往都會去操作數據庫,訪問redis,es等存儲型組件,都會涉及到磁盤IO,網絡IO。
IO密集型,可以考慮多設置一些線程,主要目的是可以增加IO的并發度,CPU密集型不宜設置過多線程,因為是會造成線程切換,反而損耗性能。
并沒有得出通用的線程池計算方式。并發任務的執行情況和任務類型相關,IO密集型和CPU密集型的任務運行起來的情況差異非常大,但這種占比是較難合理預估的,這導致很難有一個簡單有效的通用公式能直接計算出結果。
線程池參數動態化?
bingo ,這是正確的方式
動態化線程池的核心設計包括以下三個方面:
簡化線程池配置:線程池構造參數有8個,但是最核心的是3個:corePoolSize、maximumPoolSize,workQueue,它們最大程度地決定了線程池的任務分配和線程分配策略。
考慮到在實際應用中獲取并發性的場景主要是兩種:
(1)并行執行子任務,提高響應速度。這種情況下,應該使用同步隊列,沒有什么任務應該被緩存下來,而是應該立即執行。
(2)并行執行大批次任務,提升吞吐量。這種情況下,應該使用有界隊列,使用隊列去緩沖大批量的任務,隊列容量必須聲明,防止任務無限制堆積。
所以線程池只需要提供這三個關鍵參數的配置,并且提供兩種隊列的選擇,就可以滿足絕大多數的業務需求
參數可動態修改:為了解決參數不好配,修改參數成本高等問題。在Java線程池留有高擴展性的基礎上,封裝線程池,允許線程池監聽同步外部的消息,根據消息進行修改配置。將線程池的配置放置在平臺側,允許查看、修改線程池配置。
增加線程池監控:對某事物缺乏狀態的觀測,就對其改進無從下手。在線程池執行任務的生命周期添加監控能力,幫助了解線程池狀態。
1.現有的解決方案的痛點
2.動態更新的工作原理是什么
在運行期線程池使用方調用此方法設置corePoolSize之后,線程池會直接覆蓋原來的corePoolSize值,并且基于當前值和原始值的比較結果采取不同的處理策略。
對于當前值小于當前工作線程數的情況,說明有多余的worker線程,此時會向當前idle的worker線程發起中斷請求以實現回收,多余的worker在下次idel的時候也會被回收;
對于當前值大于原始值且當前隊列中有待執行任務,則線程池會創建新的worker線程來執行隊列任務,setCorePoolSize具體流程如下:
3.動態設置的注意點有哪些?
在設置核心線程的時候,同時設置最大線程數就可以。只要工作線程不大于最大線程數,那么動態設置就是有效的
4.如何動態指定隊列長度
這一種方式簡單粗暴,直接把 LinkedBlockingQueue 代碼復制出來一份,改個新名字 ResizableCapacityLinkedBlockIngQueue,然后把 capacity 所修飾的 final 關鍵字去掉,再加上一個 #setCapacity 方法
https://www.cnblogs.com/thisiswhy/p/12690630.html
https://juejin.cn/post/6991634257147854856
https://github.com/longtai94/dynamic-threadpool
線程池的監控
如果可以知道一部分線程池運行時指標,可以極大程度上的預防部分故障
- 監控業務線程池的 當前負載以及峰值負載
- 監控線程池在不同時間段 核心線程、最大線程、活躍線程數量指標
- 監控線程 池阻塞隊列相關指標,判斷是否有任務積壓的風險
- 監控線程任務在 運行時拋出的異常數量,診斷投遞的任務是否“健康”
- 監控線程池執行 拒絕策略執行的次數,確定線程池參數是否合理
我的博客即將同步至騰訊云+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=vqa9hqsir7q9
總結
以上是生活随笔為你收集整理的每日一博 - Review线程池_02的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每日一博 - Review线程池
- 下一篇: 小工匠聊架构-布隆过滤器在亿级流量的电商