Hystrix请求合并

15 篇文章 0 订阅

应用场景
将短时间内的,仅参数不同的多个请求合并成一个请求,这可以在高并发场景下减少线程数量以及网路连接数量。

好处:

  • 在高并发下以及大量重复请求下很有用
  • 增加应用的请求吞吐量

缺点

  • 会导致延迟大幅提上,具体延迟要看如何配置

批处理Command实现

创建provider提供接口

@RestController
public class UserController {
    @GetMapping("/user/{ids}")
    public List<User> getUserByIds(@PathVariable String ids){
        System.out.println(ids);
        String[] split = ids.split(",");
        List<User> users = new ArrayList<>();
        for (String s : split)
        {
            User user = new User();
            user.setId(Integer.parseInt(s));
            users.add(user);
        }
        return users;
    }
}

解释:
创建接口,将1,2,3,4根据","分开,分别赋予四个对象组成集合返回

创建发起合并过后的请求的Service

@Service
public class UserService {

    @Autowired
    RestTemplate restTemplate;

    /**
     * 发送合并起来的请求
     * @param ids
     * @return
     */
    public List<User> getUserByIds(List<Integer> ids){
        User[] users = restTemplate.getForObject("http://provider/user/{1}", User[].class, StringUtils.join(ids, ","));
         return Arrays.asList(users);
    }
}

将来将传入的参数集合拼接到url请求中,返回响应结果

创建批处理Command

//批处理,将多个请求合并成一个请求
public class UserBatchCommand  extends HystrixCommand<List<User>> {
    private List<Integer > ids;  //要合并的请求参数
    private UserService userService;  //发送合并请求的Service

    //构造,Setter
    public UserBatchCommand(List<Integer > ids , UserService userService) {
        super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("batchcmd")).andCommandKey(HystrixCommandKey.Factory.asKey("batchkey")));
        this.ids = ids;
        this.userService = userService;
    }
    //执行方法
    @Override
    protected List<User> run() throws Exception {
        return userService.getUserByIds(ids);
    }
}

解释:创建批处理Command,将从构造方法传进来的ids带入run方法,调用请求合并的Service

最重要的一步就是创建请求合并的HystrixCollapseCommand

public class UserCollapseCommand extends HystrixCollapser<List<User>,User,Integer> {
    private UserService userService;  //在批处理调用合并请求发送Service
    private Integer id;// 每一个请求的参数
    //构造方法
    public UserCollapseCommand( UserService userService, Integer id) {
        super(HystrixCollapser
                .Setter
                .withCollapserKey(HystrixCollapserKey.Factory.asKey("userCollapseCommand"))
                .andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(200))); //延时200  默认10ms
        this.userService = userService;
        this.id = id;
    }
    /**
     * 获得请求参数
     * @return
     */
    @Override
    public Integer getRequestArgument() {
        return id;
    }
    /**
     * 请求合并方法
     * @param collection
     * @return
     */
    @Override
    protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Integer>> collection) {
        List<Integer> ids = new ArrayList<>(collection.size()); //创造足够存所有请求参数的List
        for (CollapsedRequest<User, Integer> userIntegerCollapsedRequest : collection) {
            ids.add(userIntegerCollapsedRequest.getArgument());//将参数合并到一起
        }
        return new UserBatchCommand(ids,userService);//传入批处理Command
    }


    /**
     * 请求结果分发
     * @param userList
     * @param collection
     */
    @Override
    protected void mapResponseToRequests(List<User> userList, Collection<CollapsedRequest<User, Integer>> collection) {
        int count = 0;
        for (CollapsedRequest<User, Integer> userIntegerCollapsedRequest : collection) {
            userIntegerCollapsedRequest.setResponse(userList.get(count++));
        }
    }
}
  • 将每一个参数通过构造函数传入,重载获取参数的方法getRequestArgument(),直接返回注入的id即可
  • 重载合并请求的方法:createCommand,注意到这个方法返回的是HystrixCommand类型,就是刚刚创建的合并请求批处理Command,所以在这个方法里面只要把参数全部拿到,然后合并参数传入合并请求的批处理Command
  • 还有一盒就是响应结果分发,也就是给每一个请求一个满意的答复
  • 控制请求合并还有另一种方法:maxRequestsInBatch 设置HystrixCollapserProperties.Setter()
  • withMaxRequestsInBatch(int value) ,在value中设置请求的最大数量,这种方式只要请求达到预设的数量,就会合并,不然就一等,不推荐这种方式

接下来就是测试方法:

    @GetMapping("/collapseRequest")
    public void collapseRequest() throws ExecutionException, InterruptedException {
        HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
        UserCollapseCommand userCollapseCommand1 =  new UserCollapseCommand(userService, 1);
        UserCollapseCommand userCollapseCommand2 =  new UserCollapseCommand(userService,2);
        UserCollapseCommand userCollapseCommand3 =  new UserCollapseCommand(userService,3);
        Future<User> queue1 = userCollapseCommand1.queue();
        Future<User> queue2 = userCollapseCommand2.queue();
        Future<User> queue3 = userCollapseCommand3.queue();
        User user1 = queue1.get();
        User user2 = queue2.get();
        User user3 = queue3.get();
        Thread.sleep(2000);
        UserCollapseCommand userCollapseCommand4 =  new UserCollapseCommand(userService,96);
        Future<User> queue4 = userCollapseCommand4.queue();
        User user4 = queue4.get();
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user3);
        System.out.println(user4);
        ctx.close();
    }

在中间,调用Thread.sleep(2000)语句暂停了两面,为了就是超过预设的200ms,排除第四个请求到合并请求的队列中;

从结果就很容易看出这样发送了两次请求,参数123 为一组 4为单独一个

在这里插入图片描述

注解实现

一个方法两个注解:
在发送合并请求的Service里添加一个方法:

    @HystrixCollapser(batchMethod = "getUserByIds" ,collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value = "200")})
    public Future<User> getUserById(Integer id){
        return  null;
    }

@HystrixCollapser注解里面的属性也是之前Setter里面的相似,这个方法返回Future 返回值 null;

最后还要在发送合并请求的方法上,也就是@HystrixCollapser 的 batchMathod 指出的方法名上添加@HystrixCommand注解即可

测试

于批处理不太一样

直接调用注入的Service调用刚创建的getUserById方法,这个方法直接返回Future 剩下的跟批处理一样;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值