SpringCloud之服务容错保护

本文详细介绍了Spring Cloud中的Hystrix组件如何实现服务隔离、降级、熔断,包括创建Hystrix模块、配置参数、服务缓存和常见配置。通过实例演示了如何在微服务架构中有效地应对故障并提升系统稳定性。
摘要由CSDN通过智能技术生成

SpringCloud各组件作用及使用

Hystrix 简介

在微服务架构中,服务与服务之间通过远程调用的方式进行通信,一旦某个被调用的服务发生了故障,其依赖服务也会发生故障,此时就会发生故障的蔓延,最终导致系统瘫痪。Hystrix实现了断路器模式,当某个服务发生故障时,通过断路器的监控,给调用方返回一个错误响应,而不是长时间的等待,这样就不会使得调用方由于长时间得不到响应而占用线程,从而防止故障的蔓延。Hystrix具备服务降级、服务熔断、线程隔离、请求缓存、请求合并及服务监控等强大功能。

创建一个hystrix-service模块

  • 在pom.xml中添加相关依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.10.RELEASE</version>
        </dependency>
  • 在application.yml进行配置
server:
  port: 8401
spring:
  application:
    name: hystrix-service
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
service-url:
  user-service: http://user-service
  • 在启动类上添加@EnableHystrix来开启Hystrix的断路器功能,并且将RestTemplate注入
@EnableDiscoveryClient
@EnableHystrix
@SpringBootApplication
public class HystrixServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(HystrixServiceApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
  • 创建UserHystrixController接口用于调用user-service服务
@RestController
@RequestMapping("/user")
public class UserHystrixController {
    @Autowired
    private UserService userService;

    @GetMapping("/testFallback/{id}")
    public CommonResult testFallback(@PathVariable Long id) {
        return userService.getUser(id);
    }
}
  • 在UserService中添加调用方法与服务降级方法,方法上需要添加@HystrixCommand注解:
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private RestTemplate restTemplate;
    @Value("${service-url.user-service}")
    private String userServiceUrl;

    @Override
    @HystrixCommand(fallbackMethod = "getDefaultUser")
    public CommonResult getUser(Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/"+id, CommonResult.class, id);
    }

    public CommonResult getDefaultUser(@PathVariable Long id) {
        User defaultUser = new User(-1L, "defaultUser", "123456");
        return new CommonResult<>(defaultUser);
    }
}
  • 启动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 CommonResult testCommand(@PathVariable Long id) {
        return userService.getUserCommand(id);
    }
  • 在UserService中添加方式实现功能:
    @Override
    @HystrixCommand(fallbackMethod = "getDefaultUser",
            commandKey = "getUserCommand",
            groupKey = "getUserGroup",
            threadPoolKey = "getUserThreadPool")
    public CommonResult getUserCommand(@PathVariable Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }
使用ignoreExceptions忽略某些异常降级
  • 在UserHystrixController中添加测试接口:
    @GetMapping("/testException/{id}")
    public CommonResult testException(@PathVariable Long id) {
        return userService.getUserException(id);
    }
  • 在UserService中添加实现方法,这里忽略了NullPointerException,当id为1时抛出IndexOutOfBoundsException,id为2时抛出NullPointerException:
@Override
    @HystrixCommand(fallbackMethod = "getDefaultUser2", ignoreExceptions = {NullPointerException.class})
    public CommonResult getUserException(Long id) {
        if (id == 1) {
            throw new IndexOutOfBoundsException();
        } else if (id == 2) {
            throw new NullPointerException();
        }
        return restTemplate.getForObject(userServiceUrl + "/user/"+id, CommonResult.class, id);
    }
    public CommonResult getDefaultUser2(@PathVariable Long id, Throwable e) {
        //LOGGER.error("getDefaultUser2 id:{},throwable class:{}", id, e.getClass());
        User defaultUser = new User(-2L, "defaultUser2", "123456");
        return new CommonResult<>(defaultUser);
    }
  • 调用接口进行测试:http://localhost:8401/user/testException/1
    在这里插入图片描述
    这里id等于1,异常被处理,服务降级。
  • 调用接口http://localhost:8401/user/testException/1

