线程池隔离
提供一种新的线程池管理方式,用于隔离服务之间的线程池
特性说明
一种新的线程池管理方式,使得提供者应用内各个服务的线程池隔离开来,互相独立,某个服务的线程池资源耗尽不会影响其他正常服务。支持线程池可配置化,由用户手动指定。
使用场景
使用线程池隔离来确保 Dubbo 用于调用远程方法的线程与微服务用于执行其任务的线程是分开的。可以通过防止线程阻塞或相互竞争来帮助提高系统的性能和稳定性。
使用方式
目前可以以 API、XML、Annotation 的方式进行配置
配置参数
ApplicationConfig
新增String executor-management-mode
参数,配置值为default
和isolation
,默认为isolation
。executor-management-mode = default
使用原有 以协议端口为粒度、服务间共享 的线程池管理方式executor-management-mode = isolation
使用新增的 以服务三元组为粒度、服务间隔离 的线程池管理方式
ServiceConfig
新增Executor executor
参数,用以服务间隔离的线程池,可以由用户配置化、提供自己想要的线程池,若没有指定,则会根据协议配置(ProtocolConfig
)信息构建默认的线程池用以服务隔离。
ServiceConfig
新增Executor executor
配置参数只有指定executor-management-mode = isolation
才生效。
API
public void test() {
// provider app
DubboBootstrap providerBootstrap = DubboBootstrap.newInstance();
ServiceConfig serviceConfig1 = new ServiceConfig();
serviceConfig1.setInterface(DemoService.class);
serviceConfig1.setRef(new DemoServiceImpl());
serviceConfig1.setVersion(version1);
// set executor1 for serviceConfig1, max threads is 10
NamedThreadFactory threadFactory1 = new NamedThreadFactory("DemoService-executor");
ExecutorService executor1 = Executors.newFixedThreadPool(10, threadFactory1);
serviceConfig1.setExecutor(executor1);
ServiceConfig serviceConfig2 = new ServiceConfig();
serviceConfig2.setInterface(HelloService.class);
serviceConfig2.setRef(new HelloServiceImpl());
serviceConfig2.setVersion(version2);
// set executor2 for serviceConfig2, max threads is 100
NamedThreadFactory threadFactory2 = new NamedThreadFactory("HelloService-executor");
ExecutorService executor2 = Executors.newFixedThreadPool(100, threadFactory2);
serviceConfig2.setExecutor(executor2);
ServiceConfig serviceConfig3 = new ServiceConfig();
serviceConfig3.setInterface(HelloService.class);
serviceConfig3.setRef(new HelloServiceImpl());
serviceConfig3.setVersion(version3);
// Because executor is not set for serviceConfig3, the default executor of serviceConfig3 is built using
// the threadpool parameter of the protocolConfig ( FixedThreadpool , max threads is 200)
serviceConfig3.setExecutor(null);
// It takes effect only if [executor-management-mode=isolation] is configured
ApplicationConfig applicationConfig = new ApplicationConfig("provider-app");
applicationConfig.setExecutorManagementMode("isolation");
providerBootstrap
.application(applicationConfig)
.registry(registryConfig)
// export with tri and dubbo protocol
.protocol(new ProtocolConfig("tri", 20001))
.protocol(new ProtocolConfig("dubbo", 20002))
.service(serviceConfig1)
.service(serviceConfig2)
.service(serviceConfig3);
providerBootstrap.start();
}
XML
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- NOTE: we need config executor-management-mode="isolation" -->
<dubbo:application name="demo-provider" executor-management-mode="isolation">
</dubbo:application>
<dubbo:config-center address="zookeeper://127.0.0.1:2181"/>
<dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>
<dubbo:registry id="registry1" address="zookeeper://127.0.0.1:2181?registry-type=service"/>
<dubbo:protocol name="dubbo" port="-1"/>
<dubbo:protocol name="tri" port="-1"/>
<!-- expose three service with dubbo and tri protocol-->
<bean id="demoServiceV1" class="org.apache.dubbo.config.spring.impl.DemoServiceImpl"/>
<bean id="helloServiceV2" class="org.apache.dubbo.config.spring.impl.HelloServiceImpl"/>
<bean id="helloServiceV3" class="org.apache.dubbo.config.spring.impl.HelloServiceImpl"/>
<!-- customized thread pool -->
<bean id="executor-demo-service"
class="org.apache.dubbo.config.spring.isolation.spring.support.DemoServiceExecutor"/>
<bean id="executor-hello-service"
class="org.apache.dubbo.config.spring.isolation.spring.support.HelloServiceExecutor"/>
<!-- this service use [executor="executor-demo-service"] as isolated thread pool-->
<dubbo:service executor="executor-demo-service"
interface="org.apache.dubbo.config.spring.api.DemoService" version="1.0.0" group="Group1"
timeout="3000" ref="demoServiceV1" registry="registry1" protocol="dubbo,tri"/>
<!-- this service use [executor="executor-hello-service"] as isolated thread pool-->
<dubbo:service executor="executor-hello-service"
interface="org.apache.dubbo.config.spring.api.HelloService" version="2.0.0" group="Group2"
timeout="5000" ref="helloServiceV2" registry="registry1" protocol="dubbo,tri"/>
<!-- not set executor for this service, the default executor built using threadpool parameter of the protocolConfig -->
<dubbo:service interface="org.apache.dubbo.config.spring.api.HelloService" version="3.0.0" group="Group3"
timeout="5000" ref="helloServiceV3" registry="registry1" protocol="dubbo,tri"/>
</beans>
Annotation
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.isolation.spring.annotation.provider")
public class ProviderConfiguration {
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
return registryConfig;
}
// NOTE: we need config executor-management-mode="isolation"
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig("provider-app");
applicationConfig.setExecutorManagementMode("isolation");
return applicationConfig;
}
// expose services with dubbo protocol
@Bean
public ProtocolConfig dubbo() {
ProtocolConfig protocolConfig = new ProtocolConfig("dubbo");
return protocolConfig;
}
// expose services with tri protocol
@Bean
public ProtocolConfig tri() {
ProtocolConfig protocolConfig = new ProtocolConfig("tri");
return protocolConfig;
}
// customized thread pool
@Bean("executor-demo-service")
public Executor demoServiceExecutor() {
return new DemoServiceExecutor();
}
// customized thread pool
@Bean("executor-hello-service")
public Executor helloServiceExecutor() {
return new HelloServiceExecutor();
}
}
// customized thread pool
public class DemoServiceExecutor extends ThreadPoolExecutor {
public DemoServiceExecutor() {
super(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(),
new NamedThreadFactory("DemoServiceExecutor"));
}
}
// customized thread pool
public class HelloServiceExecutor extends ThreadPoolExecutor {
public HelloServiceExecutor() {
super(100, 100, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(),
new NamedThreadFactory("HelloServiceExecutor"));
}
}
// "executor-hello-service" is beanName
@DubboService(executor = "executor-demo-service", version = "1.0.0", group = "Group1")
public class DemoServiceImplV1 implements DemoService {
@Override
public String sayName(String name) {
return "server name";
}
@Override
public Box getBox() {
return null;
}
}
// not set executor for this service, the default executor built using threadpool parameter of the protocolConfig
@DubboService(version = "3.0.0", group = "Group3")
public class HelloServiceImplV2 implements HelloService {
private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV2.class);
@Override
public String sayHello(String name) {
return "server hello";
}
}
@DubboService(executor = "executor-hello-service", version = "2.0.0", group = "Group2")
public class HelloServiceImplV3 implements HelloService {
private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV3.class);
@Override
public String sayHello(String name) {
return "server hello";
}
}
最后修改 December 20, 2023: Update isolation-executor.md (342374444c6)