`
manzhizhen
  • 浏览: 293110 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Dubbo源代码分析七:使用executes属性的一个问题

阅读更多

我们知道,在Dubbo中可以给Provider配置线程池大小来控制系统提供服务的最大并行度,默认是200个,如果我们想配置成500,可以如下配置:

 

<dubbo:provider token="true" threads="500"/>

 

当我们想限制某个dubbo服务使用的最大线程数量时,dubbo提供了executes这一属性来提供这个功能,比如我们想限制某个接口最大能同时使用线程池中的100个线程,我们可以如下配置:

 

<dubbo:service interface="com.manzhizhen.service.MyLoverService" executes="100" />

 

我们看下dubbo内部executes是如何实现的,这就得移步到ExecuteLimitFilter,我们直接看下它的实现:

@Activate(group = Constants.PROVIDER, value = Constants.EXECUTES_KEY)

public class ExecuteLimitFilter implements Filter {

 

    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

        URL url = invoker.getUrl();

        String methodName = invocation.getMethodName();

        int max = url.getMethodParameter(methodName, Constants.EXECUTES_KEY, 0);

        // 如果该接口/方法设置了executes并且值大于0

        if (max > 0) {

            // 取出该接口/方法对应的计数器

            RpcStatus count = RpcStatus.getStatus(url, invocation.getMethodName());

            // 如果当前使用的线程数量已经大于等于设置的阈值,那么直接抛出异常

            if (count.getActive() >= max) {

                throw new RpcException("Failed to invoke method " + invocation.getMethodName() + " in provider " + url + ", cause: The service using threads greater than <dubbo:service executes=\"" + max + "\" /> limited.");

            }

        }

        long begin = System.currentTimeMillis();

        boolean isException = false;

        // 计数器+1

        RpcStatus.beginCount(url, methodName);

        try {

            Result result = invoker.invoke(invocation);

            return result;

        } catch (Throwable t) {

            isException = true;

            if (t instanceof RuntimeException) {

                throw (RuntimeException) t;

            } else {

                throw new RpcException("unexpected exception when ExecuteLimitFilter", t);

            }

        } finally {

            // finally中进行计数器-1

            RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, isException);

        }

    }

}

 

看上面的代码,可以得知基本步骤就是(黄底的部分代码):计数器当前值和阈值比较 > 计数器+1 > 计数器-1。这种方式在高并发时会出现静态条件问题的,比如当前该接口已经使用了99个线程,这是时候有两个请求同时到达都发现count.getActive()是小于max的,于是该接口使用的线程数就有可能达到了101个。

 

那么,我们能不能把RpcStatus.beginCount(url, methodName);放到count.getActive() >= max的前面去执行?仔细想想后也不行,这样做的话有可能在高并发时请求被count.getActive() >= max卡死,因为大量请求将计数器+1+1的速度远大于原有请求执行完将计数器-1的速度),导致一段时间内计数器一直大于阈值但实际上该接口使用的线程数却是0

 

于是,为了将比较和+1做成原子的,我们想到了Semaphore信号量Semaphore维护了一组许可,用来管理有限的资源,比如这里的线程数。使用Semaphore的有两点需要注意的地方,第一个就是说如果使用不当会导致Semaphore中的许可数多于最初设置的值,或者变为负数,也就是说,Semaphore并没有对非正常使用作出任何保护措施。还有一点是Semaphore没有方法能直接修改许可数量,但我们可以通过间接方法(比如多release几次以增加许可数量),但毕竟不优雅。

 

<!--StartFragment--> <!--EndFragment-->

Semaphore可以解决上述问题,但当需要修改线程数时,我们应该新建一个Semaphore对象,当采用这种替换Semaphore对象来应对许可数的变化时,一定要确保在仍和情况下acquire和release操作应该在一个Semaphore对象上。这也是我们在设计那些控制并发的小工具时需要注意的地方。

0
0
分享到:
评论
5 楼 manzhizhen 2017-08-12  
yingwuluohan 写道
楼主,我还想请教个问题,一起分析下。
场景是几台台分布式部署的集群服务器,rpc通信用的dubbo,生产和消费也都按照dubbo框架的消费生产模式拆分的。目前运行的进程在上线几周后经常出现服务调用超时的情况,查询数据库监控并没有发现DB有锁表的情况,服务器cpu也正常。在重启应用服务器后超时的现象消失,应用又正常了。
  我几次想在问题发生时下载服务器的内存快照,想找出具体是应用的哪个对象占用了资源。不知道楼主熟悉java堆栈的监控的工具吗?能不能推荐一下,另外就是JVM的调优,当时也考虑到是不是GC没有及时回收导致的,我始终没有找到合适的工具分析内存快照,还有就是怎么样去权衡JVM的配置是否合适


先通过gc日志看是否是gc时间过长导致的超时,如果不是gc原因,可以通过请求日志来判断是否是网络耗时(consumer处理耗时-provider处理耗时)导致。如果不是gc和网络原因,看是否代码内部有什么锁或者队列导致的耗时增加,需要具体情况具体分析。
4 楼 yingwuluohan 2017-08-11  
楼主,我还想请教个问题,一起分析下。
场景是几台台分布式部署的集群服务器,rpc通信用的dubbo,生产和消费也都按照dubbo框架的消费生产模式拆分的。目前运行的进程在上线几周后经常出现服务调用超时的情况,查询数据库监控并没有发现DB有锁表的情况,服务器cpu也正常。在重启应用服务器后超时的现象消失,应用又正常了。
  我几次想在问题发生时下载服务器的内存快照,想找出具体是应用的哪个对象占用了资源。不知道楼主熟悉java堆栈的监控的工具吗?能不能推荐一下,另外就是JVM的调优,当时也考虑到是不是GC没有及时回收导致的,我始终没有找到合适的工具分析内存快照,还有就是怎么样去权衡JVM的配置是否合适
3 楼 yingwuluohan 2017-08-04  
manzhizhen 写道
yingwuluohan 写道
楼主,RpcStatus 中所有对计数的方法全部都是静态的,这样做与给方法加锁的效果是一样的吗?

静态方法和线程安全的方法是没有直接联系的。

我理解错了
2 楼 manzhizhen 2017-07-29  
yingwuluohan 写道
楼主,RpcStatus 中所有对计数的方法全部都是静态的,这样做与给方法加锁的效果是一样的吗?

静态方法和线程安全的方法是没有直接联系的。
1 楼 yingwuluohan 2017-07-28  
楼主,RpcStatus 中所有对计数的方法全部都是静态的,这样做与给方法加锁的效果是一样的吗?

相关推荐

    Dubbo源代码(2.8.4)

    总的来说,Dubbo 2.8.4的源代码是一个深度学习分布式服务治理框架的好材料,它揭示了服务治理的核心机制和实现细节,对于理解微服务架构和提升Java开发能力大有裨益。通过深入研究,开发者可以更好地利用Dubbo来构建...

    Dubbo源代码(2.5.4)

    【Dubbo源代码(2.5.4)】是一份重要的开源项目资源,它包含了Dubbo框架在2.5.4版本的完整源代码。Dubbo是中国阿里巴巴公司贡献的高性能、轻量级的服务治理框架,它专注于服务调用、监控和服务治理。这个版本的源...

    Apache Dubbo:Dubbo服务治理:限流与降级策略

    ### Apache Dubbo:Dubbo服务治理:限流与降级策略 #### 1. Dubbo服务治理概述 ##### 1.1 Dubbo服务治理的重要性 在微服务架构中,服务之间的交互频繁且复杂,特别是在高并发场景下,某些服务可能会因为请求量过...

    Dubbo源代码分析之远程调用过程(2.5.4开发版)

    该文档分析了 Dubbo 框架中 RPC 调用的整个流程,并基于源代码按照执行 时序进行说明,源码版本为2.5.4开发版。 涉及的关键点包括:Invocation、Invoker、Directory、路由、负载均衡、集群容错、过滤器以及监控模块...

    Apache Dubbo:Dubbo高级特性:服务降级与熔断实战

    Apache Dubbo:Dubbo高级特性:服务降级与熔断实战 Dubbo是著名的RCP框架,文档内有干货,提供代码和可复现的命令,值得借鉴。

    dubbo示例代码dubbo-sample

    本示例代码 "dubbo-sample" 提供了对Dubbo核心特性的实践展示,旨在帮助开发者更深入地理解和使用Dubbo。 1. **服务提供者(Provider)** 在Dubbo中,服务提供者是实现业务逻辑的组件,它通过`@Service`注解将接口...

    Apache Dubbo:Dubbo监控与运维:服务性能分析

    ### Apache Dubbo:Dubbo监控与运维:服务性能分析 #### 一、Dubbo监控概述 ##### 1.1 Dubbo监控的重要性 在现代微服务架构中,由于服务之间存在着复杂的调用关系,任何单一服务的性能问题都有可能对整体系统稳定...

    Apache Dubbo:Dubbo服务治理:服务熔断与超时重试

    ### Apache Dubbo:服务熔断与超时重试 #### 一、服务熔断基础 ##### 1.1 服务熔断的概念 服务熔断,作为一种重要的服务稳定性保障措施,在分布式系统中扮演着至关重要的角色。它的工作原理是,当某个服务节点...

    dubbo源代码

    dubbo分布式服务框架,方便大家对分布式服务的学习,方便对dubbo的扩展

    Spring+mybatis+dubbo整合源代码及jar包

    Mybatis则是一个持久层框架,它允许开发者使用简单的XML或注解来映射原生信息,将SQL语句与Java代码分离,避免了传统的JDBC代码的繁琐。Mybatis3.2.8版本在保持简洁的同时,提升了性能,优化了缓存机制,支持更多...

    dubbo2.8.4.jar

    如果使用dubbo遇到错误:com.alibaba.dubbo.remoting.RemotingException: Fail to decode request due to: RpcInvocation 请下载这个jar,替换掉你项目中的那个jar,应该可以解决。

    Apache Dubbo:Dubbo服务治理:负载均衡与容错机制

    ### Apache Dubbo:Dubbo服务治理:负载均衡与容错机制 #### 一、Dubbo服务治理的重要性 在现代微服务架构中,服务间的交互变得日益频繁和复杂,因此需要一种有效的方式来管理这些服务,以确保整个系统的稳定性和...

    Apache Dubbo:Dubbo服务治理:服务路由与动态配置

    ### Apache Dubbo:服务治理——服务路由与动态配置 #### 一、服务治理的重要性 在当前流行的微服务架构中,由于各个服务之间存在着频繁而复杂的交互,如何有效地管理和控制这些服务成为了确保整个系统稳定性和可...

    Apache Dubbo:Dubbo高级特性:服务版本与分组

    - **配置文件方式**:在服务提供者和消费者的配置文件中,使用 `&lt;dubbo:service&gt;` 或 `&lt;dubbo:reference&gt;` 标签的 `version` 属性来指定服务版本。 - **服务提供者配置**: ```xml &lt;dubbo:service interface=...

    dubbo server+client 完整代码

    【Dubbo Server+Client 完整代码】是一个深入学习和实践Dubbo框架的实例项目,它涵盖了服务端(Server)和服务消费者端(Client)的完整实现。Dubbo是阿里巴巴开源的一款高性能、轻量级的Java远程服务框架,它强调了...

    Apache Dubbo:Dubbo核心概念:服务提供者与消费者

    ### Apache Dubbo:服务提供者与消费者核心概念详解 #### 一、Apache Dubbo概览 **Apache Dubbo**是一款高性能、轻量级的开源微服务框架,最初由阿里巴巴内部开发并在2008年开始使用,随后在2011年开源。自2017年...

    dubbo2.8.4源代码

    【标题】"Dubbo 2.8.4 源代码" 涵盖了分布式服务框架的核心技术,是阿里巴巴开源的一款高性能、轻量级的服务治理框架。它为开发者提供了微服务开发所需的诸多功能,包括服务注册与发现、负载均衡、调用链路监控等。...

    dubbo xsd的支持

    6. `&lt;dubbo:provider&gt;` 和 `&lt;dubbo:consumer&gt;`:这两个元素是服务提供者和服务消费者的高级配置,可以用来设置一些全局的属性。 7. `&lt;dubbo:method&gt;` 和 `&lt;dubbo:argument&gt;`:细化服务方法和参数的配置,如异步调用...

    dubbo入门源代码

    apache dubbo官网最简单的小例子,只是按照说明弄了下。

    Dubbo demo

    【标题】"Dubbo Demo" 是一个专门为初学者设计的示例项目,旨在帮助他们快速理解和上手Apache Dubbo框架。Dubbo是一个高性能、轻量级的开源Java RPC框架,它提供了服务治理、集群容错、负载均衡等功能,是阿里巴巴...

Global site tag (gtag.js) - Google Analytics