新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「猿天地」,作者尹吉?dú)g。轉(zhuǎn)載本文請(qǐng)聯(lián)系猿天地公眾號(hào)。

10余年的古交網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。網(wǎng)絡(luò)營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整古交建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。成都創(chuàng)新互聯(lián)從事“古交網(wǎng)站設(shè)計(jì)”,“古交網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
前言
micrometer 中自帶了很多其他框架的指標(biāo)信息,可以很方便的通過(guò) prometheus 進(jìn)行采集和監(jiān)控,常用的有 JVM 的信息,Http 請(qǐng)求的信息,Tomcat 線程的信息等。
對(duì)于一些比較活躍的框架,有些還是不支持的,比如 Dubbo。如果想監(jiān)控 Dubbo 的一些指標(biāo),比如線程池的狀況,我們需要手動(dòng)去擴(kuò)展,輸出對(duì)應(yīng)的線程池指標(biāo)才行。
在這種情況下,肯定是沒(méi)什么思路的,因?yàn)槟悴恢涝趺慈U(kuò)展,下面給大家介紹去做一件事情之前的思考,方式方法很重要。
- Dubbo 有沒(méi)有現(xiàn)成的實(shí)現(xiàn)?
- 參考 micrometer 中指標(biāo)的實(shí)現(xiàn),依葫蘆畫(huà)瓢?
Dubbo 有沒(méi)有現(xiàn)成的實(shí)現(xiàn)?
完整的實(shí)現(xiàn)應(yīng)該沒(méi)有,至少我還沒(méi)用過(guò),也沒(méi)有那種去搜索引擎一搜就大把結(jié)果的現(xiàn)狀,于是我在 Dubbo 的 Github 上找到了一個(gè)相關(guān)的項(xiàng)目 dubbo-spring-boot-actuator。
https://github.com/apache/dubbo-spring-boot-project/tree/master/dubbo-spring-boot-actuator
dubbo-spring-boot-actuator 看名稱就知道,提供了 Dubbo 相關(guān)的各種信息端點(diǎn)和健康檢查。從這里面也許能發(fā)現(xiàn)點(diǎn)有用的代碼。
果不其然,在介紹頁(yè)面中看到了想要的內(nèi)容,線程池的指標(biāo)數(shù)據(jù),只不過(guò)是拼接成了字符串顯示而已。
- "threadpool": {
- "source": "management.health.dubbo.status.extras",
- "status": {
- "level": "OK",
- "message": "Pool status:OK, max:200, core:200, largest:0, active:0, task:0, service port: 12345",
- "description": null
- }
- }
然后就去翻 dubbo-spring-boot-actuator 的代碼了,沒(méi)找到線程池這塊的代碼。后面在 dubbo.jar 中找到了 ThreadPoolStatusChecker 這個(gè)類,核心邏輯在這里面。現(xiàn)在已經(jīng)解決了第一個(gè)問(wèn)題,就是獲取到 Dubbo 的線程池對(duì)象。
參考 micrometer 中指標(biāo)的實(shí)現(xiàn),依葫蘆畫(huà)瓢?
線程池對(duì)象能拿到了,各種數(shù)據(jù)也就能獲取了。接下來(lái)的問(wèn)題就是如何暴露出去給 prometheus 采集。
兩種方式,一種是自定義一個(gè)新的端點(diǎn)暴露,一種是直接在已有的 prometheus 端點(diǎn)中增加指標(biāo)數(shù)據(jù)的輸出,也就是依葫蘆畫(huà)瓢。
看源碼中已經(jīng)有很多 Metrics 的實(shí)現(xiàn)了,我們也實(shí)現(xiàn)一個(gè) Dubbo 線程池的 Metrics 即可。
上圖框起來(lái)的就是一個(gè)已經(jīng)存在的線程池 Metrics,可以直接復(fù)用代碼。
實(shí)現(xiàn)的主要邏輯就是實(shí)現(xiàn)一個(gè) MeterBinder 接口,然后將你需要的指標(biāo)進(jìn)行輸出即可。于是打算在 bindTo 方法中獲取 Dubbo 的線程池對(duì)象,然后輸出指標(biāo)。經(jīng)過(guò)測(cè)試,在 MeterBinder 實(shí)例化的時(shí)候 Dubbo 還沒(méi)初始化好,拿不到線程池對(duì)象,綁定后無(wú)法成功輸出指標(biāo)。
后面還是打算采用定時(shí)采樣的方式來(lái)輸出,自定義一個(gè)后臺(tái)線程,定時(shí)去輸出數(shù)據(jù)。可以用 Timer,我這圖簡(jiǎn)單就直接 while 循環(huán)了。
- /**
- * Dubbo線程池指標(biāo)
- *
- * @author yinjihuan
- */
- @Configuration
- public class DubboThreadMetrics {
- @Autowired
- private MeterRegistry meterRegistry;
- private final Iterable
TAG = Collections.singletonList(Tag.of("thread.pool.name", "dubboThreadPool")); - @PostConstruct
- public void init() {
- new Thread(() -> {
- while (true) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
- Map
executors = dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY); - for (Map.Entry
entry : executors.entrySet()) { - ExecutorService executor = (ExecutorService) entry.getValue();
- if (executor instanceof ThreadPoolExecutor) {
- ThreadPoolExecutor tp = (ThreadPoolExecutor) executor;
- Gauge.builder("dubbo.thread.pool.core.size", tp, ThreadPoolExecutor::getCorePoolSize)
- .description("核心線程數(shù)")
- .baseUnit("threads")
- .register(meterRegistry);
- Gauge.builder("dubbo.thread.pool.largest.size", tp, ThreadPoolExecutor::getLargestPoolSize)
- .description("歷史最高線程數(shù)")
- .baseUnit("threads")
- .register(meterRegistry);
- Gauge.builder("dubbo.thread.pool.max.size", tp, ThreadPoolExecutor::getMaximumPoolSize)
- .description("最大線程數(shù)")
- .baseUnit("threads")
- .register(meterRegistry);
- Gauge.builder("dubbo.thread.pool.active.size", tp, ThreadPoolExecutor::getActiveCount)
- .description("活躍線程數(shù)")
- .baseUnit("threads")
- .register(meterRegistry);
- Gauge.builder("dubbo.thread.pool.thread.count", tp, ThreadPoolExecutor::getPoolSize)
- .description("當(dāng)前線程數(shù)")
- .baseUnit("threads")
- .register(meterRegistry);
- Gauge.builder("dubbo.thread.pool.queue.size", tp, e -> e.getQueue().size())
- .description("隊(duì)列大小")
- .baseUnit("threads")
- .register(meterRegistry);
- Gauge.builder("dubbo.thread.pool.taskCount", tp, ThreadPoolExecutor::getTaskCount)
- .description("任務(wù)總量")
- .baseUnit("threads")
- .register(meterRegistry);
- Gauge.builder("dubbo.thread.pool.completedTaskCount", tp, ThreadPoolExecutor::getCompletedTaskCount)
- .description("已完成的任務(wù)量")
- .baseUnit("threads")
- .register(meterRegistry);
- }
- }
- }
- }).start();
- }
- }
指標(biāo)信息:
配置線程池圖表
創(chuàng)建一個(gè)新的 dashboard 配置圖表,然后新建 panel 配置指標(biāo)信息
左側(cè)配指標(biāo)信息,右側(cè)選擇對(duì)應(yīng)的圖表格式。需要注意的是,如果有多個(gè)服務(wù)實(shí)例,Metrics 這邊最好是根據(jù)服務(wù)實(shí)例來(lái)顯示,需要在指標(biāo)后面增加條件,如下:
- dubbo_thread_pool_max_size_theads{application="$application", instance=~"$instance"}
關(guān)于作者:尹吉?dú)g,簡(jiǎn)單的技術(shù)愛(ài)好者,《Spring Cloud 微服務(wù)-全棧技術(shù)與案例解析》, 《Spring Cloud 微服務(wù) 入門 實(shí)戰(zhàn)與進(jìn)階》作者, 公眾號(hào)猿天地發(fā)起人。
原文鏈接:http://cxytiandi.com/blog/user/1
當(dāng)前文章:用了很多年Dubbo,連Dubbo線程池監(jiān)控都不知道,覺(jué)得自己很厲害?
網(wǎng)頁(yè)鏈接:http://m.fisionsoft.com.cn/article/dpisgjo.html


咨詢
建站咨詢
