dubbo 容错策略


dubbo 容错策略

        

官网:https://dubbo.apache.org/zh/docs/advanced/fault-tolerent-strategy/

           

             

                                     

容错策略

          

容错策略:消费端服务调用出错时的处理方式

               

             

消费端服务调用流程

消费端应用启动时,创建clusterInvoker对象(默认为failoverClusterInvoker)

# 消费端发起服务调用时,依次执行如下过程:
获取所有可用invoker列表(directory#list)
 * dynamicDirectory:动态invoker列表,从注册中心获取
 * staticDirectory:静态invoker列表,创建staticDirectory对象时传入的invoker列表
对所有可用列表进行路由过滤(routerChain#route)
使用负载均衡算法(loadbalance#select)在路由过滤后的invoker列表选择一个invoker,发起远程服务调用;

# 服务调用结果处理
如果调用正常,消费端收到服务端返回的结果(如果有结果返回);
如果调用异常,执行容错策略:重试(failover,默认)、忽略异常(failsafe)等;
如果设置了mock,服务调用异常时,可进行服务降级;

             

Cluster:容错接口

@SPI(Cluster.DEFAULT)     //默认为failover
public interface Cluster {

    String DEFAULT = "failover";

    /**
     * Merge the directory invokers to a virtual invoker.
     *
     * @param <T>
     * @param directory
     * @return cluster invoker
     * @throws RpcException
     */
    @Adaptive
    <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException;

    static Cluster getCluster(ScopeModel scopeModel, String name) {
        return getCluster(scopeModel, name, true);
    }

    static Cluster getCluster(ScopeModel scopeModel, String name, boolean wrap) {
        if (StringUtils.isEmpty(name)) {
            name = Cluster.DEFAULT;
        }
        return ScopeModelUtil.getApplicationModel(scopeModel).getExtensionLoader(Cluster.class).getExtension(name, wrap);
    }
}

            

           

容错策略说明

# FailoverCluster
消费端调用失败,会进行重试(retries参数设置重试次数);
该策略适合读操作、幂等写操作,同时重试会加大下游服务器负载
<dubbo:reference retries="2" />                  //接口级别容错设置
<dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />  //方法级别容错设置
</dubbo:reference>

# FailfastCluster
消费端调用失败,不会重试,直接返回异常;
该策略用在非幂等接口上,受网络抖动影响较大(可能网络原因导致服务调用失败)
 
# FailsafeCluster
消费端调用失败,忽略异常;
该策略不关心是否调用成功,也不抛出异常,适用于日志发送等场景
 
# FailbackCluster
消费端调用失败,会在失败记录中记录下来,由定时线程池重试;
适用于一致性(最终一致性)要求比较高的场景
 
# ForkingCluster
同时对多个服务发起调用,只要有一个返回结果,调用结束;
适用于对事实现性要求比较高的场景,但会浪费很多资源
 
# BroadcastCluster
调用所有可用服务,任何一个出错则抛出异常;
适用于服务状态更新后的广播
 
# AvaliableCluster
请求不做负载均衡,遍历所有可用列表,选出第一个可用服务调用,如果没有可用服务,则抛出异常
 
# MockCluster
服务调用失败,不抛出异常,返回默认的结果;
或者不调用远程服务,强制返回预设结果
 
# MergeableCluster
把不同group的服务请求结果合并
 
# ZoneAwareCluster:多注册中心,服务选取设置
This extension provides a strategy to decide how to distribute traffics among them:
 * 1. registry marked as 'preferred=true' has the highest priority.
 * 2. check the zone the current request belongs, pick the registry that has the same zone first.
 * 3. Evenly balance traffic between all registries based on each registry's weight.
 * 4. Pick anyone that's available.
带有prefered=true的注册中心优先使用:
 * <dubbo:registry address="zookeeper://127.0.0.1:2181" preferred="true" />
优先选取注册中心为同一个zone的服务:
 * <dubbo:registry address="zookeeper://127.0.0.1:2181" zone="beijing" />
可根据权重对注册中心进行负载均衡:
 * <dubbo:registry id="beijing" address="zookeeper://127.0.0.1:2181" weight="100" />
 * <dubbo:registry id="shanghai" address="zookeeper://127.0.0.1:2182" weight="10" />
如果注册中心没有以上配置,选取任何一个可用的服务中心拉取服务信息,进行服务调用

             

FailoverCluster

public class FailoverCluster extends AbstractCluster {

    public final static String NAME = "failover";

    @Override
    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
        return new FailoverClusterInvoker<>(directory);
    }   //消费端应用启动时,创建failoverClusterInvoker对象

}

              

消费端创建failoverClusterInvoker对象调用栈

# 创建FailoverClusterInvoker对象,默认创建该对象
at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.<init>(FailoverClusterInvoker.java:52)
 
# join操作
at org.apache.dubbo.rpc.cluster.support.FailoverCluster.doJoin(FailoverCluster.java:33)
at org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster.join(AbstractCluster.java:58)
at org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper.join(MockClusterWrapper.java:39)
 
# 创建invoker
at org.apache.dubbo.registry.integration.RegistryProtocol.doCreateInvoker(RegistryProtocol.java:564)
 
# 获取invoker
at org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol.getInvoker(InterfaceCompatibleRegistryProtocol.java:58)
 
# MigrationInvoker类
at org.apache.dubbo.registry.client.migration.MigrationInvoker.refreshInterfaceInvoker(MigrationInvoker.java:448)
at org.apache.dubbo.registry.client.migration.MigrationInvoker.migrateToApplicationFirstInvoker(MigrationInvoker.java:239)
 
# MigrationRuleHandler类
at org.apache.dubbo.registry.client.migration.MigrationRuleHandler.refreshInvoker(MigrationRuleHandler.java:73)
at org.apache.dubbo.registry.client.migration.MigrationRuleHandler.doMigrate(MigrationRuleHandler.java:57)
	  - locked <0x21db> (a org.apache.dubbo.registry.client.migration.MigrationRuleHandler)
at org.apache.dubbo.registry.client.migration.MigrationRuleListener.onRefer(MigrationRuleListener.java:241)
 
# RegistryProtocol类
at org.apache.dubbo.registry.integration.RegistryProtocol.interceptInvoker(RegistryProtocol.java:531)
at org.apache.dubbo.registry.integration.RegistryProtocol.doRefer(RegistryProtocol.java:500)
at org.apache.dubbo.registry.integration.RegistryProtocol.refer(RegistryProtocol.java:485)
 
# refer操作
at org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper.refer(ProtocolListenerWrapper.java:74)
at org.apache.dubbo.qos.protocol.QosProtocolWrapper.refer(QosProtocolWrapper.java:83)
at org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper.refer(ProtocolFilterWrapper.java:71)
at org.apache.dubbo.rpc.protocol.ProtocolSerializationWrapper.refer(ProtocolSerializationWrapper.java:52)
at org.apache.dubbo.rpc.Protocol$Adaptive.refer(Protocol$Adaptive.java:-1)
 
# ReferenceConfig类
at org.apache.dubbo.config.ReferenceConfig.createInvokerForRemote(ReferenceConfig.java:481)
at org.apache.dubbo.config.ReferenceConfig.createProxy(ReferenceConfig.java:386)
at org.apache.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:275)
	  - locked <0x21dc> (a org.apache.dubbo.config.ReferenceConfig)
at org.apache.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:216)
 
