欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

4、Dubbo消费端服务mock&降级策略原理

程序员文章站 2022-04-05 23:37:00
...

当我们聊服务消费端降级的时候时候,应该考虑哪些问题?

  • dubbo如何设置服务消费的降级策略?用到了那个类(保存到zookeeper的configurator节点下)?
  • dubbo的服务降级策略有哪些?
  • 如何使用dubbo的服务降级策略?

降级策略注册

当服务因为超时等某些原因不可用的时候,我们需要无服务设置降级策略;手动编写伪代码将服务降级信息注册到zookeeper;也可以通过配置mock参数的形式指定某个消费服务的mock策略,返回指定字符串,或者自定义mock处理类;

1、手动伪代码将服务降级注册到zk

/**
 * 注册服务降级策略到注册中心
 * @Param type 降级策略类型
 */
public static void mockResult(String type){
    RegistryFactory registryFactory =     ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
    Registry registry =    registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
    registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
}

2、配置mock参数指定返回字符串

<dubbo:reference id="xxService" check="false" interface="com.xx.XxService" timeout="3000" mock="return null" />

<dubbo:reference id="xxService2" check="false" interface="com.xx.XxService2" timeout="3000" mock="return 1234" />

timeout:超过该时间返回null 或者1234。
配置后启动即可,我们在服务提供者例 如 UserServiceImpl 中的 getUser 方法打个断点来模拟请求超时。

然后浏览器访问,断点不过,一致等待,当时间超过3秒,直接返回了空;ok! 这样我们就已经实现了一个简单的服务降级了 。

3、自定义服务降级方法实现类

<dubbo:reference id="xxService" check="false" interface="com.xx.XxService" timeout="3000" mock="true"/>

配置dubbo服务消费引用标签的mock参数值为true,同时定义服务名+Mock 的自定义类;这样在服务接口超时时,就会返回自定义的相应信息;

public class UserServiceMock implements UserService{
 
	public List<Article>getUserArticles(int uid){
		return null;
		
	}
	public List<User>getUser(String name){
		//throw new RuntimeException("服务降级-----");
		User user = new User();
		user.setUserName("服务降级啦");
		user.setUserAge("500");
		List<User> list = new ArrayList<User>();
		list.add(user);
		return list;
		
	}
}

4、通过admin管理平台手动配置服务降级策略

4、Dubbo消费端服务mock&降级策略原理

 

不论使用何种方式,最终降级策略会被注册到zk上的configurators节点下(假设使用zk注册中心),

4、Dubbo消费端服务mock&降级策略原理

  • mock值默认false:直接发起远程调用,无降级
  • mock值设置为force: 不发起远程调用,直接返回降级策略
  • mock值设置为fail: 发起远程调用,失败时return降级策略

服务消费端使用降级策略

服务消费端在MockClusterInvoker类的invoke()方法里使用降级策略并在DubboInvoker的invoke()方法里发起远程调用,所以服务降级是在消费端还没有发起远程调用时完成。

1、MockClusterInvoker代码

    @Override
    public Result invoke(Invocation invocation) throws RpcException {
        Result result;
        // 获得 "mock" 配置项,有多种配置方式
        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
        //【第一种】无 mock
        if (value.length() == 0 || value.equalsIgnoreCase("false")) {
            // no mock
            // 调用原 Invoker ,发起 RPC 调用
            result = this.invoker.invoke(invocation);
        //【第二种】强制服务降级 https://dubbo.gitbooks.io/dubbo-user-book/demos/service-downgrade.html
        } else if (value.startsWith("force")) {
            if (logger.isWarnEnabled()) {
                logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
            }
            // force:direct mock
            // 直接调用 Mock Invoker ,执行本地 Mock 逻辑
            result = doMockInvoke(invocation, null);
        // 【第三种】失败服务降级 https://dubbo.gitbooks.io/dubbo-user-book/demos/service-downgrade.html
        } else {
            // fail-mock
            try {
                // 调用原 Invoker ,发起 RPC 调用
                result = this.invoker.invoke(invocation);
            } catch (RpcException e) {
                // 业务性异常,直接抛出
                if (e.isBiz()) {
                    throw e;
                } else {
                    if (logger.isWarnEnabled()) {
                        logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                    }
                    // 失败后,调用 Mock Invoker ,执行本地 Mock 逻辑
                    result = doMockInvoke(invocation, e);
                }
            }
        }
        return result;
    }

directory.getUrl获取服务提供者的动态配置信息,含降级mock参数信息;之后判断三种mock值,决定是否执行降级策略;这里关注如果mock值为fail,如果远程调用失败,则返回降级策略,乳沟成功则代码会调用FailoverClusterInvokerd的doInvoke()方法发起远程调用;