第四篇:架构服务降级熔断 Hystrix 实战

核心知识降级、熔断概念

  1. 熔断:
    为了防止整个系统故障的服务保护机制。
    例如:下单时,订单服务需要调用商品服务和用户服务,如果用户服务由于一些特殊原因服务挂了,导致订单服务调用了好几次都没有正常响应,那么在指定时间内的请求到达了一个阈值时,就会触发 Hystrix 的熔断机制,不再调用用户服务防止请求过多,导致大部分请求堵塞,造成系统崩溃,也可以说是服务雪崩。
  2. 降级:
    服务器负载过高时,抛弃一些非核心的接口与数据,响应回客户端。
    例如:双十一天猫负载过高,用户下单时需要调用商品的许多信息,那么这时候就会触发降级,将商品推荐、用户评价一些非核心的数据抛弃不再调用,而调用库存、价格等核心的数据,从而达到正常响应客户端,给用户一个友好的回复。
  3. 熔断和降级的相同点:
    都是从高可用、可靠性的角度出发防止系统崩溃。

为什么要用 Hystrix?

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

Hystrix 开发实战

1.pom.xml 添加Hystrix依赖

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

2.在 order-service 服务的主程序入口添加 @EnableCircuitBreaker 注解,开启Hystrix断路由,当然也可以使用 @SpringCloudApplication 代替 @SpringBootApplication 和 @EnableCircuitBreaker

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class OrderServiceApplication {

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

3.改造 order-service 订单服务的 controller 控制层接口

@RestController
@RequestMapping(value = "/api/v2/order")
public class OrderController {

    @Autowired
    private ProductOrderService productOrderService;

    @RequestMapping(value = "save")
    //指定出错后执行的方法
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id") int userId, @RequestParam("product_id") int productId){
        return productOrderService.save(userId, productId);
    }

    /**
     * 出错执行该方法
     * 注意这里的参数要与api方法save()参数一致
     *  @author: 药岩
     *  @Date: 2020/3/24 21:37
     *  @Description:
     */
    public Object saveOrderFail(int userId, int productId){
        Map<String, Object> map = new HashMap<>();
        map.put("code", 500);
        map.put("message", "当前下单人数过多,请稍后再试!");
        map.put("data", new int[0]);
        return map;
    }
}

4.启动 eureka_server 项目和 order-service 项目,product-service 不启动。
浏览器访问:
http://localhost:8781/api/v2/order/save?user_id=1&product_id=3
在这里插入图片描述

Hystrix 结合 feign 使用

  1. application.yml 开启 feign 对 Hystrix 的支持
feign:
  hystrix:
    enabled: true #开启Hystrix,旧版本默认开启,新版本默认关闭
  1. 我们可以点击这个 @FeignClient 注解,看一下它的源码。
// feign 客户端,指定商品服务名
@FeignClient(name = "product-service")
public interface ProductClient {

    /**
     * 这里指定调用的product-service 商品服务的URL接口
     * @author
     * @param id
     * @return
     */
    @GetMapping(value = "/api/v1/product/find")
    String findById(@RequestParam(value = "id") int id);
}

可以看到有一个fallback,注释说,自定义一个class,然后这个class必须实现被@FeignClient注释标记的接口,这里也就是ProductClient ,并且被spring当成bean扫描。
在这里插入图片描述
创建一个包名为 fallback,编写一个ProductClientFallback并且实现ProductClient接口

/**
 * 针对商品服务降级处理
 *  @author: 药岩
 *  @Date: 2020/3/24 22:58
 *  @Description:
 */
@Component
public class ProductClientFallback implements ProductClient {
    @Override
    public String findById(int id) {
    	System.out.println("feign结合Hystrix调用...");
        return null;
    }
}

在 feign 的客户端指定降级处理的fallback类

// feign 客户端,指定商品服务名
@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
public interface ProductClient {

    /**
     * 这里指定调用的product-service 商品服务的URL接口
     * @author
     * @param id
     * @return
     */
    @GetMapping(value = "/api/v1/product/find")
    String findById(@RequestParam(value = "id") int id);
}

启动 eureka-serve 注册中心和order-service服务,暂时不用启动 product-service。
访问浏览器:
http://localhost:8781/api/v2/order/save?user_id=1&product_id=3
在这里插入图片描述
控制台:

