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

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

項目地址
gitee地址:https://gitee.com/dromara/dynamic-tp github地址:https://github.com/dromara/dynamic-tp
最近熬夜給大家準(zhǔn)備了非常全的一套Java一線大廠面試題。全面覆蓋BATJ等一線互聯(lián)網(wǎng)公司的面試題及解答,由BAT一線互聯(lián)網(wǎng)公司大牛帶你深度剖析面試題背后的原理,不僅授你以魚,更授你以漁,為你面試掃除一切障礙。
資源,怎么領(lǐng)取?
掃二維碼,加我微信,備注:面試題
一定要備注:面試題,不要急哦,工作忙完后就會通過!

