源码github
功能特性
- 实现rpc调用,像调用本地方法一样调用远程server上的方法
- 支持多协议:(默认Dubbo协议)用户可以根据业务场景选择合适的协议
- 解耦:利用注册中心,实现服务提供者和消费者之间解耦,也实现服务提供者和提供者之间的解耦,实现灵活的扩展和缩容。
- 负载均衡:4种策略配合权重,而且支持代码配置和Dubbo控制台动态配置
- 高可用: 利用注册中心发现功能,一个provider挂了的话,会自动被剔除掉,保证服务器继续对外提供服务,如果重新provider重新恢复的话,又恢复到服务提供队列当中了
- 重试容错: 支持failover、failfast、forking等多种容错机制
- 并发控制:服务端(executors)和消费端(actives)都支持不同形式的并发控制
- 缓存:消费端支持配置3种策略的结果缓存(但是需要自己实现缓存结果超时的配置)
- 支持两种调用方式:同步(默认)和异步(返回Future对象)两种调用方式
- 支持权限配置功能:比如白名单功能
Dubbo 原理浅析(基于Dubbo协议)
- 每个Provider就是一个Nio的Server,内部机制由Netty实现(也可以是Mina等),两个线程组工作。Provider启动的时候,结合注册中心,暴露对外服务。
- Consumer的一个线程发起请求,会获取一个全局的线程ID,然后会把该请求的接口名称、方法名称、参数值等信息封装成一个object的对象
- 把 ID,请求Object放在全局的ConcurrentHashMap里面,发起异步的调用,自身用object为锁对象,wait请求线程进入阻塞状态
- 调用成功后,触发客户端的监听,然后根据全局ConcurrentHashMap中ID找到object,设置好返回值和回调方法的时候,notifyAll调用的阻塞线程,完成调用
Dubbo配置
配置规则(timeout 、 retries, loadbalance, actives )
- 方法级优先,接口级次之,全局配置再次之
- 如果级别一样,则消费方优先,提供方次之,其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
- 在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值。否则,Consumer会使用Consumer端的全局设置,这对于Provider不可控的,并且往往是不合理的
默认配置
- 默认集群容错方案: failover,超时失败就切换到Provider的其它Node
- 默认负载均衡方案:random
- 默认调用超时重试的时间: 1s,未响应就重试
- 默认重试的次数: retries=2
- 默认Dubbo服务接口: port="20880"
其它高级特性
Dubbo 结果缓存(支持3种策略:LRU、FIFO、LFU)
Dubbo的缓存是在服务消费者调用端进行配置的,因为只有业务端才知道自己业务,然后配置相应的策略
配置在消费者上面
<dubbo:reference id="demoService" interface="com.mor.server.dubbo.service.DemoServer" cache="lru" />
白名单功能
- maven项目需要在resources 下创建 META-INF\dubbocom.alibaba.dubbo.rpc.Filter文件
- 配置
dubboContextFilter=com.mor.server.dubbo.service.AuthorityFilter
- 重写Filter方法
注意事项
- 调用参数、返回值都要实现序列号接口,因为交互时需要序列化
public class ProductType implements Serializable{
private static final long serialVersionUID = -5661679310882808443L;
- 前后端的Bean和接口名字要一致,不然报错找不到
provider.xml
第一个要配置的接口,但是ref要配置的是实际的实现类才行
<dubbo:service interface="com.mor.server.dubbo.service.DemoServer" ref="demoService" />
- 实际上RPC在Consumer端也可以没有Provider的jar包,只需要在本地实现包名一样的接口,也一样
异步调用
- 同步调用:看起来是一种阻塞式的调用方式,即 Consumer 端代码一直阻塞等待,直到 Provider 端返回为止。实际上底层 IO 操作都是异步的。Consumer 端发起调用后,得到一个 Future 对象。对于同步调用,业务线程通过Future#get(timeout),阻塞等待 Provider 端将结果返回;timeout则是 Consumer 端定义的超时时间
- 异步将来式:future.get(timeout)直接将来式获取结果
- 异步回调式:基于Callback 机制