美團(tuán)動態(tài)線程池實(shí)踐思路,開源了
背景
使用線程池 ThreadPoolExecutor 過程中你是否有以下痛點(diǎn)呢?
1.代碼中創(chuàng)建了一個 ThreadPoolExecutor,但是不知道那幾個核心參數(shù)設(shè)置多少比較合適
2.憑經(jīng)驗(yàn)設(shè)置參數(shù)值,上線后發(fā)現(xiàn)需要調(diào)整,改代碼重啟服務(wù),非常麻煩
3.線程池相對開發(fā)人員來說是個黑盒,運(yùn)行情況不能及時(shí)感知到,直到出現(xiàn)問題
如果你有以上痛點(diǎn),動態(tài)可監(jiān)控線程池(DynamicTp)或許能幫助到你。
如果看過 ThreadPoolExecutor 的源碼,大概可以知道它對核心參數(shù)基本都有提供 set / get 方法以及一些擴(kuò)展方法,可以在運(yùn)行時(shí)動態(tài)修改、獲取相應(yīng)的值。
現(xiàn)在大多數(shù)的互聯(lián)網(wǎng)項(xiàng)目其實(shí)都會微服務(wù)化部署,有一套自己的服務(wù)治理體系,微服務(wù)組件中的分布式配置中心扮演的就是動態(tài)修改配置, 實(shí)時(shí)生效的角色。那么我們是否可以結(jié)合配置中心來做運(yùn)行時(shí)線程池參數(shù)的動態(tài)調(diào)整呢?答案是肯定的,而且配置中心相對都是高可用的, 使用它也不用過于擔(dān)心配置推送出現(xiàn)問題這類事兒,而且也能減少研發(fā)動態(tài)線程池組件的難度和工作量。
綜上,可以總結(jié)出以下的背景
廣泛性:在 Java 開發(fā)中,想要提高系統(tǒng)性能,線程池已經(jīng)是一個 90%以上的人都會選擇使用的基礎(chǔ)工具
不確定性:項(xiàng)目中可能會創(chuàng)建很多線程池,既有 IO 密集型的,也有 CPU 密集型的,但線程池的參數(shù)并不好確定;需要有套機(jī)制在運(yùn)行過程中動態(tài)去調(diào)整參數(shù)
無感知性,線程池運(yùn)行過程中的各項(xiàng)指標(biāo)一般感知不到;需要有套監(jiān)控報(bào)警機(jī)制在事前、事中就能讓開發(fā)人員感知到線程池的運(yùn)行狀況,及時(shí)處理
高可用性,配置變更需要及時(shí)推送到客戶端;需要有高可用的配置管理推送服務(wù),配置中心是現(xiàn)在大多數(shù)互聯(lián)網(wǎng)系統(tǒng)都會使用的組件,與之結(jié)合可以大幅度減少開發(fā)量及接入難度
簡介
基于以上背景分析,我們對線程池 ThreadPoolExecutor 做一些擴(kuò)展增強(qiáng),主要實(shí)現(xiàn)以下目標(biāo)
1.實(shí)現(xiàn)對運(yùn)行中線程池參數(shù)的動態(tài)修改,實(shí)時(shí)生效
2.實(shí)時(shí)監(jiān)控線程池的運(yùn)行狀態(tài),觸發(fā)設(shè)置的報(bào)警策略時(shí)報(bào)警,報(bào)警信息推送辦公平臺
3.定時(shí)采集線程池指標(biāo)數(shù)據(jù),配合像 grafana 這種可視化監(jiān)控平臺做大盤監(jiān)控
經(jīng)過多個版本的迭代,目前最新版本 v1.0.9 具有以下特性??
代碼零侵入:所有配置都放在配置中心,對業(yè)務(wù)代碼零侵入
輕量簡單:基于 SpringBoot 實(shí)現(xiàn),引入 starter,接入只需簡單 4 步就可完成,順利 3 分鐘搞定
高可擴(kuò)展:框架核心功能都提供 SPI 接口供用戶自定義個性化實(shí)現(xiàn)(配置中心、配置文件解析、通知告警、監(jiān)控?cái)?shù)據(jù)采集、任務(wù)包裝等等)
線上大規(guī)模應(yīng)用:參考美團(tuán)線程池實(shí)踐,美團(tuán)內(nèi)部已經(jīng)有該理論成熟的應(yīng)用經(jīng)驗(yàn)
多平臺通知報(bào)警:提供多種報(bào)警維度(配置變更通知、活性報(bào)警、容量閾值報(bào)警、拒絕觸發(fā)報(bào)警、任務(wù)執(zhí)行或等待超時(shí)報(bào)警),已支持企業(yè)微信、釘釘、飛書、郵件報(bào)警,同時(shí)提供 SPI 接口可自定義擴(kuò)展實(shí)現(xiàn)
監(jiān)控:定時(shí)采集線程池指標(biāo)數(shù)據(jù),支持通過 MicroMeter、JsonLog 日志輸出、Endpoint 三種方式,可通過 SPI 接口自定義擴(kuò)展實(shí)現(xiàn)
任務(wù)增強(qiáng):提供任務(wù)包裝功能,實(shí)現(xiàn) TaskWrapper 接口即可,如 MdcTaskWrapper、TtlTaskWrapper、SwTraceTaskWrapper,可以支持線程池上下文信息傳遞
兼容性:JUC 普通線程池和 Spring 中的 ThreadPoolTaskExecutor 也可以被框架監(jiān)控,@Bean 定義時(shí)加 @DynamicTp 注解即可
可靠性:框架提供的線程池實(shí)現(xiàn) Spring 生命周期方法,可以在 Spring 容器關(guān)閉前盡可能多的處理隊(duì)列中的任務(wù)
多模式:參考 Tomcat 線程池提供了 IO 密集型場景使用的 EagerDtpExecutor 線程池
支持多配置中心:基于主流配置中心實(shí)現(xiàn)線程池參數(shù)動態(tài)調(diào)整,實(shí)時(shí)生效,已支持 Nacos、Apollo、Zookeeper、Consul、Etcd,同時(shí)也提供 SPI 接口可自定義擴(kuò)展實(shí)現(xiàn)
中間件線程池管理:集成管理常用第三方組件的線程池,已集成Tomcat、Jetty、Undertow、Dubbo、RocketMq、Hystrix、Grpc 等組件的線程池管理(調(diào)參、監(jiān)控報(bào)警)
架構(gòu)設(shè)計(jì)
框架功能大體可以分為以下幾個模塊
1.配置變更監(jiān)聽模塊
2.服務(wù)內(nèi)部線程池管理模塊
3.三方組件線程池管理模塊
4.監(jiān)控模塊
5.通知告警模塊
代碼結(jié)構(gòu)

