Dubbo服务化最佳实践和Dubbo协议

1 Dubbo服务化最佳实践

1. 分包

建议将服务接口,服务模型,服务异常等均放在API包中,因为服务模型及异常也是API的一部分,
同时,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)
如果需要,也可以考虑在API包中放置一份spring的引用配置,这样使用方,只需在Spring加载过程中引用此配置即可,
配置建议放在模块的包目录下,以免冲突,如:com/alibaba/china/xxx/dubbo-reference.xml

2. 粒度

服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo暂未提供分布式事务支持。

3. 划分

服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸 不建议使用过于抽象的通用接口,如:Map
query(Map),这样的接口没有明确语义,会给后期维护带来不便。

4. 版本化

每个接口都应定义版本号,为后续不兼容升级提供可能,如:<dubbo:service
interface=”com.xxx.XxxService” version=”1.0″ />
建议使用两位版本号,因为第三位版本号通常表示兼容升级,只有不兼容时才需要变更服务版本。
当不兼容时,先升级一半提供者为新版本,再将消费者全部升为新版本,然后将剩下的一半提供者升为新版本。

5. 兼容性

服务接口增加方法,或服务模型增加字段,可向后兼容,删除方法或删除字段,将不兼容,枚举类型新增字段也不兼容,需通过变更版本号升级。
各协议的兼容性不同,参见:服务协议

6. 序列化

服务参数及返回值建议使用POJO对象,即通过set,get方法表示属性的对象。
服务参数及返回值不建议使用接口,因为数据模型抽象的意义不大,并且序列化需要接口实现类的元信息,并不能起到隐藏实现的意图。
服务参数及返回值都必需是byValue的,而不能是byRef的,消费方和提供方的参数或返回值引用并不是同一个,只是值相同,Dubbo不支持引用远程对象。

7. 异常

建议使用异常汇报错误,而不是返回错误码,异常信息能携带更多信息,以及语义更友好,
如果担心性能问题,在必要时,可以通过override掉异常类的fillInStackTrace()方法为空方法,使其不拷贝栈信息,
查询方法不建议抛出checked异常,否则调用方在查询时将过多的try…catch,并且不能进行有效处理,
服务提供方不应将DAO或SQL等异常抛给消费方,应在服务实现中对消费方不关心的异常进行包装,否则可能出现消费方无法反序列化相应异常。

2 Dubbo协议参考手册

1. Dubbo协议

缺省协议,使用基于mina1.1.7+hessian3.2.1的tbremoting交互。
连接个数:单连接
连接方式:长连接
传输协议:TCP
传输方式:NIO异步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用
为什么要消费者比提供者个数多:
因dubbo协议采用单一长连接,
假设网络为千兆网卡(1024Mbit=128MByte),
根据测试经验数据每条连接最多只能压满7MByte(不同的环境可能不一样,供参考),
理论上1个服务提供者需要20个服务消费者才能压满网卡。
为什么不能传大包:
因dubbo协议采用单一长连接,
如果每次请求的数据包大小为500KByte,假设网络为千兆网卡(1024Mbit=128MByte),每条连接最大7MByte(不同的环境可能不一样,供参考),
单个服务提供者的TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。
单个消费者调用单个服务提供者的TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14。
如果能接受,可以考虑使用,否则网络将成为瓶颈。
为什么采用异步单一长连接:
因为服务的现状大都是服务提供者少,通常只有几台机器,
而服务的消费者多,可能整个网站都在访问该服务,
比如Morgan的提供者只有6台提供者,却有上百台消费者,每天有1.5亿次调用,
如果采用常规的hessian服务,服务提供者很容易就被压跨,
通过单一连接,保证单一消费者不会压死提供者,
长连接,减少连接握手验证等,
并使用异步IO,复用线程池,防止C10K问题。
(1) 约束:
参数及返回值需实现Serializable接口
参数及返回值不能自定义实现List, Map, Number, Date, Calendar等接口,只能用JDK自带的实现,因为hessian会做特殊处理,自定义实现类中的属性值都会丢失。()
Hessian序列化,只传成员属性值和值的类型,不传方法或静态变量,兼容情况:(由吴亚军提供)
数据通讯 情况 结果
A->B 类A多一种 属性(或者说类B少一种 属性) 不抛异常,A多的那 个属性的值,B没有, 其他正常
A->B 枚举A多一种 枚举(或者说B少一种 枚举),A使用多 出来的枚举进行传输 抛异常
A->B 枚举A多一种 枚举(或者说B少一种 枚举),A不使用 多出来的枚举进行传输 不抛异常,B正常接 收数据
A->B A和B的属性 名相同,但类型不相同 抛异常
A->B serialId 不相同 正常传输
总结:会抛异常的情况:枚 举值一边多一种,一边少一种,正好使用了差别的那种,或者属性名相同,类型不同
接口增加方法,对客户端无影响,如果该方法不是客户端需要的,客户端不需要重新部署;
输入参数和结果集中增加属性,对客户端无影响,如果客户端并不需要新属性,不用重新
部署;
输入参数和结果集属性名变化,对客户端序列化无影响,但是如果客户端不重新部署,不管输入还是输出,属性名变化的属性值是获取不到的。
总结:服务器端和客户端对领域对象并不需要完全一致,而是按照最大匹配原则。
(2) 配置:
dubbo.properties:
dubbo.service.protocol=dubbo

