Dubbo框架線程池使用介紹
1、Dubbo已有線程池
dubbo在使用時(shí),都是通過(guò)創(chuàng)建真實(shí)的業(yè)務(wù)線程池進(jìn)行操作的。目前已知的線程池模型有兩個(gè)和java中的相互對(duì)應(yīng):
- fix: 表示創(chuàng)建固定大小的線程池。也是Dubbo默認(rèn)的使用方式,默認(rèn)創(chuàng)建的執(zhí)行線程數(shù)為200,并且是沒(méi)有任何等待隊(duì)列的。所以在極端的情況下可能會(huì)存在問(wèn)題,比如某個(gè)操作大量執(zhí)行時(shí),可能存在堵塞的情況。后面也會(huì)講相關(guān)的處理辦法。
- cache: 創(chuàng)建非固定大小的線程池,當(dāng)線程不足時(shí),會(huì)自動(dòng)創(chuàng)建新的線程。但是使用這種的時(shí)候需要注意,如果突然有高TPS的請(qǐng)求過(guò)來(lái),方法沒(méi)有及時(shí)完成,則會(huì)造成大量的線程創(chuàng)建,對(duì)系統(tǒng)的CPU和負(fù)載都是壓力,執(zhí)行越多反而會(huì)拖慢整個(gè)系統(tǒng)。
2、自定義線程池
在真實(shí)的使用過(guò)程中可能會(huì)因?yàn)槭褂胒ix模式的線程池,導(dǎo)致具體某些業(yè)務(wù)場(chǎng)景因?yàn)榫€程池中的線程數(shù)量不足而產(chǎn)生錯(cuò)誤,而很多業(yè)務(wù)研發(fā)是對(duì)這些無(wú)感知的,只有當(dāng)出現(xiàn)錯(cuò)誤的時(shí)候才會(huì)去查看告警或者通過(guò)客戶(hù)反饋出現(xiàn)嚴(yán)重的問(wèn)題才去查看,結(jié)果發(fā)現(xiàn)是線程池滿(mǎn)了。所以可以在創(chuàng)建線程池的時(shí),通過(guò)某些手段對(duì)這個(gè)線程池進(jìn)行監(jiān)控,這樣就可以進(jìn)行及時(shí)的擴(kuò)縮容機(jī)器或者告警。下面的這個(gè)程序就是這樣子的,會(huì)在創(chuàng)建線程池后進(jìn)行對(duì)其監(jiān)控,并且及時(shí)作出相應(yīng)處理。
(1)線程池實(shí)現(xiàn), 這里主要是基于對(duì)FixedThreadPool 中的實(shí)現(xiàn)做擴(kuò)展出線程監(jiān)控的部分
package com.lagou.threadpool;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.threadpool.support.fixed.FixedThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.*;
public class WachingThreadPool extends FixedThreadPool implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(WachingThreadPool.class);
// 定義線程池使用的閥值
private static final double ALARM_PERCENT = 0.90;
private final Map<URL, ThreadPoolExecutor> THREAD_POOLS = new ConcurrentHashMap<>();
public WachingThreadPool() {
// 每隔3秒打印線程使用情況
Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(this, 1, 3, TimeUnit.SECONDS);
}
// 通過(guò)父類(lèi)創(chuàng)建線程池
@Override
public Executor getExecutor(URL url) {
final Executor executor = super.getExecutor(url);
if (executor instanceof ThreadPoolExecutor) {
THREAD_POOLS.put(url, (ThreadPoolExecutor) executor);
}
return executor;
}
@Override
public void run() {
// 遍歷線程池
for (Map.Entry<URL, ThreadPoolExecutor> entry : THREAD_POOLS.entrySet()) {
final URL url = entry.getKey();
final ThreadPoolExecutor executor = entry.getValue();
// 計(jì)算相關(guān)指標(biāo)
final int activeCount = executor.getActiveCount();
final int poolSize = executor.getCorePoolSize();
double usedPercent = activeCount / (poolSize * 1.0);
LOGGER.info("線程池執(zhí)行狀態(tài):[{}/{}:{}%]", activeCount, poolSize, usedPercent * 100);
if (usedPercent > ALARM_PERCENT) {
LOGGER.error("超出警戒線! host:{} 當(dāng)前使用率是:{},URL:{}", url.getIp(), usedPercent * 100, url);
}
}
}
}(2)SPI聲明,創(chuàng)建文件(固定的)
META-INF/dubbo/org.apache.dubbo.common.threadpool.ThreadPool
watching=包名.線程池名
(3)在服務(wù)提供方項(xiàng)目引入該依賴(lài)
(4)在服務(wù)提供方項(xiàng)目中設(shè)置使用該線程池生成器
dubbo.provider.threadpool=watching
(5)接下來(lái)需要做的就是模擬整個(gè)流程,因?yàn)樵摼€程當(dāng)前是每1秒抓一次數(shù)據(jù),所以我們需要對(duì)該方法的提供者超過(guò)1秒的時(shí)間(比如這里用休眠Thread.sleep ),消費(fèi)者則需要啟動(dòng)多個(gè)線程來(lái)并行執(zhí)行,來(lái)模擬整個(gè)并發(fā)情況。
(6)在調(diào)用方則嘗試簡(jiǎn)單通過(guò)for循環(huán)啟動(dòng)多個(gè)線程來(lái)執(zhí)行 查看服務(wù)提供方的監(jiān)控情況
package com.lagou;
import com.lagou.bean.ConsumerComponent;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.io.IOException;
public class AnnotationConsumerMain {
public static void main(String[] args) throws IOException, InterruptedException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
context.start();
ConsumerComponent service = context.getBean(ConsumerComponent.class);
while (true) {
for (int i = 0; i < 1000; i++) {
Thread.sleep(5);
new Thread(new Runnable() {
@Override
public void run() {
String msg = service.sayHello("world", 0);
System.out.println(msg);
}
}).start();
}
}
}
@Configuration
@PropertySource("classpath:/dubbo-consumer.properties")
//@EnableDubbo(scanBasePackages = "com.lagou.bean")
@ComponentScan("com.lagou.bean")
@EnableDubbo
static class ConsumerConfiguration {
}
}到此這篇關(guān)于Dubbo框架線程池使用介紹的文章就介紹到這了,更多相關(guān)Dubbo線程池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java程序啟動(dòng)時(shí)-D指定參數(shù)是什么
java服務(wù)啟動(dòng)的時(shí)候,都會(huì)指定一些參數(shù),下面這篇文章主要給大家介紹了關(guān)于Java程序啟動(dòng)時(shí)-D指定參數(shù)是什么的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
java遞歸實(shí)現(xiàn)拼裝多個(gè)api的結(jié)果操作方法
本文給大家分享java遞歸實(shí)現(xiàn)拼裝多個(gè)api的結(jié)果的方法,說(shuō)白了就是好幾個(gè)API結(jié)果拼裝成的,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-09-09
Springboot實(shí)現(xiàn)頁(yè)面間跳轉(zhuǎn)功能
這篇文章主要介紹了Springboot實(shí)現(xiàn)頁(yè)面間跳轉(zhuǎn)功能,本文給大家分享兩種方式,方法一和方法二是不沖突的,但是通常情況下如果用方法二addViewControllers,需要把方法一所寫(xiě)的Controller類(lèi)給注釋掉,需要的朋友可以參考下2023-10-10
Spring Boot中l(wèi)ombok的安裝與使用詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot中l(wèi)ombok安裝與使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09
SpringBoot實(shí)現(xiàn)圖片防盜鏈功能
出于安全考慮,我們需要后端返回的圖片只允許在某個(gè)網(wǎng)站內(nèi)展示,不想被爬蟲(chóng)拿到圖片地址后被下載,或者,不想瀏覽器直接訪問(wèn)圖片鏈接,所以本文將給大家介紹SpringBoot實(shí)現(xiàn)圖片防盜鏈功能,需要的朋友可以參考下2024-04-04
Java利用Map實(shí)現(xiàn)計(jì)算文本中字符個(gè)數(shù)
這篇文章主要為大家詳細(xì)介紹了Java如何利用Map集合實(shí)現(xiàn)計(jì)算文本中字符個(gè)數(shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-08-08
線程局部變量的實(shí)現(xiàn)?ThreadLocal使用及場(chǎng)景介紹
這篇文章主要為大家介紹了線程局部變量的實(shí)現(xiàn)?ThreadLocal使用及場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
解析SpringBoot @EnableAutoConfiguration的使用
這篇文章主要介紹了解析SpringBoot @EnableAutoConfiguration的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

