策略介绍和配置示例
在pigeon开源版本中,目前实现了4种集群策略:
- failfast:调用服务的一个节点失败后抛出异常返回,可以同时配置重试timeoutRetry和retries属性
- failover:调用服务的一个节点失败后会尝试调用另外的一个节点,可以同时配置重试timeoutRetry和retries属性
- failsafe:调用服务的一个节点失败后不会抛出异常,返回null,后续版本会考虑按配置默认值返回
- forking:同时调用服务的所有可用节点,返回调用最快的节点结果数据
在failfast和failover中,重试只限于超时异常,即RequestTimeoutException,其他异常在调用失败后仍会直接抛出。
配置示例如下:
<bean id="echoService" class="com.dianping.pigeon.remoting.invoker.config.spring.ReferenceBean" init-method="init">
<property name="url" value="http://service.dianping.com/com.dianping.pigeon.demo.EchoService" />
<property name="interfaceName" value="com.dianping.pigeon.demo.EchoService" />
<property name="callType" value="sync" />
<property name="timeout" value="1000" />
<!-- 失败策略,快速失败failfast/失败转移failover/失败忽略failsafe/并发取最快返回forking,默认failfast -->
<property name="cluster" value="failfast" />
<!-- 是否超时重试,默认false -->
<property name="timeoutRetry" value="false" />
<!-- 重试次数,默认1 -->
<property name="retries" value="1" />
</bean>
集群策略初始化和调用流程
集群策略的扩展定义在ClusterInvokeFilter中。在触发RPC请求前,先调用ClusterInvokeFilter来选择响应的集群策略完成RPC请求:
public class ClusterInvokeFilter extends InvocationInvokeFilter {
public InvocationResponse invoke(ServiceInvocationHandler handler, InvokerContext invocationContext)
throws Throwable {
InvokerConfig<?> invokerConfig = invocationContext.getInvokerConfig();
// 获取配置指定的集群模式
Cluster cluster = ClusterFactory.selectCluster(invokerConfig.getCluster());
if (cluster == null) {
throw new IllegalArgumentException("Unsupported cluster type:" + cluster);
}
// 使用指定集群策略
return cluster.invoke(handler, invocationContext);
}
}
上面提到的4中集群策略的初始化和获取逻辑在ClusterFactory中完成:
public class ClusterFactory {
private final static ConcurrentHashMap<String, Cluster> clusters = new ConcurrentHashMap<String, Cluster>();
static {
init();
}
// 初始化4种集群策略
public static void init() {
clusters.put(Constants.CLUSTER_FAILFAST, new FailfastCluster());
clusters.put(Constants.CLUSTER_FAILOVER, new FailoverCluster());
clusters.put(Constants.CLUSTER_FAILSAFE, new FailsafeCluster());
clusters.put(Constants.CLUSTER_FORKING, new ForkingCluster());
}
// 用于注册自定义的集群策略
public static void registerCluster(String clusterType, Cluster cluster) {
clusters.put(clusterType, cluster);
}
// 根据集群策略类型字符串获取相应的集群策略实例
public static Cluster selectCluster(String clusterType) {
Cluster cluster = clusters.get(clusterType);
if (cluster == null) {
return clusters.get(Constants.CLUSTER_FAILFAST);
}
return cluster;
}
}
每个集群策略的逻辑起点是invoke方法,内部的大致实现逻辑是先初始化一个远程请求供远程传输,而后根据负载均衡策略选取合适的连接,如果在选取可用连接时抛出ServiceUnavailableException会直接失败,否则再应用特定的集群策略来完成调用。
下面开始对各种策略的实现原理进行分析:
failfast 快速失败策略
如果使用failfase策略,会在调用失败后抛出异常,如果配置了timeoutRetry=true,会在因为捕获到RequestTimeoutException异常失败后,重试调用最多retries次,具体实现逻辑如下:
public class FailfastCluster implements Cluster {
private ClientManager clientManager = ClientManager.getInstance();
private static final Logger logger = LoggerLoader.getLogger(FailfastCluster.class);
@Override
public InvocationResponse invoke(ServiceInvocationHandler handler, InvokerContext invocationContext)
throws Throwable {
InvokerConfig<?> invokerConfig = invocationContext