一、熔断与降级

1.1 为什么需要熔断与降级

1.1.1 需求背景

它是系统负载过高,突发流量或者网络等各种异常情况常用的解决方案。
在一个分布式系统里,一个服务依赖多个服务,可能存在某个服务调用失败,比如超时异常等,如何能够保证在一个依赖出问题的情况下,不会导致整体服务失败。
比如:某微服务业务逻辑复杂,在高负载情况下出现超时情况。
内部条件:程序bug导致死循环、存在慢查询、程序逻辑不对导致耗尽内存
外部条件:黑客攻击、促销、第三方系统响应缓慢。

1.1.2 解决思路

解决接口级故障的核心思想是优先保障核心业务和优先保障绝大部分用户。比如登录功能很重要,当访问量过高时,停掉注册功能,为登录腾出资源。

1.1.3 解决策略

熔断降级,限流,排队。

1.2 熔断

一般是某个服务故障或者是异常引起的,类似现实世界中的‘保险丝’,当某个异常条件被触发,直接熔断整个服务,而不是一直等到此服务超时,为了防止整个系统的故障,而采用了一些保护措施。过载保护。
比如A服务的X功能依赖B服务的某个接口,当B服务接口响应很慢时,A服务X功能的响应也会被拖慢,进一步导致了A服务的线程都卡在了X功能上,A服务的其它功能也会卡主或拖慢。此时就需要熔断机制,即A服务不在请求B这个接口,而可以直接进行降级处理。

1.3 降级

服务器当压力剧增的时候,根据当前业务情况及流量,对一些服务和页面进行有策略的降级。以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应。
自动降级:超时、失败次数、故障、限流
(1)配置好超时时间(异步机制探测回复情况);
(2)不稳的的api调用次数达到一定数量进行降级(异步机制探测回复情况);
(3)调用的远程服务出现故障(dns、http服务错误状态码、网络故障、Rpc服务异常),直接进行降级。
人工降级:秒杀、双十一大促降级非重要的服务。

1.4 熔断与降级的异同

相同点:
1)从可用性和可靠性触发,为了防止系统崩溃
2)最终让用户体验到的是某些功能暂时不能用
不同点:
1)服务熔断一般是下游服务故障导致的,而服务降级一般是从整体系统负荷考虑,由调用方控制
2)触发原因不同,上面颜色字体已解释

二、熔断实战

1.1 项目环境

image.png
当order调用ticket-cinema中的服务,ticket-cinema服务中止时,调用熔断的方法

1.2 Order服务中

1.2.1 引入依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  4. </dependency>

1.2.2 启动类注解

启动类上添加注解:@EnableCircuitBreaker

  1. @EnableCircuitBreaker
  2. @EnableFeignClients
  3. @SpringBootApplication
  4. public class TicketOrderApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(TicketOrderApplication.class, args);
  7. }
  8. }

1.2.3 yml配置文件

  1. feign:
  2. hystrix:
  3. enabled: true

1.2.4 Service及其实现类

Schedule_seatService**:**

@FeignClient(name = "ticket-cinema",fallback = Schedule_seatServiceImpl.class)
public interface Schedule_seatService {

    @PostMapping("schedule_seat/findToOrderById")
    String findToOrderById(@RequestParam("id") int id);
}

Schedule_seatServiceImpl:

@Service
public class Schedule_seatServiceImpl implements Schedule_seatService {

    @Override
    public String findToOrderById(int id) {
        return "服务熔断处理";
    }

}

1.3 测试

1.3.1 服务开启时

控制台打印指定数据:
image.png

1.3.2 服务关闭时

image.png

三、降级实战

项目环境同上

1.1 Order服务中修改yml配置文件

feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 2000

1.2 Cinema服务中修改代码,使其休眠3S

@Api(tags = "排片-座位管理接口")
@RestController
@RequestMapping("/schedule_seat")
public class Schedule_seatController {

    @Resource
    private Schedule_seatService schedule_seatService;

    @ApiOperation("下订单时,通过排片-座位中间表返回信息,并锁定座位")
    @PostMapping("/findToOrderById")
    public String findToOrderById(@RequestParam("id") @Min(value = 1, message = "排片-座位中间表id至少为1") @NotNull(message = "排片-座位中间表id不能为空") int id) throws InterruptedException {
        //超时测试
        Thread.sleep(3000);
        return schedule_seatService.findToOrderById(id);
    }

}

1.3 测试

1.3.1 超时情况下

此时,休眠时间大于设置的时间 2S ,已经超时
image.png

1.3.2 未超时情况下

修改order服务的yml配置文件

feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 4000

image.png
打印了添加成功后的指定信息