# SimpleReferenceCache类
at org.apache.dubbo.config.utils.SimpleReferenceCache.get(SimpleReferenceCache.java:110)
 
# DefaultModuleDeployer类
at org.apache.dubbo.config.deploy.DefaultModuleDeployer.lambda$referServices$6(DefaultModuleDeployer.java:384)
at org.apache.dubbo.config.deploy.DefaultModuleDeployer$$Lambda$880/0x0000000801039dc8.accept(Unknown Source:-1)
	  at java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(ConcurrentHashMap.java:4780)
 
# DefaultModuleDeployer类
at org.apache.dubbo.config.deploy.DefaultModuleDeployer.referServices(DefaultModuleDeployer.java:364)
at org.apache.dubbo.config.deploy.DefaultModuleDeployer.start(DefaultModuleDeployer.java:151)
	  - locked <0x21dd> (a org.apache.dubbo.config.deploy.DefaultModuleDeployer)
 
# DubboDeployApplicationListener类
at org.apache.dubbo.config.spring.context.DubboDeployApplicationListener.onContextRefreshedEvent(DubboDeployApplicationListener.java:108)
at org.apache.dubbo.config.spring.context.DubboDeployApplicationListener.onApplicationEvent(DubboDeployApplicationListener.java:98)
at org.apache.dubbo.config.spring.context.DubboDeployApplicationListener.onApplicationEvent(DubboDeployApplicationListener.java:44)
 
# SimpleApplicationEventMulticaster类
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
 
# AbstractApplicationContext类
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:938)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
	  - locked <0x21de> (a java.lang.Object)
 
# ServletWebServerApplicationContext类
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
 
# SpringApplication类
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290)
 
