Spring Cloud 核心组件——熔断降级

今天先来说说“服务熔断”和“服务降级”。

服务熔断:在股票市场,熔断这个词大家都不陌生,是指当股指波幅达到某个点后,交易所为控制风险采取的暂停交易措施。相应的,服务熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。

服务降级:大家都见过女生旅行吧,大号的旅行箱是必备物,平常走走近处绰绰有余,但一旦出个远门,再大的箱子都白搭了,怎么办呢?常见的情景就是把物品拿出来分分堆,比了又比,最后一些非必需品的就忍痛放下了,等到下次箱子够用了,再带上用一用。而服务降级,就是这么回事,整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。

所以从上述分析来看,两者其实从有些角度看是有一定的类似性的:

1)目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;

2)最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;

3)粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);

4)自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;

而两者的区别也是明显的:

1)触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;

2)管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)

3)实现方式不太一样

参考文章:https://blog.csdn.net/guwei9111986/article/details/51649240

 

下面介绍 Hystrix:

在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix 是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix 通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。

Hystrix 提供了熔断、隔离、Fallback、Cache、监控等功能。出现错误之后可以 fallback 错误的处理信息,返回一些兜底数据等等。

https://www.cnblogs.com/cjsblog/p/9391819.html

 

本文的示例承接上一篇文章:https://www.cnblogs.com/jwen1994/p/11408511.html

1. Feign 结合 Hystrix 断路器开发

第一步:加入依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

注意新旧版本问题,所以要以官网为主,不然部分注解会丢失

第二步:启动类里面增加注解 @EnableCircuitBreaker

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class OrderServiceApplication {

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

我们也可以使用 SpringCloudApplication 注解,它包含了很多 Spring Cloud 相关的注解

第三步:最外层 api 使用

api 方法上增加 @HystrixCommand(fallbackMethod = "saveOrderFail")。好比异常处理(网络异常,参数或者内部调用问题)

@RestController
@RequestMapping("api/v1/order")
public class OrderController {

    @Autowired
    private ProductOrderService productOrderService;

    @RequestMapping("save")
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){

        Map<String, Object> data = new HashMap<>();
        data.put("code", 0);
        data.put("data", productOrderService.save(userId, productId));
        return  data;
    }

    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId){
        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        return msg;
    }
}

注意:编写 fallback 方法实现,方法签名一定要和 api 方法签名一致

第四步:进行测试,我们使用一个会出错的请求,它会返回 saveOrderFail 的返回值

 

2. 我们调用服务时,如果服务出错,我们希望可以进行一些处理

 第一步:开启 Feign 支持 Hystrix (注意,一定要开启,旧版本默认支持,新版本默认关闭)

feign:
  hystrix:
    enabled: true

第二步:FeignClient(name="xxx", fallback=xxx.class ),class 需要继承当前 FeignClient 的类

@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
public interface ProductClient {
    @GetMapping("/api/v1/product/find")
    String findById(@RequestParam(value = "id") int id);
}

ProductClientFallback 类

@Component
public class ProductClientFallback implements ProductClient {
    @Override
    public String findById(int id) {
        System.out.println("feign 调用product-service findbyid 异常");
        return null;
    }
}

 

3. 进一步完善异常报警通知

我们可以试着加入 Redis 来实现一个异常报警

第一步:加入 Redis 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

第二步:配置 Redis 链接信息

spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    timeout: 2000

第三步:修改代码

@RestController
@RequestMapping("api/v1/order")
public class OrderController {
    @Autowired
    private ProductOrderService productOrderService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestMapping("save")
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId, HttpServletRequest request){

        Map<String, Object> data = new HashMap<>();
        data.put("code", 0);
        data.put("data", productOrderService.save(userId, productId));
        return  data;
    }

    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId, HttpServletRequest request){
        //监控报警
        String saveOrderKye = "save-order";

        String sendValue = redisTemplate.opsForValue().get(saveOrderKye);
        final String ip = request.getRemoteAddr();
        new Thread( ()->{
            if (StringUtils.isBlank(sendValue)) {
                System.out.println("紧急短信,用户下单失败,请离开查找原因,ip地址是="+ip);
                //发送一个http请求,调用短信服务 TODO
                redisTemplate.opsForValue().set(saveOrderKye, "save-order-fail", 20, TimeUnit.SECONDS);

            }else{
                System.out.println("已经发送过短信,20秒内不重复发送");
            }

        }).start();

        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        return msg;
    }
}

 

4. Hystrix 降级策略和调整

1)查看默认讲解策略 HystrixCommandProperties

这个文件里可以看到所有默认的策略

2)execution.isolation.strategy 隔离策略

Hystrix 有两种隔离策略:THREAD 线程池隔离 (默认)、SEMAPHORE 信号量。信号量适用于接口并发量高的情况,如每秒数千次调用的情况,导致的线程开销过高,通常只适用于非网络调用,执行速度快

3)execution.isolation.thread.timeoutInMilliseconds 超时时间

Hystrix 默认超时时间为1000毫秒

4)execution.timeout.enabled 是否开启超时限制 (一定不要禁用)

Hystrix 默认是开启超时限制的

5)execution.isolation.semaphore.maxConcurrentRequests 隔离策略为信号量的时候,如果达到最大并发数时,后续请求会被拒绝,默认是10

#把hystrix超时时间禁用
#hystrix:
#  command:
#    default:
#      execution:
#        timeout:
#          enabled: false

#execution.isolation.thread.timeoutInMilliseconds=4000

#设置超时时间
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000

官方文档:https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.strategy

5. 断路器 Dashboard 监控仪表盘

生产环境几乎不用,只要做好异常告警就可以

第一步:加入依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

第二步:启动类增加注解 @EnableHystrixDashboard

第三步:配置文件增加 endpoint

#暴露全部的监控信息
management:
  endpoints:
    web:
      exposure:
        include: "*"

第四步:访问入口

1)访问:http://localhost:8781/hystrix

2)Hystrix Dashboard 输入: http://localhost:8781/actuator/hystrix.stream

参考资料:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-security-actuator

 

 

补充: 如果从 Maven 中心仓库下载太慢,可是修改 Maven 仓库地址,使用其他 Maven 仓库。为了使用阿里云的仓库,我们在 pom.xml 中修改

<repositories>
  <repository>
    <id>nexus-aliyun</id>
    <name>Nexus aliyun</name>
    <layout>default</layout>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
    <releases>
      <enabled>true</enabled>
    </releases>
  </repository>
</repositories>

 

posted @ 2019-09-16 00:05  认真对待世界的小白  阅读(1387)  评论(0编辑  收藏  举报