2. RMI协议

Java标准的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:TCP
传输方式:同步传输
序列化:Java标准二进制序列化
适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。
适用场景:常规远程服务方法调用,与原生RMI服务互操作
(1) 约束:
参数及返回值需实现Serializable接口
dubbo配置中的超时时间对rmi无效,需使用java启动参数设置:-Dsun.rmi.transport.tcp.responseTimeout=3000,参见下面的RMI配置。
(2) 配置:
dubbo.properties:
dubbo.service.protocol=rmi
(3) RMI配置:
java -Dsun.rmi.transport.tcp.responseTimeout=3000
更多RMI优化参数请查看:
http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html

3. Hessian协议

基于Hessian的远程调用协议。 连接个数:多连接 连接方式:短连接 传输协议:HTTP 传输方式:同步传输
序列化:Hessian二进制序列化 适用范围:传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件。
适用场景:页面传输,文件传输,或与原生hessian服务互操作 (1) 约束: 参数及返回值需实现Serializable接口
参数及返回值不能自定义实现List, Map, Number, Date,
Calendar等接口,只能用JDK自带的实现,因为hessian会做特殊处理,自定义实现类中的属性值都会丢失。 (2) 配置:

dubbo.properties:
dubbo.service.protocol=hessian
web.xml:
<servlet>
         <servlet-name>serviceDispatcherServlet</servlet-name>
         <servlet-class>com.alibaba.dubbo.rpc.http.ServiceDispatcherServlet</servlet-class>
         <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
         <servlet-name>serviceDispatcherServlet</servlet-name>
         <url-pattern>/*</url-pattern>
</servlet-mapping>

注意: dubbo.service.server.port必须与servlet容器的端口相同,
dubbo.service.protocol.http.context.path必须与servlet应用的上下文路径相同,如果是根目录,可不配。

4. HTTP协议

基于http表单的远程调用协议。参见:HTTP协议使用说明 连接个数:多连接 连接方式:短连接 传输协议:HTTP 传输方式:同步传输
序列化:表单序列化 适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。 (1) 约束: 参数及返回值需符合Bean规范 (2) 配置:

dubbo.properties:
dubbo.service.protocol=http
dubbo.service.protocol.http.format=json
web.xml:
<servlet>
         <servlet-name>serviceDispatcherServlet</servlet-name>
         <servlet-class>com.alibaba.dubbo.rpc.http.ServiceDispatcherServlet</servlet-class>
         <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
         <servlet-name>serviceDispatcherServlet</servlet-name>
         <url-pattern>/*</url-pattern>
</servlet-mapping>

注意: dubbo.service.server.port必须与servlet容器的端口相同,
dubbo.service.protocol.http.context.path必须与servlet应用的上下文路径相同。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值