Spring Cloud入门-Hystrix断路器(Hoxton版本)

本文详细解读了一线大厂Java面试中关于Hystrix框架的实践应用,包括服务降级策略、请求缓存、信号量隔离、CircuitBreaker和请求合并技术,以及实战项目源码分析。
摘要由CSDN通过智能技术生成

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

此处省略了创建用户类User和统一返回前端的响应类Result,RestTemplate配置,UserService接口的创建,具体的可以参考项目源码

@RestController

@RequestMapping(“/user”)

public class UserHystrixController {

@Autowired

private UserService userService;

@GetMapping(“/testFallback/{id}”)

public Result testFallback(@PathVariable Long id) {

return userService.getUser(id);

}

@GetMapping(“/testException/{id}”)

public Result testException(@PathVariable Long id) {

return userService.getUserException(id);

}

@GetMapping(“/testCommand/{id}”)

public Result getUserCommand(@PathVariable Long id) {

return userService.getUserCommand(id);

}

@GetMapping(“/testCache/{id}”)

public Result testCache(@PathVariable Long id) {

userService.getUserCache(id);

userService.getUserCache(id);

userService.getUserCache(id);

return new Result(“操作成功”, 200);

}

@GetMapping(“/testRemoveCache/{id}”)

public Result testRemoveCache(@PathVariable Long id) {

userService.getUserCache(id);

userService.removeCache(id);

userService.getUserCache(id);

return new Result(“操作成功”, 200);

}

@GetMapping(“/testCollapser”)

public Result testCollapser() throws ExecutionException, InterruptedException {

Future future1 = userService.getUserFuture(1L);

Future future2 = userService.getUserFuture(2L);

future1.get();

future2.get();

ThreadUtil.safeSleep(200);

Future future3 = userService.getUserFuture(3L);

future3.get();

return new Result(“操作成功”, 200);

}

}

服务降级演示


在UserHystrixController中添加用于测试服务降级的接口:

@GetMapping(“/testFallback/{id}”)

public Result testFallback(@PathVariable Long id) {

return userService.getUser(id);

}

在UserService中添加调用方法与服务降级方法,方法上需要添加@HystrixCommand注解:

@HystrixCommand(fallbackMethod = “fallbackMethod1”)

public Result getUser(Long id) {

return restTemplate.getForObject(userServiceUrl + “/user/{1}”, Result.class, id);

}

/**

  • 声明的参数需要包含controller的声明参数

  • @param id

  • @return

*/

public Result fallbackMethod1(@PathVariable Long id) {

return new Result(“服务调用失败”, 500);

}

启动eureka-server、user-service、hystrix-service服务

在这里插入图片描述

调用接口进行测试:http://localhost:8401/user/testFallback/1

在这里插入图片描述

关闭user-service服务重新测试该接口,发现已经发生了服务降级:

在这里插入图片描述

@HystrixCommand详解


@HystrixCommand中的常用参数

  • fallbackMethod:指定服务降级处理方法;

  • ignoreExceptions:忽略某些异常,不发生服务降级;

  • commandKey:命令名称,用于区分不同的命令;

  • groupKey:分组名称,Hystrix会根据不同的分组来统计命令的告警及仪表盘信息;

  • threadPoolKey:线程池名称,用于划分线程池。

设置命令、分组及线程池名称

在UserHystrixController中添加测试接口:

@GetMapping(“/testCommand/{id}”)

public Result getUserCommand(@PathVariable Long id) {

return userService.getUserCommand(id);

}

在UserService中添加方式实现功能:

@HystrixCommand(fallbackMethod = “fallbackMethod1”,

commandKey = “getUserCommand”,

groupKey = “getUserGroup”,

threadPoolKey = “getUserThreadPool”)

public Result getUserCommand(Long id) {

return restTemplate.getForObject(userServiceUrl + “/user/{1}”, Result.class, id);

}

使用ignoreExceptions忽略某些异常降级

在UserHystrixController中添加测试接口:

@GetMapping(“/testException/{id}”)

public Result testException(@PathVariable Long id) {

return userService.getUserException(id);

}

在UserService中添加实现方法,这里忽略了NullPointerException,当id为1时抛出IndexOutOfBoundsException,id为2时抛出NullPointerException:

@HystrixCommand(fallbackMethod = “fallbackMethod2”, ignoreExceptions = {NullPointerException.class})

public Result getUserException(Long id) {

if (id == 1) {

throw new IndexOutOfBoundsException();

} else if (id == 2) {

throw new NullPointerException();

}

return restTemplate.getForObject(userServiceUrl + “/user/{1}”, Result.class, id);

}