在这里插入图片描述
异常被忽略,不发生服务降级。

Hystrix的请求缓存

当系统并发量越来越大时,我们需要使用缓存来优化系统,达到减轻并发请求线程数,提供响应速度的效果。
注:Hystrix的缓存,这个功能是有点鸡肋的,因为这个缓存是基于request的,为什么这么说呢?因为每次请求来之前都必须HystrixRequestContext.initializeContext();进行初始化,每请求一次controller就会走一次filter,上下文又会初始化一次,前面缓存的就失效了,又得重新来。所以如果想测试缓存,需要在一次controller请求中多次调用加了缓存的service或HystrixCommand命令。Hystrix的书上写的是:在同一用户请求的上下文中,相同依赖服务的返回数据始终保持一致。在当次请求内对同一个依赖进行重复调用,只会真实调用一次。在当次请求内数据可以保证一致性。

相关注解
  • @CacheResult:开启缓存,默认所有参数作为缓存的key,cacheKeyMethod可以通过返回String类型的方法指定key;
  • @CacheKey:指定缓存的key,可以指定参数或指定参数中的属性值为缓存key,cacheKeyMethod还可以通过返回String类型的方法指定;
  • @CacheRemove:移除缓存,需要指定commandKey。
测试使用缓存
  • 在UserHystrixController中添加使用缓存的测试接口,直接调用三次getUserCache方法:
    @GetMapping("/testCache/{id}")
    public CommonResult testCache(@PathVariable Long id) {
        userService.getUserCache(id);
        userService.getUserCache(id);
        userService.getUserCache(id);
        return new CommonResult("操作成功", 200);
    }
  • 在UserService中添加具有缓存功能的getUserCache方法:@CacheResult注解要和@HystrixCommand注解搭配使用。
    @Override
    @CacheResult(cacheKeyMethod = "getCacheKey")
    @HystrixCommand(fallbackMethod = "getDefaultUser", commandKey = "getUserCache")
    public CommonResult getUserCache(Long id) {
        System.out.println("getUserCache被调用");
        return restTemplate.getForObject(userServiceUrl + "/user/" + id, CommonResult.class, id);
    }
  • 编写为缓存生成key的方法
    public String getCacheKey(Long id) {
        return String.valueOf(id);
    }
  • 运行Eureka、user、Hystrix服务,访问http://localhost:8401/user/testCache/1,看到只打印一次,说明另外两次走的是缓存方法。
    在这里插入图片描述
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:
      maxRequestsInBatch: 100 #控制一次合并请求合并的最大请求数
      timerDelayinMilliseconds: 10 #控制多少毫秒内的请求会被合并成一个
      requestCache:
        enabled: true #控制合并请求是否开启缓存
  threadpool: #用于控制HystrixCommand执行所在线程池的行为
    default:
      coreSize: 10 #线程池的核心线程数
      maximumSize: 10 #线程池的最大线程数,超过该线程数的请求会被拒绝
      maxQueueSize: -1 #用于设置线程池的最大队列大小,-1采用SynchronousQueue,其他正数采用LinkedBlockingQueue
      queueSizeRejectionThreshold: 5 #用于设置线程池队列的拒绝阀值,由于LinkedBlockingQueue不能动态改版大小,使用时需要用该参数来控制线程数
实例配置
hystrix:
  command:
    HystrixComandKey: #将default换成HystrixComrnandKey
      execution:
        isolation:
          strategy: THREAD
  collapser:
    HystrixCollapserKey: #将default换成HystrixCollapserKey
      maxRequestsInBatch: 100
  threadpool:
    HystrixThreadPoolKey: #将default换成HystrixThreadPoolKey
      coreSize: 10
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IDEA上的操作工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值