面试题答案
一键面试设计思路
- 依赖关系管理:使用有向无环图(DAG)来表示微服务之间的依赖关系。节点代表微服务调用,边代表依赖关系。对于 OR 组合关系的节点,只要其中一个子节点完成(成功),父节点就可以继续。
- 超时处理:为每个 CompletableFuture 设置超时时间。可以使用
CompletableFuture
的orTimeout
方法来实现。 - 服务熔断:引入熔断器机制,例如使用 Hystrix 或 Sentinel。当某个微服务调用失败次数达到一定阈值,触发熔断,直接返回预设的 fallback 结果。
- 通用框架:设计一个通用的类或方法,接受微服务调用的
CompletableFuture
以及它们之间的依赖关系作为输入,返回最终的CompletableFuture
。
关键代码实现
- 定义微服务调用的包装类
import java.util.concurrent.CompletableFuture;
public class MicroserviceCall<T> {
private CompletableFuture<T> future;
private boolean isFallback;
public MicroserviceCall(CompletableFuture<T> future) {
this.future = future;
this.isFallback = false;
}
public CompletableFuture<T> getFuture() {
return future;
}
public void setFallback(boolean isFallback) {
this.isFallback = isFallback;
}
public boolean isFallback() {
return isFallback;
}
}
- 构建 DAG 结构
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DependencyGraph<T> {
private Map<MicroserviceCall<T>, List<MicroserviceCall<T>>> graph;
public DependencyGraph() {
this.graph = new HashMap<>();
}
public void addEdge(MicroserviceCall<T> from, MicroserviceCall<T> to) {
graph.putIfAbsent(from, new ArrayList<>());
graph.get(from).add(to);
}
public Map<MicroserviceCall<T>, List<MicroserviceCall<T>>> getGraph() {
return graph;
}
}
- 通用框架实现
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class CompletableFutureCombiner<T> {
private static final int DEFAULT_TIMEOUT = 10; // 秒
public CompletableFuture<T> combineTasks(DependencyGraph<T> graph, MicroserviceCall<T> root) {
return processNode(graph, root, DEFAULT_TIMEOUT);
}
private CompletableFuture<T> processNode(DependencyGraph<T> graph, MicroserviceCall<T> node, int timeout) {
CompletableFuture<T> future = node.getFuture();
future = future.orTimeout(timeout, TimeUnit.SECONDS);
List<MicroserviceCall<T>> children = graph.getGraph().getOrDefault(node, new ArrayList<>());
if (children.isEmpty()) {
return future;
}
List<CompletableFuture<T>> childFutures = new ArrayList<>();
for (MicroserviceCall<T> child : children) {
CompletableFuture<T> childFuture = processNode(graph, child, timeout);
childFutures.add(childFuture);
}
return CompletableFuture.anyOf(childFutures.toArray(new CompletableFuture[0]))
.thenApply(result -> {
try {
return (T) ((CompletableFuture<T>) result).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
});
}
}
- 示例使用
public class Main {
public static void main(String[] args) {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result from MS1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result from MS2");
MicroserviceCall<String> ms1 = new MicroserviceCall<>(future1);
MicroserviceCall<String> ms2 = new MicroserviceCall<>(future2);
DependencyGraph<String> graph = new DependencyGraph<>();
graph.addEdge(ms1, ms2);
CompletableFutureCombiner<String> combiner = new CompletableFutureCombiner<>();
CompletableFuture<String> result = combiner.combineTasks(graph, ms1);
result.join();
}
}
以上代码实现了一个简单的通用框架来处理复杂的 CompletableFuture 组合任务,包含依赖关系处理、超时处理。在实际应用中,需要结合具体的熔断器库(如 Hystrix 或 Sentinel)来实现服务熔断功能。