2016-04-26 16:45 4345人阅读 评论(1) 收藏 举报spring
分类:网络
Dubbo(13)
并发
版权声明:本文为博主原创文章,未经博主容许不得转载。app
1、dubbo降级服务 ide
dubbo开发中,可能因为服务没有启动或者网络不通,调用中会出现RpcException,也就是远程调用失败。若是是服务启动顺序的问题,可能加工check="false"的配置能够获得很好的解决。可是,若是是服务宕掉或者并发数过高致使的RpcException该如何处理?学习
通过过12306抢票的人应该常常会遇到这个问题:在抢票高峰的时候,明明票还有,可是查询出来的列表倒是为空的(若是没票列表也应该会呈现);等高峰事后再查询,列表又恢复正常。我的猜想应该是查询过程当中出现了问题,要么超时,要么网络问题致使查询失败采用的服务降级处理。因此,最终呈现给用户的并非内部系统出错之类的提示,而是一个空的列表。好了,言归正传,在dubbo中想实现服务降级,须要怎么样作能够实现?测试
查看dubbo的官方文档,能够发现有个mock的配置,mock只在出现非业务异常(好比超时,网络异常等)时执行。mock的配置支持两种,一种为boolean值,默认的为false。若是配置为true,则缺省使用mock类名,即类名+Mock后缀;另一种则是配置"return null",能够很简单的忽略掉异常。spa
2、结合dubbo的例子.net
说明下面将经过一个例子进行说明:代理
?
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 |
/**接口定义*/ 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配置:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<? 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 > |
调用方的配置:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<? 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 > |
调用的测试代码:
?
1 2 3 4 5 6 7 8 9 10 11 12 |
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。
3、思考
经过以上的例子能够知道,经过mock的配置,能够很好的实现dubbo服务降级。可是,仔细查看上面的例子会发现,IUser自己定义了两个接口,一个是新增用户,一个是根据id查询用户信息。对于根据id查询用户信息,在调用失败的时候返回null很好理解,多是因为验证失败或者记录删除了,可是对于新增用户,可能就须要抛出具体的业务信息,不然程序没法处理后续的业务,包括页面弹出”添加成功“或者列表刷新的时候没法查看到最新的记录,这样体验将会很是很差。因此,若是要有较好的区分,能够经过如下的方式,能够更好的实现降级:
(1)将接口进行归类,查询类和变动操做类:对于查询的分为一个接口类,变动的归类为其余的接口类,这样对于查询的可使用mock="return null"进行降级操做;对于变动类的,能够仍旧使用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 |
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 ; } } |