概述
一、背景
- 远程调用最常见的问题: 通信消耗与连接数占用
- 高并发的情况下,因通信次数的增加,总的通信时间消耗将会变的不那么理想
- 同时,因为对依赖服务的线程池资源有限,将出现排队等待与响应延迟的情况
- Hystrix提供了HystrixCollapser来实现请求的合并,以减少通信消耗和线程数的占用
HystrixCollapser 实现了在 HystrixCommand 之前放置一个合并处理器:
- 将处于一个很短时间窗(默认10毫秒)内对同一依赖服务的多个请求进行整合并以批量方式发起请求的功能(服务提供方也需要提供相应的批量实现接口)
- 通过 HystrixCollapser 的封装,开发者不需要去关注线程合并的细节过程,只需要关注批量化服务和处理
二、实例
1. 部分源码
/**
* BatchReturnType:合并后批量请求的返回类型
* ResponseType:单个请求返回的类型
* RequestArgumentType:请求参数类型
*/
public abstract class HystrixCollapser<BatchReturnType, ResponseType, RequestArgumentType> implements
HystrixExecutable<ResponseType>, HystrixObservable<ResponseType> {
...
//获取请求参数
public abstract RequestArgumentType getRequestArgument();
//合并请求产生批量命令的具体实现方法
protected abstract HystrixCommand<BatchReturnType> createCommand(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);
//批量命令结果返回后的处理: 需要实现将批量结果拆分并传递给合并前的各个原子请求命令的逻辑
protected abstract void mapResponseToRequests(BatchReturnType batchResponse, Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);
...
}
2. 简单的示例
假设,当前微服务 USER-SERVICE
提供了两个获取 User 的接口:
/users/{id}
:根据 id 返回 User 对象的 GET 请求接口/users?ids={ids}
:根据 ids 参数返回 User 对象列表的 GET 请求接口ids 以逗号分割的 id 集合
在服务消费端,这两个远程接口已经通过 RestTemplate 实现了简单的调用,具体如下:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private RestTemplate restTemplate;
@Override
public User find(Long id) {
return restTemplate.getForObject("http://USER-SERVICE/users/{1}", User.class, id);
}
@Override
public List<User> findAll(List<Long> ids) {
return restTemplate.getForObject("http://USER-SERVICE/users?ids={1}", List.class, StringUtils.join(ids, ","));
}
}
接着,在短时间内多个获取单一 User 对象的请求命令进行合并的实现:
-
第一步:为请求合并的实现准备一个批量请求命令的实现
public class UserBatchCommand extends HystrixCommand<List<User>> { UserService userService; List<Long> userIds; public UserBatchCommand(UserService userService, List<Long> userIds) { super(Setter.withGroupKey(asKey("userServiceCommand"))); this.userIds = userIds; this.userService = userService; } @Override protected List<User> run() throws Exception { return userService.findAll(userIds); } }
批量请求命令实际上就是一个简单的 HystrixCommand 实现
通过调用 userService.findAll 方法来访问 /users?ids={ids} 接口以返回 User 的列表结果 -
第二步,通过继承 HystrixCollapser 实现请求合并器
public class UserCollapseCommand extends HystrixCollapser<List<User>, User, Long> { private UserService userService; private Long userId; public UserCollapseCommand(UserService userService, Long userId) { super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("userCollapseCommand")).andCollapserPropertiesDefaults( HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(100))); this.userService = userService; this.userId = userId; } //获取请求参数 @Override public Long getRequestArgument() { return userId; } //合并请求产生批量命令的具体实现方法 @Override protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Long>> collapsedRequests) { List<Long> userIds = new ArrayList<>(collapsedRequests.size()); userIds.addAll(collapsedRequests.stream().map(CollapsedRequest::getArgument).collect(Collectors.toList())); return new UserBatchCommand(userService, userIds); } //批量命令结果返回后的处理: 需要实现将批量结果拆分并传递给合并前的各个原子请求命令的逻辑 @Override protected void mapResponseToRequests(List<User> batchResponse, Collection<CollapsedRequest<User, Long>> collapsedRequests) { int count = 0; for (CollapsedRequest<User, Long> collapsedRequest : collapsedRequests) { User user = batchResponse.get(count++); collapsedRequest.setResponse(user); } } }
getRequestArgument
:返回给定的单个请求参数 userIdcreateCommand
:collapsedRequests 参数保存延迟时间窗中收集到的所有获取单个 User 的请求通过获取这些请求的参数来组织准备的批量请求命令 UserBatchCommand 实例
mapResponseToRequests
:在批量命令 UserBatchCommand 实例被触发执行完成之后,该方法开始执行- batchResponse 参数保存了 createCommand 中组织的批量请求命令的返回结果
- collapsedRequests 参数代表了每个被合并的请求
通过遍历批量结果 batchResponse 对象,为 collapsedRequests 中每个合并前的单个请求设置返回结果,以此完成批量结果到单个请求结果的转换
推荐文章: Spring Cloud Hystrix的请求合并
最后
以上就是风趣冥王星为你收集整理的HystrixCollapser 请求合并一、背景二、实例的全部内容,希望文章能够帮你解决HystrixCollapser 请求合并一、背景二、实例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复