1.adapter 模塊:主要是適配一些第三方組件的線程池管理,目前已經(jīng)實(shí)現(xiàn)的有 SpringBoot 內(nèi)置的三大 web 容器(Tomcat、Jetty、Undertow)、Dubbo、RocketMq、Hystrix、Grpc 的線程池管理, 后續(xù)會接入其他常用組件的線程池管理。
2.common 模塊:主要是一些各個模板都會用到的類,解耦依賴,復(fù)用代碼,大家日常開發(fā)中可能也經(jīng)常會這樣做。
3.core 模塊:該框架的核心代碼都在這個模塊里,包括動態(tài)調(diào)整參數(shù),監(jiān)控報(bào)警,以及串聯(lián)整個項(xiàng)目流程都在此。
4.example 模塊:提供一個簡單使用示例,方便使用者參照
5.extension 模塊:放一些擴(kuò)展功能實(shí)現(xiàn),比如基于 redis 的流控?cái)U(kuò)展、郵件發(fā)送擴(kuò)展、skywalking 上下文傳遞擴(kuò)展等
6.logging 模塊:用于配置框架內(nèi)部日志的輸出,目前主要用于輸出線程池監(jiān)控指標(biāo)數(shù)據(jù)到指定文件
7.starter模塊:提供獨(dú)立功能模塊的依賴封裝、自動配置等相關(guān)。
配置變更監(jiān)聽模塊
1.監(jiān)聽特定配置中心的指定配置文件(已實(shí)現(xiàn) Nacos、Apollo、Zookeeper、Consul、Etcd),可通過內(nèi)部提供的SPI接口擴(kuò)展其他實(shí)現(xiàn)
2.解析配置文件內(nèi)容,內(nèi)置實(shí)現(xiàn) yml、properties、json 配置文件的解析,可通過內(nèi)部提供的 SPI 接口擴(kuò)展其他實(shí)現(xiàn)
3.通知線程池管理模塊實(shí)現(xiàn)參數(shù)的刷新
服務(wù)內(nèi)部線程池管理模塊
1.服務(wù)啟動時(shí)從配置中心拉取配置,生成線程池實(shí)例注冊到內(nèi)部線程池注冊中心以及 Spring 容器中
2.接受配置監(jiān)聽模塊的刷新事件,實(shí)現(xiàn)線程池參數(shù)的刷新
3.代碼中通過依賴注入(推薦)或者 DtpRegistry.getDtpExecutor() 方法根據(jù)線程池名稱來獲取線程池實(shí)例
三方組件線程池管理
1.服務(wù)啟動獲取第三方中間件的線程池,被框架管理起來
2.接受參數(shù)刷新、指標(biāo)收集、通知報(bào)警事件,進(jìn)行相應(yīng)的處理
監(jiān)控模塊
實(shí)現(xiàn)監(jiān)控指標(biāo)采集以及輸出,默認(rèn)提供以下三種方式,也可通過內(nèi)部提供的 SPI 接口擴(kuò)展其他實(shí)現(xiàn)
1.默認(rèn)實(shí)現(xiàn) JsonLog 輸出到磁盤,可以自己采集解析日志,存儲展示
2.MicroMeter采集,引入 MicroMeter 相關(guān)依賴,暴露相關(guān)端點(diǎn),采集指標(biāo)數(shù)據(jù),結(jié)合 Grafana 做監(jiān)控大盤
3.暴雷自定義 Endpoint 端點(diǎn)(dynamic-tp),可通過 http 方式實(shí)時(shí)訪問
通知告警模塊
對接辦公平臺,實(shí)現(xiàn)通知告警功能,已支持釘釘、企微、飛書、郵件,可通過內(nèi)部提供的 SPI 接口擴(kuò)展其他實(shí)現(xiàn),通知告警類型如下
1.線程池主要參數(shù)變更通知
2.阻塞隊(duì)列容量達(dá)到設(shè)置的告警閾值
3.線程池活性達(dá)到設(shè)置的告警閾值
4.觸發(fā)拒絕策略告警,格式:A/B,A:該報(bào)警項(xiàng)前后兩次報(bào)警區(qū)間累加數(shù)量,B:該報(bào)警項(xiàng)累計(jì)總數(shù)
5.任務(wù)執(zhí)行超時(shí)告警,格式:A/B,A:該報(bào)警項(xiàng)前后兩次報(bào)警區(qū)間累加數(shù)量,B:該報(bào)警項(xiàng)累計(jì)總數(shù)
6.任務(wù)等待超時(shí)告警,格式:A/B,A:該報(bào)警項(xiàng)前后兩次報(bào)警區(qū)間累加數(shù)量,B:該報(bào)警項(xiàng)累計(jì)總數(shù)

項(xiàng)目地址
gitee地址:
https://gitee.com/dromara/dynamic-tp
github地址:
https://github.com/dromara/dynamic-tp