1.简介
为了避免单点故障,现在的应用通常至少会部署在两台服务器上。对于一些负载比较高的服务,会部署更多的服务器。这样,在同一环境下的服务提供者数量会大于1。对于服务消费者来说,同一环境下出现了多个服务提供者。这时会出现一个问题,服务消费者需要决定选择哪个服务提供者进行调用。另外服务调用失败时的处理措施也是需要考虑的,是重试呢,还是抛出异常,亦或是只打印异常等。为了处理这些问题,Dubbo 定义了集群接口 Cluster 以及 Cluster Invoker。集群 Cluster 用途是将多个服务提供者合并为一个 Cluster Invoker,并将这个 Invoker 暴露给服务消费者。这样一来,服务消费者只需通过这个 Invoker 进行远程调用即可,至于具体调用哪个服务提供者,以及调用失败后如何处理等问题,现在都交给集群模块去处理。集群模块是服务提供者和服务消费者的中间层,为服务消费者屏蔽了服务提供者的情况,这样服务消费者就可以专心处理远程调用相关事宜。比如发请求,接受服务提供者返回的数据等。这就是集群的作用。
2.集群容错
这里有必要先来介绍一下集群容错的所有组件。包含 Cluster、Cluster Invoker、Directory、Router 和 LoadBalance 等。
集群工作过程可分为两个阶段,第一个阶段是在服务消费者初始化期间,集群 Cluster 实现类为服务消费者创建 Cluster Invoker 实例,即上图中的 merge 操作。第二个阶段是在服务消费者进行远程调用时。以 FailoverClusterInvoker 为例,该类型 Cluster Invoker 首先会调用 Directory 的 list 方法列举 Invoker 列表(可将 Invoker 简单理解为服务提供者)。Directory 的用途是保存 Invoker,可简单类比为 List
以上就是集群工作的整个流程。
简而言之: 容错即“耐故障”或“容许故障”的意思。对于组成系统的元器件发生不可避免的故障时,采取响应的措施,仍能使系统维持正常工作状态。
容错模式:是解决容错问题的一系列解决方案。dubbo框架为服务集群容错提供了一系列好的解决方案,在此称为dubbo服务集群容错模式。
Dubbo 主要提供了这样几种容错方式:
Failover Cluster - 失败自动切换(默认)
Failfast Cluster - 快速失败
Failsafe Cluster - 失败安全
Failback Cluster - 失败自动恢复
Forking Cluster - 并行调用多个服务提供者
Dubbo 提供了多种集群实现,包含但不限于 Failover Cluster、Failfast Cluster 和 Failsafe Cluster 等。每种集群实现类的用途不同,接下来会一一进行分析。
3.搭建基于Apache dubbo 的集群环境
- 创建父工程dubbodemo 并引入依赖:
org.apache.dubbo
dubbo
2.7.1
org.apache.zookeeper
zookeeper
3.4.6
com.github.sgroschupf
zkclient
0.1
org.apache.curator
curator-framework
2.8.0
org.apache.curator
curator-recipes
2.8.0
log4j
log4j
1.2.17
2.创建子工程dubbo-service 依赖于dubbodemo工程(服务提供者)
创建接口:
package com.gf.service;
public interface DemoService {
String sayHello(String name);
}
创建接口的实现类:
package com.gf.service.impl;
import com.gf.service.DemoService;
public class DemoServiceImpl implements DemoService {
public String sayHello(String name) {
System.err.println("service执行了===========");
return "hello : "+name;
}
}
编写provider.xml配置文件:
编写Provider.java启动类:
package com.gf.provider;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class Provider {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
context.start();
System.in.read();
}
}
3.创建子工程dubbo-web 依赖于dubbodemo工程(消费者)
声明接口:(注意:此接口必须和服务提供者接口同包同名)
package com.gf.service;
public interface DemoService {
String sayHello(String name);
}
编写consumer.xml配置文件:
编写Consumer.java启动类:
package com.gf.consumer;
import com.gf.service.DemoService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class Consumer {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml");
context.start();
DemoService demoService = context.getBean("demoService", DemoService.class);
String s = demoService.sayHello("dubbo..");
System.err.println(s);
System.in.read();
}
}
接着我们复制一份dubbo-service改名为dubbo-service1,并修改端口号即可实现模拟多个服务提供者实例即模拟的集群环境.
1.Failover Cluster
当出现失败时,重试其他服务器,为缺省值。通常用于读操作,但重试会带来更长的延迟。可通过retries="2"来设置重试次数(不含第一次)。
幂等(设置重试次数)【查询】、非幂等(不能设置重试次数)【新增】
代码:
2.Failfast Cluster
只发起一次调用,失败立即报错,并且停止当前消费,通常用于非幂等性的写操作,比如:新增记录。
代码:
3.Failsafe Cluster
出现异常时,直接忽略。当前消费者不会停止,待提供者服务恢复,即可正常调用。通常用于写入审计日志等操作。
代码:
4.Failback Cluster
后台记录失败请求,定时重发(消费者不会停止。一段时间后重新再调用,直到调用成功)。通常用于消息通知操作。
代码:
5.Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求比较高的读操作,但需要浪费更多的服务资源。
可通过forks="2"来设置最大并行数。
4.配置原则
dubbo推荐在Provider上尽量多配置Consumer端属性:【非常重要】
1、作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
2、在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值。否则,Consumer会使用Consumer端的全局设置,这对于 Provider不可控的,并且往往是不合理的
3、方法级配置别优于接口级别,即小Scope优先
5.多版本
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
在低压力时间段,先升级一半提供者为新版本
再将所有消费者升级为新版本
然后将剩下的一半提供者升级为新版本
老版本服务提供者配置:
新版本服务提供者配置:
老版本服务消费者配置:
新版本服务消费者配置:
如果不需要区分版本,可以按照以下的方式配置 :