public Result fallbackMethod2(@PathVariable Long id, Throwable e) {

LOGGER.error(“id {},throwable class:{}”, id, e.getClass());

return new Result(“服务调用失败”, 500);

}

调用接口进行测试:http://localhost:8401/user/tesException/1

在这里插入图片描述

调用接口进行测试:http://localhost:8401/user/tesException/2

在这里插入图片描述

Hystrix的请求缓存


当系统并发量越来越大时,我们需要使用缓存来优化系统,达到减轻并发请求线程数,提供响应速度的效果。

相关注解

  • @CacheResult:开启缓存,默认所有参数作为缓存的key,cacheKeyMethod可以通过返回String类型的方法指定key;

  • @CacheKey:指定缓存的key,可以指定参数或指定参数中的属性值为缓存key,cacheKeyMethod还可以通过返回String类型的方法指定;

  • @CacheRemove:移除缓存,需要指定commandKey。

测试使用缓存

在UserHystrixController中添加使用缓存的测试接口,直接调用三次getUserCache方法:

@GetMapping(“/testCache/{id}”)

public Result testCache(@PathVariable Long id) {

userService.getUserCache(id);

userService.getUserCache(id);

userService.getUserCache(id);

return new Result(“操作成功”, 200);

}

在UserService中添加具有缓存功能的getUserCache方法:

@CacheResult(cacheKeyMethod = “getCacheKey”)

@HystrixCommand(fallbackMethod = “fallbackMethod1”, commandKey = “getUserCache”)

public Result getUserCache(Long id) {

LOGGER.info(“getUserCache id:{}”, id);

return restTemplate.getForObject(userServiceUrl + “/user/{1}”, Result.class, id);

}

/**

  • 为缓存生成key的方法

  • @return

*/

public String getCacheKey(Long id) {

return String.valueOf(id);

}

调用接口测试http://localhost:8401/user/testCache/1,这个接口中调用了三次getUserCache方法,但是只打印了一次日志,说明有两次走的是缓存:

在这里插入图片描述

测试移除缓存

在UserHystrixController中添加移除缓存的测试接口,调用一次removeCache方法:

@GetMapping(“/testRemoveCache/{id}”)

public Result testRemoveCache(@PathVariable Long id) {

userService.getUserCache(id);

userService.removeCache(id);

userService.getUserCache(id);

return new Result(“操作成功”, 200);

}

在UserService中添加具有移除缓存功能的removeCache方法:

@HystrixCommand

@CacheRemove(commandKey = “getUserCache”, cacheKeyMethod = “getCacheKey”)

public Result removeCache(Long id) {

LOGGER.info(“removeCache id:{}”, id);

return restTemplate.postForObject(userServiceUrl + “/user/delete/{1}”, null, Result.class, id);

}

调用接口测试http://localhost:8401/user/testRemoveCache/1,可以发现有两次查询都走的是接口:

在这里插入图片描述

缓存使用过程中的问题

在缓存使用过程中,我们需要在每次使用缓存的请求前后对HystrixRequestContext进行初始化和关闭,否则会出现如下异常:

java.lang.IllegalStateException: Request caching is not available. Maybe you need to initialize the HystrixRequestContext?

at com.netflix.hystrix.HystrixRequestCache.get(HystrixRequestCache.java:104) ~[hystrix-core-1.5.18.jar:1.5.18]

at com.netflix.hystrix.AbstractCommand$7.call(AbstractCommand.java:478) ~[hystrix-core-1.5.18.jar:1.5.18]

at com.netflix.hystrix.AbstractCommand$7.call(AbstractCommand.java:454) ~[hystrix-core-1.5.18.jar:1.5.18]

这里我们通过使用过滤器,在每个请求前后初始化和关闭HystrixRequestContext来解决该问题:

@Component

