关于dubbo的服务降级

1、dubbo降级服务    spring

    dubbo开发中,可能因为服务没有启动或者网络不通,调用中会出现RpcException,也就是远程调用失败。若是是服务启动顺序的问题,可能加工check="false"的配置能够获得很好的解决。可是,若是是服务宕掉或者并发数过高致使的RpcException该如何处理?网络

    通过过12306抢票的人应该常常会遇到这个问题:在抢票高峰的时候,明明票还有,可是查询出来的列表倒是为空的(若是没票列表也应该会呈现);等高峰事后再查询,列表又恢复正常。我的猜想应该是查询过程当中出现了问题,要么超时,要么网络问题致使查询失败采用的服务降级处理。因此,最终呈现给用户的并非内部系统出错之类的提示,而是一个空的列表。好了,言归正传,在dubbo中想实现服务降级,须要怎么样作能够实现?并发

    查看dubbo的官方文档,能够发现有个mock的配置,mock只在出现非业务异常(好比超时,网络异常等)时执行。mock的配置支持两种,一种为boolean值,默认的为false。若是配置为true,则缺省使用mock类名,即类名+Mock后缀;另一种则是配置"return null",能够很简单的忽略掉异常。app

2、结合dubbo的例子ide

说明下面将经过一个例子进行说明:测试

/**接口定义*/
public interface IUser {
 
    public void addUser(User u);
     
    public User getUserById(int id);
     
}
 
/**实现类*/
public class UserImpl implements IUser {
     
    private static List<User> USER_LIST = new ArrayList<User>();
     
    static{
        for(int i=0;i<10;i++){
            User u = new User();
            u.setAddress("address"+i);
            u.setId(i);
            u.setName("name"+i);
             
            USER_LIST.add(u);
        }
    }
     
    public void addUser(User u) {
        USER_LIST.add(u);
        System.out.println("total:"+USER_LIST.size());
    }
 
    public User getUserById(int id) {
        for(int i=0;i<USER_LIST.size();i++){
            if(USER_LIST.get(i).getId() == id){
                return USER_LIST.get(i);
            }
        }
        return null;
    }
}

 

dubbo-provider.xml配置:spa

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

	<!-- 提供方应用信息,用于计算依赖关系 -->
	<dubbo:application name="hello-world-app" />

	<!-- 使用multicast广播注册中心暴露服务地址 -->
	<dubbo:registry address="zookeeper://127.0.0.1:2181" />

	<!-- 用dubbo协议在20880端口暴露服务 -->
	<dubbo:protocol name="dubbo" port="20880" />

	<!-- 声明须要暴露的服务接口 -->
	<dubbo:service interface="com.zzq.test.iface.IUser" ref="userImpl" timeout="10000" />

	<!-- 和本地bean同样实现服务 -->
	<bean id="userImpl" class="com.zzq.test.ifaceimpl.UserImpl" />

</beans>

调用方的配置:代理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 
    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方同样 -->
    <dubbo:application name="dubbo-consumer"  />
 
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />
 
    <!-- 生成远程服务代理,能够和本地bean同样使用demoService -->
    <dubbo:reference id="iUser" interface="com.zzq.test.iface.IUser"  timeout="10000" check="false" mock="return null">
    </dubbo:reference>
 
</beans>

调用的测试代码:code

public static void main(String[] args) throws Exception{
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"classpath:dubbo-consumer.xml"});
	    context.start();
	    
	    IUser iUser = (IUser)context.getBean("iUser");
	    User u = new User();
	    u.setAddress("aaa");
	    u.setId(311);
	    u.setName("n3");
	    iUser.addUser(u);
	    System.out.println(iUser.getUserById(1));
	}

经过测试,若是服务启动,则程序按照预期的运行正常;若是服务没启动,则此时运行程序,程序并未报错,打印出null。xml

3、思考

    经过以上的例子能够知道,经过mock的配置,能够很好的实现dubbo服务降级。可是,仔细查看上面的例子会发现,IUser自己定义了两个接口,一个是新增用户,一个是根据id查询用户信息。对于根据id查询用户信息,在调用失败的时候返回null很好理解,多是因为验证失败或者记录删除了,可是对于新增用户,可能就须要抛出具体的业务信息,不然程序没法处理后续的业务,包括页面弹出”添加成功“或者列表刷新的时候没法查看到最新的记录,这样体验将会很是很差。因此,若是要有较好的区分,能够经过如下的方式,能够更好的实现降级:

(1)将接口进行归类,查询类和变动操做类:对于查询的分为一个接口类,变动的归类为其余的接口类,这样对于查询的可使用mock="return null"进行降级操做;对于变动类的,能够仍旧使用try……catch进行异常捕获处理;

(2)配置mock="true",同时mock实现接口,接口名要注意命名规范:接口名+Mock后缀。此时若是调用失败会调用Mock实现。mock实现须要保证有无参的构造方法。

配置mock="true"的状况,对于上面的例子即在IUser的同个路径下,添加类IUserMock,实现以下:

public class IUserMock implements IUser {

	@Override
	public void addUser(User u) {
		throw new RuntimeException("add user fail!");
	}

	@Override
	public User getUserById(int id) {
		return null;
	}

}
相关文章
相关标签/搜索