Spring Cloud (八)、Hystrix的使用详解——请求合并

前言:

       在高并发的场景下,Spring Cloud通过Hystrix的请求缓存请求合并来减轻高并发时的请求线程消耗、降低请求响应时间的效果。

 这里以注解的方式进行请求合并的演示。      

请求合并:将多个单个请求合并成一个请求,去调用服务提供者提供的服务接口,再遍历合并的结果为每个合并前的单个请求设置返回结果。

进行演示的前提是已经具备了注册中心eureka-server、服务提供者hello-service、服务消费者ribbon-consume。

一、在服务提供者新增一个UserController,实现/getUser/{id}接口和/getUsers接口。

/**
 * @author HDN
 * @date 2019/6/22 10:36
 */
@RestController
public class UserController {
    private Logger logger = Logger.getLogger(String.valueOf(UserController.class));
    //根据id获得单个User
    @RequestMapping(value = "/getUser/{id}")
    public User getUserById(@PathVariable String id){
        logger.info("getUserById,它的id:"+id);
        return new User(id,"hdn",22);
    }

    //获得多个user
    @RequestMapping(value = "/getUsers")
    public List<User> getUsers(@RequestParam("ids") List<String> ids){
        logger.info("getUsers,它的ids:"+ids);
        List<User> users = new ArrayList<>();
        User user = null;
        for(String id:ids){
            logger.info("getUsers,它的id:"+id);
            user = new User(id,"hdn",24);
            users.add(user);
        }
        return users;
    }
}

二、在服务消费者中新增UserService,添加find方法(请求合并)和findAll方法(合并之后调用的):

/**
 * @author HDN
 * @date 2019/6/22 10:50
 */
@Service
public class UserService {
    private Logger logger = Logger.getLogger(String.valueOf(UserService.class));

    @Autowired
    RestTemplate restTemplate;

    //请求合并的方法
    @HystrixCollapser(batchMethod = "findAll",collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value = "3000")})
    public Future<User> find(String id){
        //这里本应该访问服务提供者提供的/getUser/{id}接口
        logger.info("======执行了find方法========");
        return null;
    }



    //合并请求之后调用的方法
    @HystrixCommand
    public List<User> findAll(List<String> ids){
        logger.info("======执行了findAll方法========"+ids);
        return restTemplate.getForObject("http://hello-service/getUsers?ids={1}", List.class, StringUtils.join(ids, ","));
    }
}

三、在服务消费者中新增UserController,实现/findUser/{id}接口:

/**
 * @author HDN
 * @date 2019/6/22 11:08
 */
@RestController
public class UserController {
    @Autowired
    UserService userService;
    
    @RequestMapping(value = "/findUser/{id}")
    public String findUser(@PathVariable String id) throws ExecutionException, InterruptedException {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        Future<User> user1 = userService.find(id);
        Future<User> defaultUser = userService.find("888");
        System.out.println(user1.get());
        System.out.println(defaultUser.get());
        context.close();
        return "SUCCESS";
    }
}

测试1:访问http://localhost:9000/findUser/1,查看ribbon-consume控制台,可以根本没有进入到find方法体,把/findUser/{id}中两次访问find的请求合并为一个服务调用请求去访问findAll方法。

 测试2:在3000毫秒之内访问http://localhost:9000/findUser/1和http://localhost:9000/findUser/2,相当于有4个请求,来看控制台的结果,这里并没有将4个服务调用全部进行合并,而是根据不同线程的服务调用进行合并的:

       这里,可以通过设置@HystrixCollapser注解的scope属性来将两次客户端的请求合并为一次服务调用:

  • scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL:将所有线程中多次服务调用进行合并
  • scope = com.netflix.hystrix.HystrixCollapser.Scope.REQUEST:对一次请求的多次服务调用进行合并

四、将@HystrixCollapser注解设置scope属性为GLOBAL,再次测试测试2的情况:
 

/**
 * @author HDN
 * @date 2019/6/22 10:50
 */
@Service
public class UserService {
    private Logger logger = Logger.getLogger(String.valueOf(UserService.class));

    @Autowired
    RestTemplate restTemplate;

    //请求合并的方法
    @HystrixCollapser(batchMethod = "findAll",scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value = "3000")})
    //@HystrixCollapser(batchMethod = "findAll",collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value = "3000")})
    public Future<User> find(String id){
        //这里本应该访问服务提供者提供的/getUser/{id}接口
        logger.info("======执行了find方法========");
        return null;
    }



    //合并请求之后调用的方法
    @HystrixCommand
    public List<User> findAll(List<String> ids){
        logger.info("======执行了findAll方法========"+ids);
        return restTemplate.getForObject("http://hello-service/getUsers?ids={1}", List.class, StringUtils.join(ids, ","));
    }
}

测试3:在3000毫秒之内访问http://localhost:9000/findUser/1和http://localhost:9000/findUser/2,相当于有4个请求,来看控制台的结果,这里将所有的服务调用都进行了合并:

 ---------------------------------------------------总结---------------------------------------------------------

  1. UserService中单个请求的方法要返回Future包装的对象,实现异步请求。如果返回User对象,这个是同步请求,不会进行请求合并。
  2. 通过@HystrixCollapser注解的scope属性合并请求的作用于。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值