您的位置:首页 > 其它

Dubbo学习:服务降级

2017-08-29 00:00 309 查看

Dubbo学习(十三):服务降级

2016-04-2616:454345人阅读评论(1)收藏举报


分类:

Dubbo(13)


版权声明:本文为博主原创文章,未经博主允许不得转载。

一、dubbo降级服务

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

经过过12306抢票的人应该经常会遇到这个问题:在抢票高峰的时候,明明票还有,但是查询出来的列表却是为空的(如果没票列表也应该会呈现);等高峰过后再查询,列表又恢复正常。个人猜测应该是查询过程中出现了问题,要么超时,要么网络问题导致查询失败采用的服务降级处理。所以,最终呈现给用户的并不是内部系统出错之类的提示,而是一个空的列表。好了,言归正传,在dubbo中想实现服务降级,需要怎么样做可以实现?

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

二、结合dubbo的例子

说明下面将通过一个例子进行说明:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**接口定义*/
publicinterfaceIUser{

publicvoidaddUser(Useru);

publicUsergetUserById(intid);

}

/**实现类*/
publicclassUserImplimplementsIUser{

privatestaticList<User>USER_LIST=newArrayList<User>();

static{
for(inti=0;i<10;i++){
Useru=newUser();
u.setAddress("address"+i);
u.setId(i);
u.setName("name"+i);

USER_LIST.add(u);
}
}

publicvoidaddUser(Useru){
USER_LIST.add(u);
System.out.println("total:"+USER_LIST.size());
}

publicUsergetUserById(intid){
for(inti=0;i<USER_LIST.size();i++){
if(USER_LIST.get(i).getId()==id){
returnUSER_LIST.get(i);
}
}
returnnull;
}
}
dubbo-provider.xml配置:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbo>'target='_blank'>http://code.alibabatech.com/schema/dubbo/dubbo.xsd"[/code]>
<!--提供方应用信息,用于计算依赖关系-->
<dubbo:applicationname="hello-world-app"/>

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

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

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

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

</beans>
调用方的配置:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbo>'target='_blank'>http://code.alibabatech.com/schema/dubbo/dubbo.xsd"[/code]>
<!--消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样-->
<dubbo:applicationname="dubbo-consumer"/>

<dubbo:registryaddress="zookeeper://127.0.0.1:2181"/>

<!--生成远程服务代理,可以和本地bean一样使用demoService-->
<dubbo:referenceid="iUser"interface="com.zzq.test.iface.IUser"timeout="10000"check="false"mock="returnnull">
</dubbo:reference>

</beans>
调用的测试代码:

?

1
2
3
4
5
6
7
8
9
10
11
12
publicstaticvoidmain(String[]args)throwsException{
ClassPathXmlApplicationContextcontext=newClassPathXmlApplicationContext(newString[]{"classpath:dubbo-consumer.xml"});
context.start();

IUseriUser=(IUser)context.getBean("iUser");
Useru=newUser();
u.setAddress("aaa");
u.setId(311);
u.setName("n3");
iUser.addUser(u);
System.out.println(iUser.getUserById(1));
}
通过测试,如果服务启动,则程序按照预期的运行正常;如果服务没启动,则此时运行程序,程序并未报错,打印出null。

三、思考

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

(1)将接口进行归类,查询类和变更操作类:对于查询的分为一个接口类,变更的归类为其他的接口类,这样对于查询的可以使用mock="returnnull"进行降级操作;对于变更类的,可以仍旧使用try……catch进行异常捕获处理;

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

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

?

1
2
3
4
5
6
7
8
9
10
11
12
13
publicclassIUserMockimplementsIUser{

@Override
publicvoidaddUser(Useru){
thrownewRuntimeException("adduserfail!");
}

@Override
publicUsergetUserById(intid){
returnnull;
}

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Dubbo