dubbo作为一个服务治理框架,功能相对比较完善,性能也挺不错。但很多朋友在使用dubbo的时候,只是简单的参考官方说明进行搭建,并没有过多的去思考一些关键参数的意义(也可能是时间紧任务多,没空出来研究),最终做出来的效果有一定的打折。 这里我根据目前我们项目的使用情况列出几个性能调优的参数及其意义,供大家参考。
在介绍参数之前,我们先了解下dubbo中配置的优先级,以免出现调优参数设置了却没发现效果实际是配置被覆盖导致这样的问题。dubbo分为consumer和provider端,在配置各个参数时,其优先级如下:
1、consumer的method配置
2、provider的method配置
3、consumer的reference配置
4、provider的service配置
5、consumer的consumer节点配置
6、provider的provider节点配置
可以看到,方法级的配置优先级高于接口级,consumer的优先级高于provider。同时,在本地参数配置还存在一层优先级:
1、系统参数(-D),如-Ddubbo.protocol.port=20881
2、xml配置
3、property文件
了解了这两个优先级,调优起来才会更加清晰,省去了一些诸如配置设置了不生效这样的麻烦。注意,其实dubbo中还可以通过将配置写入注册中心的方式覆盖用户配置,优先级高于系统参数(向注册中心写入动态配置覆盖规则 。该功能通常由监控中心或治理中心的页面完成。)
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
//在注册中心(zookeeper)的configurators节点下创建一个持久的子节点(dynamic=false指定)
//子节点的url如下,用url的参数(比如timeout)动态覆盖消费者本地缓存的提供者url的参数。
//以此达到在无需重启应用的情况下,动态调整RPC调用行为的目的
//详见http://dubbo.apache.org/zh-cn/docs/user/demos/config-rule.html
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&timeout=1000"));
接下来我们看看dubbo的几个比较重要的调优参数,及其影响的方式和大概实现。
参数名 | 作用范围 | 默认值 | 说明 | 备注 |
---|---|---|---|---|
actives | consumer | 0 | 每服务消费者每服务每方法最大并发调用数 | 0表示不限制 |
connections | consumer | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 | dubbo时为1,及复用单链接 | |
accepts | provider | 0 | 服务提供方最大可接受连接数 | 0表示不限制 |
iothreads | provider | cpu个数+1 | io线程池大小(固定大小) | |
threads | provider | 200 | 业务线程池大小(固定大小) | |
executes | provider | 0 | 服务提供者每服务每方法最大可并行执行请求数 | 0表示不限制 |
tps | provider | 指定时间内(默认60s)最大的可执行次数,注意与executes的区别 | 默认不开启 |
注意表中参数与图中的对应关系:
1、当consumer发起一个请求时,首先经过active limit(参数actives)进行方法级别的限制,其实现方式为CHM中存放计数器(AtomicInteger),请求时加1,请求完成(包括异常)减1,如果超过actives则等待有其他请求完成后重试或者超时后失败;
//限制 com.foo.BarService 的每个方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个:
<dubbo:reference interface="com.foo.BarService" actives="10" />
//限制 com.foo.BarService 的 sayHello 方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个:
<dubbo:service interface="com.foo.BarService">
<dubbo:method name="sayHello" actives="10" />
</dubbo:service>
@Activate(group = Constants.CONSUMER, value = Constants.ACTIVES_KEY)
public class ActiveLimitFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
URL url = invoker.getUrl();
String methodName = invocation.getMethodName();
int max = invoker.getUrl().getMethodParameter(methodName, Constants.ACTIVES_KEY, 0);
RpcStatus count = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName());
if (max > 0) {
long timeout = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.TIMEOUT_KEY, 0);
long start = System.currentTimeMillis();
long remain = timeout;
int active