1.启动服务检查
2.多协议支持
3.多注册中心支持
4.多版本支持
5.异步调用
6.主机绑定
7.dubbo服务只订阅与只注册
8.负载均衡
9.连接超时timeout
10.集群容错
11.配置的优先级
12.服务的最佳实践
13.推荐用法
14.配置dubbo缓存文件
1.启动服务检查
如果提供方没有启动的时候,默认会去检测所依赖的服务是否正常提供服务
如果check为false,表示启动的时候不去检查。
dubbo:reference check=”false” 当服务出现循环依赖的时候,check设置成false
dubbo:consumer check=”false” 没有服务提供者的时候,报错
dubbo:registry check=”false” 注册订阅失败报错
dubbo:provider check=”false”
2.多协议支持
dubbo支持的协议: dubbo、RMI、hessian、webservice、http、Thrift
1)pom
<!-- hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.26</version>
</dependency>
2)服务提供者
<dubbo:protocol name="hessian" port="8090" server="jetty"/>
3)服务消费者
<dubbo:reference id="orderServices" interface="com.charjay.order.IOrderServices" protocol="hessian" />
4)注册接口
hessian://xxxxx:8090/com.charjay.order.IOrderServices
3.多注册中心支持
使用场景比较少
1)注册中心配置
<dubbo:registry id="zkOne" protocol="zookeeper" address="192.168.98.165:2181,192.168.98.166:2181,192.168.98.167:2181"/>
<dubbo:registry id="zkTwo" protocol="zookeeper" address="192.168.98.169:2181"/>
2)服务选择配置中心
<dubbo:service interface="com.charjay.order.IOrderServices" ref="orderService" protocol="hessian" registry="zkTwo"/>
4.多版本支持
1)服务提供者
<dubbo:service interface="com.charjay.order.IOrderServices" ref="orderService" version="1.0"/>
<dubbo:service interface="com.charjay.order.IOrderServices" ref="orderService2" version="2.0"/>
2)消费者
<dubbo:reference id="orderServices" interface="com.charjay.order.IOrderServices" version="2.0"/>
服务注册的时候会把version也注册到zookeeper,两个version两个url
5.异步调用
1)异步调用原理图
2)async="true"
配置<dubbo:service interface="com.charjay.order.IOrderServices" ref="orderService2" async="true"/>
代码异步获取 RpcContext.getContext().getFuture()
hessian协议,使用async异步回调会报错,只有dubbo支持
6.主机绑定
provider注册到zookeeper的ip地址是怎么来的?
1.通过<dubbo:protocol host="192.168.1.1" />t配置的地址去找(使用场景是当dubbo获取到的地址有问题的时候)
2.获取方式2:host = InetAddress.getLocalHost().getHostAddress();
3.获取方式3:通过socket发起连接连接到注册中心的地址。再获取连接过去以后本地的ip地址
4.获取方式4:host = NetUtils.getLocalHost();
if (NetUtils.isInvalidLocalHost(host)) {
anyhost = true;
try {
host = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
logger.warn(e.getMessage(), e);
}
if (NetUtils.isInvalidLocalHost(host)) {
if (registryURLs != null && registryURLs.size() > 0) {
for (URL registryURL : registryURLs) {
try {
Socket socket = new Socket();
try {
SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
socket.connect(addr, 1000);
host = socket.getLocalAddress().getHostAddress();
break;
} finally {
try {
socket.close();
} catch (Throwable e) {}
}
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
}
}
if (NetUtils.isInvalidLocalHost(host)) {
host = NetUtils.getLocalHost();
}
}
7.dubbo服务只订阅与只注册
1)只订阅
使用场景:我们在本地笔记本开发的时候,不能把自己笔记本的服务注册到开发环境,但是可以使用注册中心的服务
服务提供者配置 register="false"
<dubbo:registry protocol="zookeeper" address="192.168.98.165:2181,192.168.98.166:2181,192.168.98.167:2181" register="false"/>
1)只注册
如果有两个镜像环境,两个注册中心,有一个服务只在其中一个注册中心有部署,另一个注册中心还没来得及部署,而两个注册中心的其它应用都需要依赖此服务。
这个时候,可以让服务提供者方只注册服务到另一注册中心,而不从另一注册中心订阅服务。
就是说这个服务只能在一台服务器上订阅,其他服务器都不能订阅当消费者?
服务提供者配置 subscribe="false"
<dubbo:registry protocol="zookeeper" address="192.168.98.165:2181,192.168.98.166:2181,192.168.98.167:2181" subscribe="false"/>
8.负载均衡
在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。可以自行扩展负载均衡策略
配置: <dubbo:reference interface="..." loadbalance="roundrobin" />
源码:dubbo-cluster
1)Random LoadBalance(默认)
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
2)RoundRobin LoadBalance
轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
3)LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
4)ConsistentHash LoadBalance
一致性Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
9.连接超时timeout
必须要设置服务的处理的超时时间,超时后报错
<dubbo:service interface="com.charjay.order.IOrderServices" ref="orderService" timeout="2000"/>
消费者与提供者同时设置了timeout,那么哪个优先级高?
消费端优先级高
10.集群容错
1)Failover cluster 失败的时候自动切换并重试其他服务器。 通过retries=2。 来设置重试次数(失败后再重试两次)
使用场景:读操作,但是重试会带来更长的延时
2)failfast cluster 快速失败,只发起一次调用 ;
使用场景:写操作。比如新增记录的时候,非幂等请求
幂等:不管操作多少次,都只影响一次或不影响数据(比如插入唯一key数据的时候,插入多次都只有一条记录是成功的)
3)failsafe cluster 失败安全。 出现异常时,直接忽略异常
使用场景:记录日志的时候
4)failback cluster 失败自动恢复。 后台记录失败请求,定时重发
使用场景:消息通知,比如支付回调的通知
5)forking cluster 并行调用多个服务器,只要一个成功就返回。可通过forks="2"来设置最大并行数。
使用场景: 通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
6)broadcast cluster 广播调用所有提供者,逐个调用。其中一台报错就会返回异常
使用场景:通常用于通知所有提供者更新缓存或日志等本地资源信息。
7)配置
<dubbo:reference cluster="failsafe" />
<dubbo:reference retries="2" />
11.配置的优先级
消费端 > 服务端
12.服务的最佳实践
1)分包
1、服务接口、请求服务模型、异常信息都放在api里面,符合重用发布等价原则,共同重用原则
2、api里面放入spring 的引用配置。 也可以放在模块的包目录下。 com.xxx.order/***-reference.xml
2)粒度
1、尽可能把接口设置成粗粒度,每个服务方法代表一个独立的功能,而不是某个功能的步骤。否则就会涉及到分布式事务
2、服务接口建议以业务场景为单位划分。并对相近业务做抽象,防止接口暴增
3、不建议使用过于抽象的通用接口 T T<泛型>, 接口没有明确的语义,带来后期的维护
3)版本
1、每个接口都应该定义版本,为后续的兼容性提供前瞻性的考虑 version (maven -snapshot)
2、建议使用两位版本号,因为第三位版本号表示的兼容性升级,只有不兼容时才需要变更服务版本
3、当接口做到不兼容升级的时候,先升级一半或者一台提供者为新版本,再将消费全部升级新版本,然后再将剩下的一半提供者升级新版本(预发布环境)
13.推荐用法
1)在provider端尽可能配置consumer端的属性
比如timeout、retires、线程池大小、LoadBalance
2)配置管理员信息
application上面配置的owner 、 owner建议配置2个人以上。因为owner都能够在监控中心看到
14.配置dubbo缓存文件
web层配置
<dubbo:registry protocol="zookeeper" file="d:/dubbo.cache"
address="192.168.98.165:2181,192.168.98.166:2181,192.168.98.167:2181"/>
注册中心的列表
服务提供者列表