failover:故障转移
当出现失败,重试其它服务器,通常用于读操作(推荐使用)。 重试会带来更长延迟。
protected RpcResult doInvoke(RpcInvocation invocation, List<Invoker<T>> invokers) throws Throwable {
List<Invoker<T>> invoked = new ArrayList<>();
Throwable recordExe = null;
for (int i = 0; i <= retryTimes; i++) {
//负载均衡选择Invoker
Invoker<T> invoker = select(invocation, invokers, invoked);
invoked.add(invoker);
try {
return invoker.invoke(invocation);
} catch (Throwable e) {
logger.warn("Failed " + i + " times, interface=" + invoker.getInterface().getName() +
"|method=" + invocation.getMethod().getName() + "|provider=" +
invoker.getProvider().getIp() + Constants.COLON + invoker.getProvider().getPort(), e);
recordExe = e;
}
}
if (recordExe != null) {
throw recordExe;
}
return new RpcResult();
}
failfast:
只发起一次调用,失败立即报错,通常用于非幂等性的写操作。 如果有机器正在重启,可能会出现调用失败 。
protected RpcResult doInvoke(RpcInvocation invocation, List<Invoker<T>> invokers) throws Throwable {
Invoker<T> invoker = select(invocation, invokers, new ArrayList<Invoker<T>>());
return invoker.invoke(invocation);
}
failback:
后台记录失败请求,定时重发。通常用于消息通知操作 不可靠,重启丢失。 可用于生产环境 Registry。
protected RpcResult doInvoke(RpcInvocation invocation, List<Invoker<T>> invokers) {
//select负载均衡
Invoker<T> invoker = select(invocation, invokers, new ArrayList<Invoker<T>>());
try {
return invoker.invoke(invocation);
} catch (Throwable e) {
logger.error("Remote invoke failed, interface=" + invoker.getInterface().getName() +
"|method=" + invocation.getMethod().getName() + "|provider=" +
invoker.getProvider().getIp() + Constants.COLON + invoker.getProvider().getPort() + ", wait for retry in background", e);
addFailed(invocation, this);
}
return new RpcResult();
}
private void addFailed(RpcInvocation invocation, ClusterHandler<T> clusterHandler) {
if (retryFuture == null) {
synchronized (this) {
if (retryFuture == null) {
retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
// 定时重试
try {
retryFailed();
} catch (Throwable t) {
logger.error("Unexpected error occur at retry", t);
}
}
}, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS);
}
}
}
failed.put(invocation, clusterHandler);
}
private void retryFailed() {
if (failed.size() == 0) {
return;
}
for (Map.Entry<RpcInvocation, ClusterHandler<?>> entry : new HashMap<>(failed).entrySet()) {
RpcInvocation invocation = entry.getKey();
ClusterHandler clusterHandler = entry.getValue();
try {
clusterHandler.handle(invocation);
failed.remove(invocation);
} catch (Throwable e) {
logger.error("Failed retry to invoke method=" + invocation.getMethod().getName() + ", waiting again.", e);
}
}
}
failsafe:
出现异常时,直接忽略,通常用于写入审计日志等操作。 调用信息丢失 可用于生产环境 Monitor。
protected RpcResult doInvoke(RpcInvocation invocation, List<Invoker<T>> invokers) throws Throwable {
//select负载均衡
Invoker<T> invoker = select(invocation, invokers, new ArrayList<Invoker<T>>());
try {
return invoker.invoke(invocation);
} catch (Throwable e) {
//出现异常时,直接忽略
}
return new RpcResult();
}