# 项目启动入口
at com.example.demo.DemoApplication.main(DemoApplication.java:12)

               

AbstractClusterInvoker

public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {

    @Override
    public Result invoke(final Invocation invocation) throws RpcException {
        checkWhetherDestroyed();

        // binding attachments into invocation.
//        Map<String, Object> contextAttachments = RpcContext.getClientAttachment().getObjectAttachments();
//        if (contextAttachments != null && contextAttachments.size() != 0) {
//            ((RpcInvocation) invocation).addObjectAttachmentsIfAbsent(contextAttachments);
//        }

        List<Invoker<T>> invokers = list(invocation);   //返回路由过滤后的invoker服务列表
        LoadBalance loadbalance = initLoadBalance(invokers, invocation);  //初始化负载均衡器
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
        return doInvoke(invocation, invokers, loadbalance);
    }

    protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
        return getDirectory().list(invocation);
    }   //getDirectory():获取所有invoker服务列表
        //list(invocation):执行路由过滤,返回过滤后的列表

    protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {
        ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(invocation.getModuleModel());
        if (CollectionUtils.isNotEmpty(invokers)) {  //invokers列表不为空,从url的参数中获取使用的负载均衡算法
            return applicationModel.getExtensionLoader(LoadBalance.class).getExtension(
                invokers.get(0).getUrl().getMethodParameter(
                    RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE
                )  //默认使用随机负载均衡
            );
        } else {
            return applicationModel.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);
        }          //invokers列表为空,默认也是使用随机负载均衡算法
    }

               

FailoverClusterInvoker:服务调用失败时进行重试

public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {

    private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);

    public FailoverClusterInvoker(Directory<T> directory) {
        super(directory);
    }

    @Override
    @SuppressWarnings({"unchecked", "rawtypes"})
    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyInvokers = invokers;
        checkInvokers(copyInvokers, invocation);
        String methodName = RpcUtils.getMethodName(invocation);
        int len = calculateInvokeTimes(methodName);
        // retry loop.
        RpcException le = null; // last exception.
        List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
        Set<String> providers = new HashSet<String>(len);
        for (int i = 0; i < len; i++) {
            //Reselect before retry to avoid a change of candidate `invokers`.
            //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
            if (i > 0) {
                checkWhetherDestroyed();
                copyInvokers = list(invocation);
                // check again
                checkInvokers(copyInvokers, invocation);
            }
            Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
            invoked.add(invoker);
            RpcContext.getServiceContext().setInvokers((List) invoked);
            boolean success = false;
            try {
                Result result = invokeWithContext(invoker, invocation);
                if (le != null && logger.isWarnEnabled()) {
                    logger.warn("Although retry the method " + methodName
                            + " in the service " + getInterface().getName()
                            + " was successful by the provider " + invoker.getUrl().getAddress()
                            + ", but there have been failed providers " + providers
                            + " (" + providers.size() + "/" + copyInvokers.size()
                            + ") from the registry " + directory.getUrl().getAddress()
                            + " on the consumer " + NetUtils.getLocalHost()
                            + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                            + le.getMessage(), le);
                }
                success = true;
                return result;
            } catch (RpcException e) {  
                if (e.isBiz()) { // biz exception.
                    throw e;
                }  //如果消费端收到的异常为biz exception,不重试,直接抛出异常
                le = e;
            } catch (Throwable e) {
                le = new RpcException(e.getMessage(), e);
            } finally {
                if (!success) {
                    providers.add(invoker.getUrl().getAddress());
                }
            }
        }
        throw new RpcException(le.getCode(), "Failed to invoke the method "
                + methodName + " in the service " + getInterface().getName()
                + ". Tried " + len + " times of the providers " + providers
                + " (" + providers.size() + "/" + copyInvokers.size()
                + ") from the registry " + directory.getUrl().getAddress()
                + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
                + Version.getVersion() + ". Last error is: "
                + le.getMessage(), le.getCause() != null ? le.getCause() : le);
    }

    private int calculateInvokeTimes(String methodName) {  //失败重试次数,失败后默认重试2次
        int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
        RpcContext rpcContext = RpcContext.getClientAttachment();
        Object retry = rpcContext.getObjectAttachment(RETRIES_KEY);
        if (retry instanceof Number) {
            len = ((Number) retry).intValue() + 1;
            rpcContext.removeAttachment(RETRIES_KEY);
        }
        if (len <= 0) {
            len = 1;
        }

        return len;
    }

}

                 

                  

                                     

容错配置

       

