@HystrixCommand命令修饰的方法有2种执行方式:
1.同步:调用其他服务等待返回结果
2.异步:异步调用其他服务,返回Future对象,通过Future.get()获取返回结果。场景:当前服务需要调用多个其他服务然后汇总返回结果
---------------
服务降级
不用添加fallback服务降级方法的接口:
1.该接口返回类型为void,即不是查询类操作而是写操作,当写操作失败时要告诉调用者
2.接口执行批处理操作,报了异常不需要降级,只需要将异常返回给调用者就行
-----------------
命令分组、命令所属线程池
执行Hystrix命令默认使用的线程池是按照命令所在的分组划分的,一个命令分组公用一个线程池,在注解参数中指定分组,也可以更细粒度地指定所属线程池,如果指定了线程池,它的优先级更高,命令就不会用所在分组的默认线程池
配置方式:@HystrixCommand(fallbackMethod = "helloFallback", groupKey = "Group1", threadPoolKey = "HystrixFooServiceGaGa")
1.当上面3个属性都不配置的时候,比如study-spring-cloud-consumer中的HystrixUserService 这个类中所有标明了@HystrixCommand标的方法,都是使用1个线程池(线程名用的是类名hystrix-HystrixUserService-1 ),而如果有HystrixUserService2,里面也有@HystrixCommand标的方法,那么执行的时候使用的是另一个线程池,所以默认就已经是线程池隔离的
2.如果同时配置了groupKey 和 threadPoolKey ,那么具有相同的threadPoolKey的使用同一个线程池;
3.如果只配置了groupKey ,那么具有相同的groupKey 的使用同一个线程池;比如如果配置的是@HystrixCommand(fallbackMethod = "helloFallback", groupKey = "Group1"),那么线程名就是hystrix-Group1-*
-----------------
请求缓存
将命令请求获得的结果按照指定的key存储起来,key可以通过方法生成也可通过注解指定
@CacheResult(cacheKeyMethod = "getUserCatchKey") @HystrixCommand public User getUserById(Long id) { return restTemplate.getForEntity("http://hello-provider/user", User.class).getBody(); } public Long getUserCatchKey(Long id) { return id; }
@CacheResult @HystrixCommand public User getUserById(@CacheKey("id") Long id) { return restTemplate.getForEntity("http://hello-provider/user", User.class).getBody(); } --------------- @CacheResult @HystrixCommand public User getUserById(@CacheKey("id") User user) {// 自动获取user的id属性值 return restTemplate.getForEntity("http://hello-provider/user", User.class).getBody(); }
缓存清理
@CacheResult @HystrixCommand public User getUserById(@CacheKey("id") Long id) { return restTemplate.getForEntity("http://hello-provider/user", User.class).getBody(); } @CacheRemove(commandKey = "getUserById") @HystrixCommand public int update(@CacheKey("id") User user) { return restTemplate.postForEntity("http://hello-provider/user",user,Integer.class).getBody(); }
--------------------
请求合并
在延时时间窗口10ms内,对同一个接口的多次请求合并成一个请求,底层是通过将多个请求的参数进行合并,变成一个请求,只占用线程池中的一条线程,前提是被调用服务要提供批量查询接口,比如getAll(List<Stirng> ids)
接收到回复后再做拆分响应给不同的请求
手写合并命令稍微麻烦点,要同时实现具体命令和合并器,参考P168
使用注解实现:
@HystrixCollapser(batchMethod = "findAll", collapserProperties = { @HystrixProperty(name = "timeDelayInMilliseconds", value = "100") }) @HystrixCommand public User find(Long id) { return null; } @HystrixCommand public List<User> findAll(List<Long> ids) { return restTemplate.getForEntity("http://hello-provider/users?ids={1}", List.class, StringUtils.join(ids, ",")) .getBody(); }
------------------
是否开启请求合并
请求合并有延迟时间窗,会造成请求延迟
1.若请求链路本身延迟较高,可开启请求合并,时间窗的10ms延迟可忽略不计了
2.若请求接口本身没什么并发量,不要开启
-------------------
仪表盘
引入turbine构建监控聚集服务,将多个服务节点的信息进行汇总监控
还可在turbine前加入MQ,先将服务发送的监控信息-》MQ-》turbine异步消费汇总-》DashBoard仪表盘展示
--------------------
整体流程:
请求接口-》创建命令HystrixCommand-》触发命令执行-》命令结果是否被缓存-》(是,直接返回缓存结果)否-》断路器是否打开-》(是,走服务降级处理)否-》线程池是否有资源-》(否,走服务降级逻辑)是-》HystrixCommand.run()真正开始执行命令处理逻辑,调用服务提供者-》(如果超时,走服务降级逻辑)-》断路器统计命令执行情况(成功、失败、超时、拒绝)-》断路器维护10s内的统计时间窗,在此时间窗内若统计数据同时满足一下两个条件则打开断路器: “错误百分比超过50%”&&"请求总数超过20"-》断路器有5s休眠时间,5s内断路器状态是打开,期间的命令请求全部走服务降级逻辑,5s后断路器状态是半开,允许新请求进来测试服务是否恢复正常,若命令执行成功则关闭断路器,若失败进入下一个5s睡眠期
------------------