@WebFilter(urlPatterns = “/*”, asyncSupported = true)

public class HystrixRequestContextFilter implements Filter {

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

HystrixRequestContext context = HystrixRequestContext.initializeContext();

try {

filterChain.doFilter(servletRequest, servletResponse);

} finally {

context.close();

}

}

}

请求合并


微服务系统中的服务间通信,需要通过远程调用来实现,随着调用次数越来越多,占用线程资源也会越来越多。Hystrix中提供了@HystrixCollapser用于合并请求,从而达到减少通信消耗及线程数量的效果。

@HystrixCollapser的常用属性

  • batchMethod:用于设置请求合并的方法;

  • collapserProperties:请求合并属性,用于控制实例属性,有很多;

  • timerDelayInMilliseconds:collapserProperties中的属性,用于控制每隔多少时间合并一次请求;

功能演示

在UserHystrixController中添加testCollapser方法,这里我们先进行两次服务调用,再间隔200ms以后进行第三次服务调用:

@GetMapping(“/testCollapser”)

public Result testCollapser() throws ExecutionException, InterruptedException {

Future future1 = userService.getUserFuture(1L);

Future future2 = userService.getUserFuture(2L);

future1.get();

future2.get();

ThreadUtil.safeSleep(200);

Future future3 = userService.getUserFuture(3L);

future3.get();

return new Result(“操作成功”, 200);

}

使用@HystrixCollapser实现请求合并,所有对getUserFuture的的多次调用都会转化为对getUserByIds的单次调用:

@HystrixCollapser(batchMethod = “listUsersByIds”,collapserProperties = {

@HystrixProperty(name = “timerDelayInMilliseconds”,value = “100”)

})

public Future getUserFuture(Long id) {

return new AsyncResult() {

@Override

public User invoke() {

Result result = restTemplate.getForObject(userServiceUrl + “/user/{1}”, Result.class, id);

Map data = (Map) result.getData();

User user = BeanUtil.mapToBean(data, User.class, true);

LOGGER.info(“getUserById username:{}”,user.getUsername());

return user;

}

};

}

@HystrixCommand

public List listUsersByIds(List ids) {

LOGGER.info(“listUsersByIds:{}”,ids);

Result result = restTemplate.getForObject(userServiceUrl + “/user/listUsersByIds?ids={1}”, Result.class, CollUtil.join(ids, “,”));

return (List)result.getData();

}

注意:测试之前需要重启user-service服务,因为刚才测试请求缓存把数据删了一个,不然会报错

访问接口测试http://localhost:8401/user/testCollapser,由于我们设置了100毫秒进行一次请求合并,前两次被合并,最后一次自己单独合并了。

在这里插入图片描述

Hystrix的常用配置


全局配置

hystrix:

command: #用于控制HystrixCommand的行为

default:

execution:

isolation:

strategy: THREAD #控制HystrixCommand的隔离策略,THREAD->线程池隔离策略(默认),SEMAPHORE->信号量隔离策略

thread:

timeoutInMilliseconds: 1000 #配置HystrixCommand执行的超时时间,执行超过该时间会进行服务降级处理

interruptOnTimeout: true #配置HystrixCommand执行超时的时候是否要中断

interruptOnCancel: true #配置HystrixCommand执行被取消的时候是否要中断

timeout:

enabled: true #配置HystrixCommand的执行是否启用超时时间

semaphore:

maxConcurrentRequests: 10 #当使用信号量隔离策略时,用来控制并发量的大小,超过该并发量的请求会被拒绝

fallback:

enabled: true #用于控制是否启用服务降级

circuitBreaker: #用于控制HystrixCircuitBreaker的行为

enabled: true #用于控制断路器是否跟踪健康状况以及熔断请求

requestVolumeThreshold: 20 #超过该请求数的请求会被拒绝

forceOpen: false #强制打开断路器,拒绝所有请求

forceClosed: false #强制关闭断路器,接收所有请求

requestCache:

enabled: true #用于控制是否开启请求缓存

collapser: #用于控制HystrixCollapser的执行行为

default:

总结

在这里,由于面试中MySQL问的比较多,因此也就在此以MySQL为例为大家总结分享。但是你要学习的往往不止这一点,还有一些主流框架的使用,Spring源码的学习,Mybatis源码的学习等等都是需要掌握的,我也把这些知识点都整理起来了

面试真题

Spring源码笔记

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
true #配置HystrixCommand的执行是否启用超时时间

semaphore:

maxConcurrentRequests: 10 #当使用信号量隔离策略时,用来控制并发量的大小,超过该并发量的请求会被拒绝

fallback:

enabled: true #用于控制是否启用服务降级

circuitBreaker: #用于控制HystrixCircuitBreaker的行为

enabled: true #用于控制断路器是否跟踪健康状况以及熔断请求

requestVolumeThreshold: 20 #超过该请求数的请求会被拒绝

forceOpen: false #强制打开断路器,拒绝所有请求

forceClosed: false #强制关闭断路器,接收所有请求

requestCache:

enabled: true #用于控制是否开启请求缓存

collapser: #用于控制HystrixCollapser的执行行为

default:

总结

在这里,由于面试中MySQL问的比较多,因此也就在此以MySQL为例为大家总结分享。但是你要学习的往往不止这一点,还有一些主流框架的使用,Spring源码的学习,Mybatis源码的学习等等都是需要掌握的,我也把这些知识点都整理起来了

[外链图片转存中…(img-LglzQ19J-1714751159044)]

[外链图片转存中…(img-AR5YJxKP-1714751159044)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值