@DubboReference:消费端服务调用,使用该注解配置容错策略

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface DubboReference {
 
    /**
     * Interface class, default value is void.class
     */
    Class<?> interfaceClass() default void.class;
 
    /**
     * Interface class name, default value is empty string
     */
    String interfaceName() default "";
 
    String group() default "";    //服务分组
    String version() default "";  //服务版本
 
    /**
     * Service target URL for direct invocation, if this is specified, then registry center takes no effect.
     */
    String url() default "";      //直连服务提供端(如果配置了,则不使用注册中心)
 
    /**
     * Client transport type, default value is "netty"
     */
    String client() default "";   //客户端传输方式,默认为netty
 
    /**
     * Whether to enable generic invocation, default value is false
     * @deprecated Do not need specify generic value, judge by injection type and interface class
     */
    @Deprecated
    boolean generic() default false;   //已禁用
 
    /**
     * When enable, prefer to call local service in the same JVM if it's present, default value is true
     * @deprecated using scope="local" or scope="remote" instead
     */
    @Deprecated
    boolean injvm() default true;      //已禁用
 
    /**
     * Check if service provider is available during boot up, default value is true
     */
    boolean check() default true;
 
    /**
     * Whether eager initialize the reference bean when all properties are set, default value is true ( null as true)
     * @see ReferenceConfigBase#shouldInit()
     */
    boolean init() default true;
 
    /**
     * Whether to make connection when the client is created, the default value is false
     */
    boolean lazy() default false;
 
    /**
     * Export an stub service for event dispatch, default value is false.
     * <p>
     * see org.apache.dubbo.rpc.Constants#STUB_EVENT_METHODS_KEY
     */
    boolean stubevent() default false;
 
    /**
     * Whether to reconnect if connection is lost, if not specify, reconnect is enabled by default, and the interval
     * for retry connecting is 2000 ms
     * <p>
     * see org.apache.dubbo.remoting.Constants#DEFAULT_RECONNECT_PERIOD
     */
    String reconnect() default "";
 
    /**
     * Whether to stick to the same node in the cluster, the default value is false
     * <p>
     * see Constants#DEFAULT_CLUSTER_STICKY
     */
    boolean sticky() default false;
 
    /**
     * How the proxy is generated, legal values include: jdk, javassist
     */
    String proxy() default "";
 
    /**
     * Service stub name, use interface name + Local if not set
     */
    String stub() default "";
 
    /**
     * Cluster strategy, legal values include: failover, failfast, failsafe, failback, forking
     * you can use {@link org.apache.dubbo.common.constants.ClusterRules#FAIL_FAST} ……
     */
    String cluster() default ClusterRules.EMPTY;  //容错策略,可选值:failover, failfast, failsafe, failback, forking
 
    /**
     * Service invocation retry times
     * <p>
     * see Constants#DEFAULT_RETRIES
     */
    int retries() default -1;                     //重试次数
 
    /**
     * Service mock name, use interface name + Mock if not set
     */
    String mock() default "";                     //服务降级接口
 
    /**
     * Service merger
     */
    String merger() default "";                   //分组聚合
 
    /**
     * Customized parameter key-value pair, for example: {key1, value1, key2, value2} or {"key1=value1", "key2=value2"}
     */
    String[] parameters() default {};             //自定义参数,如:
            //forking:@DubboReference(cluster = ClusterRules.FORKING, parameters = {"forks","3"})
            //broadcast:@DubboReference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"})
 
    /**
     * Load balance strategy, legal values include: random, roundrobin, leastactive
     * you can use {@link org.apache.dubbo.common.constants.LoadbalanceRules#RANDOM} ……
     */
    String loadbalance() default LoadbalanceRules.EMPTY;  //负载均衡算法,默认为随机算法

    /**
     * Maximum connections service provider can accept, default value is 0 - connection is shared
     */
    int connections() default -1;
 
    /**
     * The callback instance limit peer connection
     * <p>
     * see org.apache.dubbo.rpc.Constants#DEFAULT_CALLBACK_INSTANCES
     */
    int callbacks() default -1;
 
    /**
     * Callback method name when connected, default value is empty string
     */
    String onconnect() default "";
 
    /**
     * Callback method name when disconnected, default value is empty string
     */
    String ondisconnect() default "";
 
    /**
     * Service owner, default value is empty string
     */
    String owner() default "";
 
    /**
     * Service layer, default value is empty string
     */
    String layer() default "";
  
    /**
     * Whether to enable async invocation, default value is false
     */
    boolean async() default false;
 
    /**
     * Maximum active requests allowed, default value is 0
     */
    int actives() default -1;
 
    /**
     * Whether the async request has already been sent, the default value is false
     */
    boolean sent() default false;
 
    /**
     * Whether to use JSR303 validation, legal values are: true, false
     */
    String validation() default "";
 
    /**
     * Timeout value for service invocation, default value is 0
     */
    int timeout() default -1;
 
    /**
     * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache
     */
    String cache() default "";
 
    /**
     * Filters for service invocation
     * <p>
     * see Filter
     */
    String[] filter() default {};
 
    /**
     * Listeners for service exporting and unexporting
     * <p>
     * see ExporterListener
     */
    String[] listener() default {};
 
    /**
     * Application name
     * @deprecated This attribute was deprecated, use bind application/module of spring ApplicationContext
     */
    @Deprecated
    String application() default "";
 
    /**
     * Module associated name
     */
    String module() default "";
 
    /**
     * Consumer associated name
     */
    String consumer() default "";
 
    /**
     * Monitor associated name
     */
    String monitor() default "";
 
    /**
     * Registry associated name
     */
    String[] registry() default {};
 
    /**
     * The communication protocol of Dubbo Service
     *
     * @return the default value is ""
     * @since 2.6.6
     */
    String protocol() default "";
 
    /**
     * Service tag name
     */
    String tag() default "";
 
    /**
     * methods support
     */
    Method[] methods() default {};
 
    /**
     * The id
     * NOTE: The id attribute is ignored when using @DubboReference on @Bean method
     * @return default value is empty
     * @since 2.7.3
     */
    String id() default "";
 
    /**
     * @return The service names that the Dubbo interface subscribed
     * @see RegistryConstants#SUBSCRIBED_SERVICE_NAMES_KEY
     * @since 2.7.8
     * @deprecated using {@link DubboReference#providedBy()}
     */
    @Deprecated
    String[] services() default {};
 
    /**
     * declares which app or service this interface belongs to
     * @see RegistryConstants#PROVIDED_BY
     */
    String[] providedBy() default {};
 
    /**
     * the scope for referring/exporting a service, if it's local, it means searching in current JVM only.
     * @see org.apache.dubbo.rpc.Constants#SCOPE_LOCAL
     * @see org.apache.dubbo.rpc.Constants#SCOPE_REMOTE
     */
    String scope() default "";
 
    /**
     * Weather the reference is refer asynchronously
     */
    boolean referAsync() default false;
}

          

