hystrix

234 阅读4分钟

分布式系统面临的问题

复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败。

服务雪崩

多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的"扇出"。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的"雪崩效应"。

对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和,比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性

断路器本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的 可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩

入门

加入依赖

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

启动类里添加注解

@SpringBootApplication
@EnableCircuitBreaker
public class HystrixApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixApplication.class, args);
    }
}

API接口编码实战

@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;
}
/**
 * 商品服务客户端
 */
@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
public interface ProductClient {
    @GetMapping("/api/v1/product/find")
    String findById(@RequestParam(value = "id") int id);
}
/**
 * 针对商品服务,错降级处理
 */
@Component
public class ProductClientFallback implements ProductClient {
    @Override
    public String findById(int id) {
        System.out.println("feign 调用product-service findbyid 异常");
        return null;
    }
}
feign:
  hystrix:
    enabled: true

熔断降级服务异常报警通知实战

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    timeout: 2000
@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;
}

高级篇幅之深入源码剖析Hystrix降级策略和调整

查看默认讲解策略 HystrixCommandProperties

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

2)execution.isolation.thread.timeoutInMilliseconds  超时时间
		默认 1000毫秒

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

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

断路器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>

启动类添加注解

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrixDashboard
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
#暴露全部的监控信息
management:
  endpoints:
    web:
      exposure:
        include: "*"

访问入口 http://localhost:8781/hystrix

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

参考资料

断路器监控仪表参数讲解和模拟熔断

简介:讲解 断路器监控仪表盘参数和模拟熔断

1、sse  server-send-event推送到前端

资料:https://github.com/Netflix/Hystrix/wiki/Dashboard