在默认情况下,每次请求会占用一次线程和一次网络请求,在高并发的场景下效率不高,Hystrix请求合并就是将多个请求合并为一个请求,提高服务并发能力,适用场景,单个对象的查询并发数很高,服务提供方负载比较大的时候。
两种实现方式:
1.编码
/**
* <h1>请求合并器</h1>
* */
@Slf4j
public class NacosClientCollapseCommand
extends HystrixCollapser<List<List<ServiceInstance>>, List<ServiceInstance>, String> {
private final NacosClientService nacosClientService;
private final String serviceId;
public NacosClientCollapseCommand(NacosClientService nacosClientService, String serviceId) {
super(
HystrixCollapser.Setter.withCollapserKey(
HystrixCollapserKey.Factory.asKey("NacosClientCollapseCommand")
).andCollapserPropertiesDefaults(
HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(300)
)
);
this.nacosClientService = nacosClientService;
this.serviceId = serviceId;
}
/**
* <h2>获取请求中的参数</h2>
* */
@Override
public String getRequestArgument() {
return this.serviceId;
}
/**
* <h2>创建批量请求 Hystrix Command</h2>
* */
@Override
protected HystrixCommand<List<List<ServiceInstance>>> createCommand(
Collection<CollapsedRequest<List<ServiceInstance>, String>> collapsedRequests) {
List<String> serviceIds = new ArrayList<>(collapsedRequests.size());
serviceIds.addAll(
collapsedRequests.stream()
.map(CollapsedRequest::getArgument)
.collect(Collectors.toList())
);
return new NacosClientBatchCommand(nacosClientService, serviceIds);
}
/**
* <h2>响应分发给单独的请求</h2>
* */
@Override
protected void mapResponseToRequests(List<List<ServiceInstance>> batchResponse,
Collection<CollapsedRequest<List<ServiceInstance>,
String>> collapsedRequests) {
int count = 0;
for (CollapsedRequest<List<ServiceInstance>, String> collapsedRequest : collapsedRequests) {
// 从批量响应集合中按顺序取出结果
List<ServiceInstance> instances = batchResponse.get(count++);
// 将结果返回原 Response 中
collapsedRequest.setResponse(instances);
}
}
}
/**
* <h1>批量请求 Hystrix Command</h1>
* */
@Slf4j
public class NacosClientBatchCommand extends HystrixCommand<List<List<ServiceInstance>>> {
private final NacosClientService nacosClientService;
private final List<String> serviceIds;
protected NacosClientBatchCommand(
NacosClientService nacosClientService, List<String> serviceIds
) {
super(
HystrixCommand.Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey("NacosClientBatchCommand")
)
);
this.nacosClientService = nacosClientService;
this.serviceIds = serviceIds;
}
@Override
protected List<List<ServiceInstance>> run() throws Exception {
log.info("use nacos client batch command to get result: [{}]",
JSON.toJSONString(serviceIds));
return nacosClientService.getNacosClientInfos(serviceIds);
}
@Override
protected List<List<ServiceInstance>> getFallback() {
log.warn("nacos client batch command failure, use fallback");
return Collections.emptyList();
}
}2.注解
// 使用注解实现 Hystrix 请求合并
@HystrixCollapser(
batchMethod = "findNacosClientInfos",
scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
collapserProperties = {
@HystrixProperty(name = "timerDelayInMilliseconds", value = "300")
}
)
public Future<List<ServiceInstance>> findNacosClientInfo(String serviceId) {
// 系统运行正常, 不会走这个方法
throw new RuntimeException("This method body should not be executed!");
}
@HystrixCommand
public List<List<ServiceInstance>> findNacosClientInfos(List<String> serviceIds) {
log.info("coming in find nacos client infos: [{}]", JSON.toJSONString(serviceIds));
return getNacosClientInfos(serviceIds);
} /**
* <h2>注解的方式实现请求合并</h2>
* */
@GetMapping("/request-merge-annotation")
public void requestMergeAnnotation() throws Exception {
Future<List<ServiceInstance>> future01 = nacosClientService.findNacosClientInfo(
"e-commerce-nacos-client1"
);
Future<List<ServiceInstance>> future02 = nacosClientService.findNacosClientInfo(
"e-commerce-nacos-client2"
);
Future<List<ServiceInstance>> future03 = nacosClientService.findNacosClientInfo(
"e-commerce-nacos-client3"
);
future01.get();
future02.get();
future03.get();
Thread.sleep(2000);
Future<List<ServiceInstance>> future04 = nacosClientService.findNacosClientInfo(
"e-commerce-nacos-client4"
);
future04.get();
}