启动服务方法
如果提供方没有启动的时候、默认会去检测所依赖的服务是否正常提供服务
如果check为false,表示启动的时候不去检查,当服务循环依赖的时候,check设置为false
dubbo:referene 属性check 默认为true
dubbo:consumer check= false 没有服务提供方的时候、报错
dubbo:registry check=false 注册订阅失败报错
多协议支持
dubbo协议
- 缺省协议
- 链接个数:单链接
- 连接方式:长连接
- 传输方式:NIO异步传输
- 序列化:Hession二进制序列化
- 适用范围:传入传出参数数据包小(建议小于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问题。
接口增加方法,对客户端无影响,如果该方法不是客户端需要的,客户端不需要重新部署;
输入参数和结果集中增加属性,对客户端无影响,如果客户端并不需要新属性,不用重新
部署;
输入参数和结果集属性名变化,对客户端序列化无影响,但是如果客户端不重新部署,不管输入还是输出,属性名变化的属性值是获取不到的。
总结:服务器端和客户端对领域对象并不需要完全一致,而是按照最大匹配原则。
rmi协议
- 连接个数:多连接
- 连接方式:短连接
- 传输协议:TCP
- 传输方式:同步传输
- 序列化:Java标准二进制序列化
- 适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件
- 适用场景:常规远程服务方法调用,与原生RMI服务互操作
hessian协议
- 连接个数:多连接
- 连接方式:短连接
- 传输协议:Http
- 传输方式:同步传输
- 序列化:表单序列化
- 适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
- 适用场景:需同时给应用程序和浏览器JS使用的服务
Http协议
- 连接个数:多连接
- 连接方式:短连接
- 传输协议:Http
- 传输方式:同步传输
- 序列化:表单序列化
- 适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
- 适用场景:需同时给应用程序和浏览器JS使用的服务
webService协议
- 连接个数:多连接
- 连接方式:短连接
- 传输协议:Http
- 传输方式:同步传输
- 序列化:SOAP文本序列化
- 系统集成,跨语言调用
thrift协议
memcached协议
redis协议
集群容错
failOver:失败自动切换并重试其他服务器,通过retries=2,来设置重试机制
failfast:快速失败,只发起一次调用;写操作。比如增加记录的时候、非幂等请求
failsafe:失败安全,出现异常直接忽略
failback:失败自动恢复,后台记录请求,定时重发
forking:并行调用多个服务器,只要一个调用成功立即返回。只能应用在读的请求
broadcast:广播调用所有提供者,一台报错就抛出异常
配置优先级
reference method->service methond->reference->service->consumer->provider
服务的最佳实践
分包
- 服务接口、请求服务模型、异常信息都放在api里面,符合重用发布等价原则,共同重用
- api里面放入spring的引用配置,也可以放在模块的包目录下
粒度
- 尽可能把接口设置成粗粒度,每个服务方法代表一个独立功能,而不是某个功能的步骤,否则会涉及分布式事务
- 服务接口建议以业务场景为单位划分。并对相近业务做抽象,防止接口暴增
- 不建议使用抽象通用接口T,接口没有明确语义,带来后期维护
版本
- 每个接口都应该定义版本、为后续的兼容性提供前瞻性的考虑 version
- 建议使用二位版本号,因为第三位版本号表示兼容性升级,只有不兼容时才需要变更服务版本
- 当接口做到不兼容升级的时候,先升级一半或者一台提供者为新版本
推荐用法
- 在provider端尽可能配置consumer端属性,比如timeout、retries、线程池大小、LoadBlance
- 配置缓存 注册列表,服务提供者列表
源码分析
ExtensionLoader
invoker