zoukankan      html  css  js  c++  java
  • dubbo探究

    一 占位

    待整理。。 

    二 问题汇总

    1 谈谈dubbo的超时重试

    dubbo 启动时默认有重试机制和超时机制。如果在一定的时间内,provider没有返回,则认为本次调用失败。重试机制出现在调用失败时,会再次调用,如果在配置的调用次数内都失败,则认为此次请求异常,消费端出现RpcException提示retry了多少次还是失败。

    如果出现超时,通常是业务处理太慢,可在服务提供方执行 jstack PID > jstack.log 分析线程都卡在哪个方法调用上。如果不能调优性能,请将timeout设大。

    dubbo消费端设置的超时时间需要根据业务实际情况来设定,如果设置的过短,一些复杂业务需要很长时间完成,导致在设定的超时时间内无法完成正常的业务处理。这样消费端达到超时时间,那么dubbo会进行重试,不合理的重试在一些特殊的业务场景下可能会引发很多问题。比如发送邮件,可能会发出多份重复邮件等。

    dubbo调用服务不成功时,默认会重试两次。dubbo的路由机制,会把超时的请求路由到其他机器上,而不是本机尝试,所以dubbo的重试机制也能得到一定程度的保证。但是不合理地配置重试次数,当失败时会进行重试多次,这样在某个时间点出现性能问题,调用方继续重试请求为正常retries倍,容易引起服务雪崩。

    最佳实践:

    1.对于核心的服务中心,去除dubbo超时重试机制,并重新评估设置超时时间。
    2.业务处理代码必须放在服务端,客户端只做参数验证和服务调用,不涉及业务流程处理

    2 dubbo的provider和consumer都配置timeout超时时间, 以哪个为准

    在dubbo的provider和consumer的配置文件中,如果都配置了timeout的超时时间,dubbo默认以consumer中配置的时间为准

    provider.xml的配置:

    <dubbo:service timeout="4000" retries="0" interface="com.dingding.tms.bms.service.BillingZfbCodOrderService" ref="billingZfbCodOrderService" registry="globalRegistry"/>

    conusmer中的配置:

    <dubbo:reference id="billingInterService" interface="com.dingding.tms.bms.service.BillingInterService" protocol="dubbo" check="false" registry="globalRegistry" timeout="3000"/>

    最后这个service在调用时的超时时间就是3秒

    另外,超过3s后的表现如下:

    (1) consumer会在超过3秒时得到一个调用超时的异常。

    (2) provider中代码的执行不会因为超时而中断,在执行完毕后,会得到一个dubbo的警告。

    3 关于dubbo的配置上,你有什么经验

    (1) 在Provider上尽量多地配置Consumer的属性

    原因: 

    a. 作为服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数等

    b. 在provider配置后,consumer不配置则自动使用provider的配置,即作为了consumer端的缺省值。否则,consumer会使用consumer端的全局配置,这对于provider端往往是不可控的。

    ps: 配置的优先级:

    1. 方法级配置别优于接口级别,即小Scope优先 
    2. Consumer端配置优于Provider配置,优于全局配置 
    3. Dubbo Hard Code的配置值(默认)

    根据规则2, 纵使消费端配置优于服务器配置,但消费端配置超时时间不能随心所欲,需要根据业务实际情况来设定。如果设置的太短,复杂业务本来就需要很长时间完成,服务端无法在设定的超时时间内完成业务处理; 如果设置太长,会由于服务端或者网络问题导致客户端大量线程挂起。

    配置示例

    <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService"
        timeout="300" retry="2" loadbalance="random" actives="0"/>
     
    <dubbo:service interface="com.alibaba.hello.api.WorldService" version="1.0.0" ref="helloService"
        timeout="300" retry="2" loadbalance="random" actives="0" >
        <dubbo:method name="findAllPerson" timeout="10000" retries="9" loadbalance="leastactive" actives="5" />
    <dubbo:service/>

    在provider端可以配置的consumer属性有:

    1 timeout 方法调用超时时间

    2 retry 失败重试次数,缺省是2(加上第一次调用,共调用三次)

    3 loadbalance 负责均衡算法(即多个provider如何挑选provider调用),缺省是随机(random),还可以有轮训(roundrobin),最不活跃优先(leastactive, 指从consumer端并发调用效果最好的provider,这样可以相对减少并发的堆积)

    4 actives 消费端最大并发调用限制,即当consumer对一个服务的并发调用达到上限后,新调用会wait直到超时。粒度上,在方法上配置(dubbo: method)则并发针对方法,在接口上配置(dubbo:service)则并发限制针对服务

    (2) 在Provider上配置合理的provider属性

    <dubbo:protocol threads="200" />
    <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" executes="200" >
        <dubbo:method name="findAllPerson" executes="50" />
    </dubbo:service>

    Provider上可以配置的Provider端属性有:

    1. threads,服务线程池大小
    2. executes,一个服务提供者并行执行请求上限,即当Provider对一个服务的并发调用到上限后,新调用会wait(Consumer可能到超时)。在方法上配置(dubbo:method )则并发限制针对方法,在接口上配置(dubbo:service),则并发限制针对服务。

    超时配置:

    Dubbo消费端 
    全局超时配置

    <dubbo:consumer timeout="5000" />

    指定接口以及特定方法超时配置

    <dubbo:reference interface="com.foo.BarService" timeout="2000">
        <dubbo:method name="sayHello" timeout="3000" />
    </dubbo:reference>

    Dubbo服务端 
    全局超时配置

    <dubbo:provider timeout="5000" />

    指定接口以及特定方法超时配置

    <dubbo:provider interface="com.foo.BarService" timeout="2000">
        <dubbo:method name="sayHello" timeout="3000" />
    </dubbo:provider>

    4 dubbo协议超时实现

     Dubbo协议超时实现使用了Future模式,主要涉及类DubboInvoker,ResponseFuture, DefaultFuture。 
    ResponseFuture.get()在请求还未处理完或未到超时前一直是wait状态;响应达到后,设置请求状态,并进行notify唤醒。

    public Object get() throws RemotingException {
            return get(timeout);
        }
    
        public Object get(int timeout) throws RemotingException {
            if (timeout <= 0) {
                timeout = Constants.DEFAULT_TIMEOUT;
            }
            if (! isDone()) {
                long start = System.currentTimeMillis();
                lock.lock();
                try {
                    while (! isDone()) {
                        done.await(timeout, TimeUnit.MILLISECONDS);
                        if (isDone() || System.currentTimeMillis() - start > timeout) {
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
                if (! isDone()) {
                    throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
                }
            }
            return returnFromResponse();
        }
    View Code
        public static void received(Channel channel, Response response) {
            try {
                DefaultFuture future = FUTURES.remove(response.getId());
                if (future != null) {
                    future.doReceived(response);
                } else {
                    logger.warn("The timeout response finally returned at " 
                                + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())) 
                                + ", response " + response 
                                + (channel == null ? "" : ", channel: " + channel.getLocalAddress() 
                                    + " -> " + channel.getRemoteAddress()));
                }
            } finally {
                CHANNELS.remove(response.getId());
            }
        }
    
        private void doReceived(Response res) {
            lock.lock();
            try {
                response = res;
                if (done != null) {
                    done.signal();
                }
            } finally {
                lock.unlock();
            }
            if (callback != null) {
                invokeCallback(callback);
            }
        }
    View Code

    @see http://shiyanjun.cn/archives/325.html dubbo架构设计详解

  • 相关阅读:
    如何从零开始开发一款嵌入式产品(20年的嵌入式经验分享学习)如何从零开始开发一款嵌入式产品(20年的嵌入式经验分享学习)
    shell命令【ulimit】
    ARM开发经典学习网站推荐
    [转]链表逆序
    [转]Rhythmbox中文乱码解决办法
    vi/vim 查找替换使用方法
    [转]程序员的十个层次 你属于哪一层?
    如何在程序中删除一个文件
    C/C++编译器错误代码大全
    R制作eset 的简单步骤
  • 原文地址:https://www.cnblogs.com/balfish/p/8663143.html
Copyright © 2011-2022 走看看