94-java-springcloud(07)-服务降级-HystrixHystrix Dashboard

    技术2022-07-12  73

    Hystrix

    一.简介

    1.官网

    参考官网: https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.2.3.RELEASE/reference/html/#circuit-breaker-spring-cloud-circuit-breaker-with-hystrix

    2.分布式微服务面临的问题?

    服务雪崩 某个或者某些服务出现故障,导致调用本服务的其他服务调用缓慢,或者调用失败,发生级联反应,从而导致多个服务不能使用,发生服务雪崩不能使用.

    3.Hystrix的作用

    在微服务之间作为断路器,保险丝使用,避免发生级联错误,从而保护服务,避免服务雪崩.

    (1)服务降级(出现错误怎么办?)

    #服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback. 可能出现服务降级的原因:

    程序运行异常超时服务熔断触发服务降级线程池/信号量打满也会导致服务降级
    (2)服务熔断(错误过多怎么办?)

    #类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示.

    总结: 就是单位时间内出现多少次错误;或者访问的错误比率达到多少就对外不提供服务;等过一段时间(时间窗口期)再次尝试提供服务.

    (3) 服务限流

    #秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

    二.代码使用

    1.基础使用

    1) 建module

    2) 改pom
    <!--新增hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
    3) 改yml
    生产者 则不需要配置什么,可能需要配置的就是暴露监控断点给hystrix dashboard. # 在被监控服务上添加暴露端点 management: endpoints: web: exposure: include: hystrix.stream 消费者 #如果消费者使用feign作为调用客户端的话,则需要开启hystrix;如果使用的是RestTemplate调用的话,以下yml配置不用配置. feign: hystrix: enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
    4) 主启动

    @EnableHystrix注解和@EnableCircuitBreaker随便使用一个就可以了.

    @SpringBootApplication @EnableFeignClients //以下两个注解随便使用一个就可以 @EnableHystrix //@EnableCircuitBreaker //启动服务熔断,使注解 @HystrixCommand生效 public class PaymentHystrixMain80 { public static void main(String[] args) { SpringApplication.run(PaymentHystrixMain80.class,args); } }

    @EnableHystrix注解 #@EnableHystrix注解就是@EnableCircuitBreaker的子类,并且和他一模一样 所以,以后我们使用@EnableHystrix就好.

    5) 业务类

    (1) 单独使用Hystrix(生产者和消费者均可) 在任何方法上都可以,一般是在controller类或者service类中使用.

    [1] 单独配置方法的熔断方法

    优点: 精确控制每个方法的服务降级 缺点: 1.每个方法都需要编写,服务降级方法,麻烦 2.服务降级方法和业务方法在一个类中,糅杂.

    //服务熔断 /** * 当id为正数的时候,访问正常 * 当id为负数的时候,进行服务降级. * 当请求的次数超过10次,并且请求的降级率为60%,则开启服务熔断. * 过一段时间,服务会再次尝试开启请求,检查是否能通过 */ @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { //fallbackMethod表示出现服务熔断调用的方法 @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间范围 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸 }) public String paymentCircuitBreaker(@PathVariable("id") Integer id){ if (id < 0){ throw new RuntimeException("*****id 不能负数"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber; } /** * 这是服务熔断之后,调用的方法 */ public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ return "id 不能负数,请稍候再试,(┬_┬)/~~ id: " +id; } [2] 给整个类配置熔断方法 类上用注解@DefaultProperties指明本类的默认熔断方法; 方法上用注解 @HystrixCommand 标明本方法需要开启服务降级.

    优点: 减少代码的编写 缺点: 业务代码和服务降级方法糅杂在一起,在一个类中.

    @RestController @Slf4j //这是Hystrix的注解,指定本类的默认的熔断执行方法是哪个. @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod") public class OrderHystrixController { .... /** * 服务降级的fallBackMethod方法调用的优先级: * 1.@HystrixCommand加上方法上指明fallbackMethod调用的fallback方法. * 2.@HystrixCommand只配置了本注解,使用类上@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")配置的方法 * 3.@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class) * 使用feign接口上配置的fallback类中对应的方法 */ @HystrixCommand //没有fallbackMethod这个属性,就表示使用全局服务降级方法, @GetMapping("/consumer/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_TimeOut(id); log.info("*******result:"+result); return result; } //下面是全局fallback方法 public String payment_Global_FallbackMethod(){ return "Global异常处理信息,请稍后再试,(┬_┬)"; } }

    (2) openFeign + Hystrix openFeign即可使用上述的两种方式,也可在feign客户端调用api接口的时候,使用服务降级.

    优点: 面向接口编程,服务降级方法和业务方法分离.

    第一步:feign调用interface类 feign调用的interface类,指明使用哪个类作为服务降级类. @Component //fallback标明,feign调用这个服务的时候,如果服务出现异常的服务降级类是哪个 @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class) public interface PaymentHystrixService { @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id); @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id); } 第二步:Hystrix服务降级实现类 /** * @author gl * @time 2020-06-18 22:26 * @function :Openfeign调用的服务降级类. * @step : */ @Component //需要实现feign调用的接口interface public class PaymentFallbackService implements PaymentHystrixService{ //对应feign调用方法中的paymentInfo_OK这个方法的降级方法. @Override public String paymentInfo_OK(Integer id) { return "-------PaymentFallbackService.paymentInfo_OK-----对方服务已宕机,请稍后重试"; } //对应feign调用方法中的paymentInfo_TimeOut这个方法的降级方法. @Override public String paymentInfo_TimeOut(Integer id) { return "-------PaymentFallbackService.paymentInfo_TimeOut-----对方服务已宕机,请稍后重试"; } }

    2.服务降级(程序规定时间获取不到结果,怎么办?)

    服务降级可能发生的地方

    程序运行异常超时服务熔断触发服务降级线程池/信号量打满也会导致服务降级

    其余代码省略,列举服务降级可能发生的地方.

    @Service public class PaymentService { /** * 成功的方法 */ public String paymentInfo_OK(Integer id){ return "线程池:"+Thread.currentThread().getName()+" paymentInfo_OK,id: "+id+"\t"+"哈哈哈" ; } /** * 服务降级 --出现错误 */ @HystrixCommand(fallbackMethod = "paymentInfo_handler" ,commandProperties = { //这个表示服务如果出现异常,执行哪个方法 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000") //3秒钟以内就是正常的业务逻辑 }) public String paymentInfo_Exception(Integer id){ //测试出现错误 int i= 10/0; return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"; } /** * 服务降级--超时 */ @HystrixCommand(fallbackMethod = "paymentInfo_handler" ,commandProperties = { //这个表示服务如果出现异常,执行哪个方法 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1000") //3秒钟以内就是正常的业务逻辑 }) public String paymentInfo_TimeOut(Integer id){ //测试超时 int timeNumber = 2; try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) { e.printStackTrace(); } return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber; } /** * 这是hystrix服务降级的回调方法. * @param id * @return */ public String paymentInfo_handler(Integer id){ return "线程池:"+Thread.currentThread().getName()+" paymentInfo_handler,当前方法超时或者出现错误,请稍后尝试id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"; } ..... }

    3.服务熔断(程序错误过多,怎么办?)

    一定时间周期内,错误效应次数达到多少次,则熔断即不再调用该服务,经过一定时间窗口期,再尝试去请求服务.一定时间周期内,当请求次数达到多少,错误比例达到多少,则熔断即不再调用该服务,经过一定时间窗口期,再次尝试去请求服务. //================服务熔断 //服务熔断 /** * 当id为正数的时候,访问正常 * 当id为负数的时候,进行服务降级. * 当请求的次数超过10次,并且请求的降级率为60%,则开启服务熔断. * 过一段时间,服务会再次尝试开启请求,检查是否能通过 */ @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { //fallbackMethod表示出现服务熔断调用的方法 @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间范围 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸 }) public String paymentCircuitBreaker(@PathVariable("id") Integer id){ if (id < 0){ throw new RuntimeException("*****id 不能负数"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber; } /** * 这是服务熔断之后,调用的方法 */ public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ return "id 不能负数,请稍候再试,(┬_┬)/~~ id: " +id; }

    4.@HystrixCommand 注解详解

    这个注解是Hystrix最重要的注解,关于这个注解的属性可以参考官网. 参考文章: https://github.com/Netflix/Hystrix/wiki/Configuration

    /** * This annotation used to specify some methods which should be processes as hystrix commands. */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface HystrixCommand { String groupKey() default ""; String commandKey() default ""; String threadPoolKey() default ""; String fallbackMethod() default ""; //定义熔断相关的属性配置.具体的属性参考官网 HystrixProperty[] commandProperties() default {}; //hystrix的线程池的配置,具体属性参考官网 HystrixProperty[] threadPoolProperties() default {}; //异常忽略 Class<? extends Throwable>[] ignoreExceptions() default {}; ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER; HystrixException[] raiseHystrixExceptions() default {}; String defaultFallback() default ""; }

    Hystrix Dashboard

    因为Hystrix Dashboard也是一个微服务,所以也需要搭建一个微服务模块,其实就有点类似于Eureka的server端一样的.

    1.dashboard的搭建

    (1) 建module 略 (2) 改pom

    <!--新增hystrix dashboard,这个会自动依赖导入web模块--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>

    (3) 写yml

    #配置端口号即可 server: port: 9001

    (4) 主启动 @EnableHystrixDashboard //启动HystrixDashboard

    @SpringBootApplication //启动HystrixDashboard @EnableHystrixDashboard public class HystrixDashboardMain9001 { public static void main(String[] args) { SpringApplication.run(HystrixDashboardMain9001.class,args); } }

    (5) 测试页面 根据你项目的端口号.访问如下路劲,出现如下页面即成功 http://localhost:9001/hystrix

    2.监控具体的项目

    (1).被监控的微服务都必须引入依赖

    <!--新增hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!--健康检查--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

    (2) 被监控的微服务必须暴露监控断点

    # 在被监控服务上添加暴露端点 management: endpoints: web: exposure: include: hystrix.stream

    (3) 在监控面板填写监控地址

    (4) 如果出现Unable to connect to Command Metric Stream 则在被监控的微服务中注入如下bean

    /** * 这是为了hystri dashboard监控仪表盘,而配置的bean * @return */ @Bean public ServletRegistrationBean getServlet(){ HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); registrationBean.setLoadOnStartup(1); registrationBean.addUrlMappings("/hystrix.stream"); registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; }

    3.监控面板说明

    总体就是7色,一线,一圈.

    7色:成功数/熔断数/错误请求/超时数/线程拒绝数/异常失败数/错误百分比1线:表示请求的变化图1圈:圈越大,qps越大,并发越大,颜色绿色表示正常运行,红色表示错误比例大.

    4.Turbine(监控多个微服务)

    上面的监控,我们只能监控单个微服务,我们可以利用turbine整合多个监控流,一次性监控多个微服务. 具体略.

    Processed: 0.012, SQL: 9