美文网首页
Spring Cloud 熔断降级

Spring Cloud 熔断降级

作者: 二圈儿 | 来源:发表于2019-05-12 11:43 被阅读0次

1、 什么是熔断

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

2、 什么是降级

服务器当压力剧增的时候,根据当前业务情况及流量,对一些服务和页面进行有策略的降级。以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应。

3、熔断和降级异同

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

4、Netflix开源组件断路器Hystrix

文档地址:
https://github.com/Netflix/Hystrix

为什么用Hystrix

在一个分布式系统里,一个服务依赖多个服务,可能存在某个服务调用失败,比如超时、异常等,如何能够保证在一个依赖出问题的情况下,不会导致整体服务失败,通过Hystrix就可以解决。

Hystrix是如何实现它的目标的

(1)通过HystrixCommand或者HystrixObservableCommand来封装对外部依赖的访问请求,这个访问请求一般会运行在独立的线程中,资源隔离
(2)对于超出我们设定阈值的服务调用,直接进行超时,不允许其耗费过长时间阻塞住。这个超时时间默认是99.5%的访问时间,但是一般我们可以自己设置一下
(3)为每一个依赖服务维护一个独立的线程池,或者是semaphore,当线程池已满时,直接拒绝对这个服务的调用
(4)对依赖服务的调用的成功次数,失败次数,拒绝次数,超时次数,进行统计
(5)如果对一个依赖服务的调用失败次数超过了一定的阈值,自动进行熔断,在一定时间内对该服务的调用直接降级,一段时间后再自动尝试恢复
(6)当一个服务调用出现失败,被拒绝,超时,短路等异常情况时,自动调用fallback降级机制
(7)对属性和配置的修改提供近实时的支持

5、Hystrix实战

使用到的组件包括:Eureka、Feign包括以下三个项目:
(1)Eureka-server: 注册中心
(2)product-service :商品微服务
(3)order-service: 订单微服务
前面文章已经搭建过 这里不做赘述 这里只写order-service微服务
pom.xml 添加依赖

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

application.yml

server:
  port: 8781

#指定注册中心地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:7001/eureka/

#服务的名称
spring:
  application:
    name: order-service
    
#开启feign支持hystrix  (注意,一定要开启,旧版本默认支持,新版本默认关闭)
# #修改调用超时时间(默认是1秒就算超时)
feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 2000
#hystrix超时时间调整(默认是一秒)
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000

SpringBoot启动类

@SpringBootApplication
@EnableFeignClients
//添加熔断降级注解
@EnableCircuitBreaker
public class OrderServiceApplication {

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

}

ProductClient

/**
 * 商品服务客户端
 * name = "product-service"是你调用服务端名称
 * fallback = ProductClientFallback.class,后面是你自定义的降级处理类,降级类一定要实现ProductClient
 */
@FeignClient(name = "product-service",fallback = ProductClientFallback.class)
public interface ProductClient {

    //这样组合就相当于http://product-service/api/v1/product/find
    @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("ProductClientFallback中的降级方法");

        //这对gai该接口进行一些逻辑降级处理........
        return null;
    }
}

OrderController类
注意:fallbackMethod = "saveOrderFail"中的saveOrderFail方法中的参数类型,个数,顺序要和save一模一样,否则会报找不到saveOrderFail方法。

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

    @Autowired
    private ProductOrderService productOrderService;

    @RequestMapping("save")
    //当调用微服务出现异常会降级到saveOrderFail方法中
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){

        return productOrderService.save(userId, productId);
    }

    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId){

        System.out.println("controller中的降级方法");

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

测试

正常情况时如图: 订单服务调用商品服务正常

异常情况

此刻商品微服务停掉:只启动订单微服务,这时去调用商品服务当然会出现超时异常情况在调接口,发现已经成功到降级方法里 在看controller中的降级方法和ProductClientFallback降级方法的实现先后顺序,它们的顺序是不固定的,具体要看哪个线程先获得cpu执行权

6、结合redis模拟熔断降级服务异常报警通知实战

主要是完善服务熔断处理,报警机制完善结合redis进行模拟短信通知用户下单失败。
pom.xml

  <!--springboot整合redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

application.yml

#redis
spring:
  application:
    name: order-service
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    timeout: 2000

OrderController类
主要看降级方法的不同

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

    @Autowired
    private ProductOrderService productOrderService;

    //添加bean
    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestMapping("save")
    //当调用微服务出现异常会降级到saveOrderFail方法中
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId,HttpServletRequest request){

        return productOrderService.save(userId, productId);
    }

    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId, HttpServletRequest request){
        
        //监控报警
        String saveOrderKye = "save-order";
        //有数据代表20秒内已经发过
        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;
    }

}

测试

当20秒内连续发请求会提醒已发短信。

7、 Dashboard仪表盘监控

1、加入依赖

     <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>

2、启动类增加注解

   @EnableHystrixDashboard

3、配置文件增加endpoint

#新版本默认不暴露端点 改成暴露全部端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

4、访问入口

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

相关文章

网友评论

      本文标题:Spring Cloud 熔断降级

      本文链接:https://www.haomeiwen.com/subject/hiafaqtx.html