@Method:标注在注解上,设置方法级别的服务调用

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})   //标注在注解上
@Inherited
public @interface Method {
    String name();
 
    int timeout() default -1;
    int retries() default -1;
 
    String merger() default "";
    String loadbalance() default "";
 
    boolean async() default false;
 
    boolean sent() default true;
 
    int actives() default -1;
    int executes() default -1;
 
    boolean deprecated() default false;
    boolean sticky() default false;
    boolean isReturn() default true;
 
    String oninvoke() default "";
    String onreturn() default "";
    String onthrow() default "";
 
    String cache() default "";
 
    String validation() default "";
 
    Argument[] arguments() default {};
 
    /**
     * Customized parameter key-value pair, for example: {key1, value1, key2, value2} or {"key1=value1", "key2=value2"}
     */
    String[] parameters() default {};
 
}

              

ClusterRules

public interface ClusterRules {

    /**
     *  When invoke fails, log the initial error and retry other invokers
     *  (retry n times, which means at most n different invokers will be invoked)
     **/
    String FAIL_OVER = "failover";

    /**
     *  Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error.
     **/
    String FAIL_FAST = "failfast";

    /**
     *  When invoke fails, log the error message and ignore this error by returning an empty Result.
     **/
    String FAIL_SAFE = "failsafe";

    /**
     *  When fails, record failure requests and schedule for retry on a regular interval.
     **/
    String FAIL_BACK = "failback";

    /**
     *  Invoke a specific number of invokers concurrently, usually used for demanding real-time operations, but need to waste more service resources.
     **/
    String FORKING = "forking";

    /**
     *  Call all providers by broadcast, call them one by one, and report an error if any one reports an error
     **/
    String BROADCAST = "broadcast";

    String AVAILABLE = "available";
    String MERGEABLE = "mergeable";

    String EMPTY = "";

}

               

HelloController

@RestController
public class HelloController {

    @DubboReference(cluster = ClusterRules.FORKING, parameters = {"forks","3"})
    private HelloService helloService;

    @DubboReference
    private HelloService2 helloService2;

    @RequestMapping("/hello")
    public String hello(){
        System.out.println(helloService.hello());
        System.out.println(helloService2.hello2());

        return "hello consumer 2";
    }
}

                 

                     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值