集群容错系列文章:
Failover Cluster 失败自动切换
Failfast Cluster 快速失败,抛出异常
Failsafe Cluster 快速失败,不抛出异常
Failback Cluster 失败后定时重试
Forking Cluster 并行调用多个实例,只要一个成功就返回
Broadcast Cluster 广播调用所有实例,有一个报错则抛出异常
Available Cluster 可用的实例
Mergeable Cluster 合并结果
本文简单介绍 Dubbo 中的 Mergeable Cluster(结果可合并)。
简介
该集群容错模式下,可以合并结果集,一般和 group 一起使用,具体使用规则参考 分组聚合
实现逻辑
- 如果没有配置 merger,则不合并结果集,直接调用实例执行后返回
- 异步调用所有的实例
- 获取要调用的方法的返回类型,根据返回类型进行调用,如果是 . 开头的,则调用方法;否则如果有配置自定义合并器,则调用自动以合并器,如果没有则调用默认的合并器
源代码
public class MergeableClusterInvoker<T> implements Invoker<T> {
private static final Logger log = LoggerFactory.getLogger(MergeableClusterInvoker.class);
private final Directory<T> directory;
private ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("mergeable-cluster-executor", true));
public MergeableClusterInvoker(Directory<T> directory) {
this.directory = directory;
}
@Override
@SuppressWarnings("rawtypes")
public Result invoke(final Invocation invocation) throws RpcException {
List<Invoker<T>> invokers = directory.list(invocation);
// 获取 merger 配置参数值
String merger = getUrl().getMethodParameter(invocation.getMethodName(), Constants.MERGER_KEY);
if (ConfigUtils.isEmpty(merger)) { // If a method doesn't have a merger, only invoke one Group
// 没有配置 merger,则默认所有调用实例都是一个组的
for (final Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
// 调用可用的实例
return invoker.invoke(invocation);
}
}
// 如果都是不可用的,则调用第一个实例
return invokers.iterator().next().invoke(invocation);
}
Class<?> returnType;
try {
returnType = getInterface().getMethod(
invocation.getMethodName(), invocation.getParameterTypes()).getReturnType();
} catch (NoSuchMethodException e) {
returnType = null;
}
// 异步调用所有的实例,并把对象存储到 results 中
Map<String, Future<Result>> results = new HashMap<String, Future<Result>>();
for (final Invoker<T> invoker : invokers) {
Future<Result> future = executor.submit(new Callable<Result>() {
@Override
public Result call() throws Exception {
return invoker.invoke(new RpcInvocation(invocation, invoker));
}
});
results.put(invoker.getUrl().getServiceKey(), future);
}
Object result = null;
List<Result> resultList = new ArrayList<Result>(results.size());
// 获取超时时间
int timeout = getUrl().getMethodParameter(invocation.getMethodName(), Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
// 遍历获取执行实例的结果
for (Map.Entry<String, Future<Result>> entry : results.entrySet()) {
Future<Result> future = entry.getValue();
try {
Result r = future.get(timeout, TimeUnit.MILLISECONDS);
if (r.hasException()) {
// 调用的服务内部有异常,不抛出,记录
log.error("Invoke " + getGroupDescFromServiceKey(entry.getKey()) +
" failed: " + r.getException().getMessage(),
r.getException());
} else {
// 保存执行结果
resultList.add(r);
}
} catch (Exception e) {
// 有异常则抛出
throw new RpcException("Failed to invoke service " + entry.getKey() + ": " + e.getMessage(), e);
}
}
if (resultList.isEmpty()) {
return new RpcResult((Object) null);
} else if (resultList.size() == 1) {
return resultList.iterator().next();
}
if (returnType == void.class) {
return new RpcResult((Object) null);
}
if (merger.startsWith(".")) {
// . 开头,则需要调用自定义的方法来进行合并
merger = merger.substring(1);
Method method;
try {
method = returnType.getMethod(merger, returnType);
} catch (NoSuchMethodException e) {
throw new RpcException("Can not merge result because missing method [ " + merger + " ] in class [ " +
returnType.getClass().getName() + " ]");
}
if (!Modifier.isPublic(method.getModifiers())) {
method.setAccessible(true);
}
result = resultList.remove(0).getValue();
try {
// 调用方法进行合并
if (method.getReturnType() != void.class
&& method.getReturnType().isAssignableFrom(result.getClass())) {
for (Result r : resultList) {
result = method.invoke(result, r.getValue());
}
} else {
for (Result r : resultList) {
method.invoke(result, r.getValue());
}
}
} catch (Exception e) {
throw new RpcException("Can not merge result: " + e.getMessage(), e);
}
} else {
Merger resultMerger;
if (ConfigUtils.isDefault(merger)) {
// 执行默认的合并器
resultMerger = MergerFactory.getMerger(returnType);
} else {
// 执行自定义的 Merger 合并器来合并
resultMerger = ExtensionLoader.getExtensionLoader(Merger.class).getExtension(merger);
}
if (resultMerger != null) {
List<Object> rets = new ArrayList<Object>(resultList.size());
for (Result r : resultList) {
rets.add(r.getValue());
}
// 调用合并器 merge 方法
result = resultMerger.merge(
rets.toArray((Object[]) Array.newInstance(returnType, 0)));
} else {
throw new RpcException("There is no merger to merge result.");
}
}
return new RpcResult(result);
}
@Override
public Class<T> getInterface() {
return directory.getInterface();
}
@Override
public URL getUrl() {
return directory.getUrl();
}
@Override
public boolean isAvailable() {
return directory.isAvailable();
}
@Override
public void destroy() {
directory.destroy();
}
private String getGroupDescFromServiceKey(String key) {
int index = key.indexOf("/");
if (index > 0) {
return "group [ " + key.substring(0, index) + " ]";
}
return key;
}
}
做个有梦想的程序猿