2020-03-25 20:50:41.997  INFO 10824 --- [oduct-service-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client product-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=product-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@55b80263
feign结合Hystrix调用...
2020-03-25 20:52:53.629  INFO 10824 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration
2020-03-25 20:57:53.633  INFO 10824 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration

这里可以看到方法已经走了 Hystrix 的降级处理。
思路:
首先客户端访问了 order-service 的 /api/v2/order/save 接口,但该接口已经标记了@HystrixCommand(fallbackMethod = “saveOrderFail”) 注解,出错会交给saveOrderFail()方法处理,到了service层的 save() 方法,这里通过 feign 接口去调用了 product-service 服务的接口取数据,这个feign接口标记了@FeignClient(name = “product-service”, fallback = ProductClientFallback.class),如果 product-service 商品服务调不通无响应就会交给ProductClientFallback处理,但是 product-service 商品服务没有启动,所以 ProductClientFallback 处理了并在控制台打印了,最后将异常抛给了最外层的saveOrderFail()方法处理。

熔断服务降级报警通知

在熔断降级的时候是需要及时处理的,这样子才能保证线上的平稳运行,所以我们这边设计在项目出现问题时,设定一个短信通知来进行进行报警通知。
在这里插入图片描述

  1. pom 添加 Redis 的依赖
server:
  port: 8781

spring:
  application:
    name: order-service
  redis:
    database: 0
    host: 115.29.149.49
    port: 6379
    timeout: 1000

#指定注册中心
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

#自定义负载均衡策略
product-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

feign:
  hystrix:
    enabled: true #开启Hystrix,旧版本默认开启,新版本默认关闭
  1. 在 order-service 订单服务的 OrderController 中的指定出错执行的方法 @HystrixCommand(fallbackMethod = “saveOrderFail”) 上做业务处理,当系统出错降级处理时,执行 saveOrderFail 方法进行短信通知。
    2.1 :先查询 redis 里面是否有发送短信的标识,如果有则不再继续发送,如果没有那就发送并且在 redis 里面存入发送标识,设置2分钟后过期(为了模拟所以把时间设置短一点,实际开发需要设置长一点)。
    2.2:通过线程开启异步处理,防止堵塞。
    2.3:如果并发量很大的时候,需要考虑使用 redis 的锁进行处理,防止重复发送(后续再考虑处理这个)。
    2.4:由于这边没有短信提供商,所以只能通过打印进行模拟短信发送。
 /**
     * 出错执行该方法
     * 注意这里的参数要与api方法save()参数一致
     *  @author: devin
     *  @Date: 2020/3/24 21:37
     *  @Description:
     */
    public Object saveOrderFail(int userId, int productId){

        String orderValue = redisTemplate.opsForValue().get("order-save");
        new Thread(() -> {
             if (StringUtils.isNotBlank(orderValue)){
                 System.out.println("已经发送过了,不再重复发送");
             }else {
                 redisTemplate.opsForValue().set("order-save", UUID.randomUUID().toString(), 2, TimeUnit.SECONDS);
                 System.out.println("系统异常,下单失败,开始发送信息,2分钟后过期,请处理");
             }
        }).start();

        Map<String, Object> map = new HashMap<>();
        map.put("code", 500);
        map.put("message", "当前下单人数过多,请稍后再试!");
        map.put("data", new int[0]);
        return map;
    }
  1. 启动 eureka-server 服务和 order-service 服务,product-service先不启动,模拟 Hystrix 降级处理。
  2. 浏览器访问:http://localhost:8781/api/v2/order/save?user_id=1&product_id=3
    在这里插入图片描述
  3. 控制台打印
2020-03-30 22:06:26.415  INFO 5252 --- [ HystrixTimer-1] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
系统异常,下单失败,开始发送信息,2分钟后过期,请处理
feign结合Hystrix调用...
已经发送过了,不再重复发送
feign结合Hystrix调用...
已经发送过了,不再重复发送
feign结合Hystrix调用...
系统异常,下单失败,开始发送信息,2分钟后过期,请处理
2020-03-30 22:10:29.881  INFO 5252 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration

Hystrix 降级策略调整

1.自定义 Hystrix 的超时时间

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

仪表盘监控 Dashboard

1.添加仪表盘依赖

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

2.启动类添加仪表盘注解

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker

@EnableHystrixDashboard
public class OrderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值