SpringCloud-服务降级 Hystrix、降级、熔断、监控

文章目录
	服务降级
		Hystrix
			 	服务降级
		 			创建带降级机制的pay模块
					创建带降级的order模块
			 		配置服务降级
						修改pay模块
						修改order模块
						重复代码的问题
						代码耦合度的问题
				服务熔断
					继续修改pay模块
				总结补充
						Hystrix所有可配置的属性
						熔断整体流程
				服务监控
						HystrixDashboard

服务降级
		
		首先需要了解一个概念,服务雪崩:
		
		多个微服务之间调用时,假设微服务 A 调用微服务 B 和微服务 C,微服务 B 和微服务 C 又调用其它的微服务,这就是所谓的”扇出“。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务 A 的调用就会占用越来越多的系统资源,进而导致系统”雪崩效应“。

Hystrix

		Hystrix是一个用于处理分布式系统的延迟和容错的开源库,它能够保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障(雪崩)。

主要作用
		
		服务降级:比如当某个服务繁忙,不能让客户端的请求一直等待,应该立刻返回给客户端一个备选方案。
		服务熔断:当某个服务出现问题,卡死了,不能让用户一直等待,需要关闭所有对此服务的访问然后调用服务降级。
		服务限流:比如秒杀场景,不能访问用户瞬间都访问服务器,限制一次只可以有多少请求。
		接近实时的监控
		
Hystrix

	服务降级
	比如当某个服务繁忙,不能让客户端的请求一直等待,应该立刻返回给客户端一个备选方案。

出现降级的情况:
		
		程序运行异常
		超时
		发生服务熔断
		线程池/信号量打满
		创建带降级机制的pay模块

1 名称: cloud-provider-hystrix-payment8001

2 pom文件
		<!-- hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

3 配置文件,为了减少资源占用,这里使用单机版 Eureka
        server:
          port: 8001
        spring:
          application:
            name: cloud-provider-hystrix-payment

        eureka:
          client:
            register-with-eureka: true
            fetch-registry: true
            service-url:
              defaultZone: http://eureka7001.com:7001/eureka
              
4 主启动类
		@SpringBootApplication
		@EnableEurekaClient
		@EnableCircuitBreaker
	public class PaymentHystrixMain8001 {
    
    
	    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentHystrixMain8001.class,args);
    }
}


5 service,节约时间不写接口,直接上实现类
		@Service
        public class PaymentService {
    
    

            /*
            正确的方法
             */
            public String paymentInfo_OK(Integer id){
    
    
                return "线程池:"+Thread.currentThread().getName()+" paymentInfo_OK,id:"+id+"\t"+"???";
            }

            /*
            会超时报错的方法
             */
            public String paymentInfo_TimeOut(Integer id){
    
    
                int timeNumber = 5;
                try{
    
    
                    TimeUnit.SECONDS.sleep(timeNumber);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id:"+id+"\t"+"!!!";
            }
        }

6 Controller

		@RestController
        @Slf4j
        @RequestMapping("/payment")
        public class PaymentController {
    
    
            @Resource
            private PaymentService paymentService;
            @Value("${server.port}")
            private String serverPort;

            @GetMapping("/hystrix/ok/{id}")
            public String paymentInfo_OK(@PathVariable("id") Integer id){
    
    
                String result = paymentService.paymentInfo_OK(id);
                log.info("****result:"+result);
                return result;
            }

            @GetMapping("/hystrix/timeout/{id}")
            public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    
    
                String result = paymentService.paymentInfo_TimeOut(id);
                log.info("****result:"+result);
                return result;
            }
        }

7 启动项目,并发度低的情况下可以使用,我们使用 JMeter 并发2w个请求TimeOut接口,然后访问OK接口会发现也需要进行等待。这就是因为被压测的方法它占用了服务器大部分资源, 导致其他请求也变慢了。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200909144034529.png#pic_center)

1 创建带降级的order模块
   名字: cloud-consumer-feign-hystrix-order80

2 pom

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

3 配置文件

        server:
          port: 80

        eureka:
          client:
            register-with-eureka: false
            service-url:
              defaultZone: http://eureka7001.com:7001/eureka

4 主启动类

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

5 远程调用pay模块的接口

        @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
        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);
        }

6 controller:

        @RestController
        @Slf4j
        @RequestMapping("/consumer")
        public class OrderHystrixController {
    
    
            @Resource
            private PaymentHystrixService paymentHystrixService;

            @GetMapping("/payment/hystrix/ok/{id}")
            public String paymentInfo_OK(@PathVariable("id") Integer id){
    
    
                String result = paymentHystrixService.paymentInfo_OK(id);
                return result;
            }

            @GetMapping("/payment/hystrix/timeout/{id}")
            public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    
    
                String result = paymentHystrixService.paymentInfo_TimeOut(id);
                return result;
            }
        }

7 测试,启动order模块,再次压测2万并发pay模块的timeout接口,发现order访问也变慢了,没有配置Ribbon超时参数还会调用报错。
image-20200712180843334

在这里插入图片描述


原因

出现这种现象的原因是,8001的tomcat容器中线程池的工作线程被timeout接口挤占完毕,80此时调用8001中的ok接口就无法得到处理。

解决

8001超时/宕机:80不能一直等待,需要进行服务降级
8001没问题:80自己出故障或需要自己的等待时间小于服务提供者,则需要自己处理降级
配置服务降级
修改pay模块
1 为service会延迟的方法添加 @HystrixCommand 注解

        /*
        会超时报错的方法
         */
        @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
    
    
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    	})//设置调用超时时间的峰值,超时则会调用设置的paymentInfo_TimeOutHandler方法
        public String paymentInfo_TimeOut(Integer id){
    
    
            int timeNumber = 5;
            //int age = 10/0;
            //其他异常也会触发服务降级
            try{
    
    
                TimeUnit.SECONDS.sleep(timeNumber);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id:"+id+"\t"+"!!!";
        }
        public String paymentInfo_TimeOutHandler(Integer id){
    
    
            return "线程池:"+Thread.currentThread().getName()+" 系统繁忙,请稍后再试,id:"+id+"\t"+"。。。";
        }
2 动类上,添加激活hystrix的注解@EnableCircuitBreaker

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

3 访问8001的timeout接口,可以看到触发了降级

在这里插入图片描述

修改order模块
一般服务降级,都是放在客户端。此外,对于@HystrixCommand内的修改,建议重启微服务。

1 修改配置文件,feign开启hystrix支持

        feign:
          hystrix:
            enabled: true

2 主启动类添加@EnableHystrix,启用hystrix

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

3 修改controller【pay模块timeout改为3s,限制5s】

        @GetMapping("/payment/hystrix/timeout/{id}")
        @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
    
    
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
        })
        public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    
    
            String result = paymentHystrixService.paymentInfo_TimeOut(id);
            return result;
        }
        public String paymentInfo_TimeOutHandler(Integer id){
    
    
            return "本80系统繁忙,请稍后再试,id:"+id+"\t"+"。。。";
        }

4 测试,order访问pay需要3s,而自己只运行1.5s,所以会在order中降级

在这里插入图片描述

5 目前两个降级模块出现的问题

降级方法与业务方法写在了一块,耦合度高
每个业务方法都写了一个降级方法,重复代码多
重复代码的问题
解决:

配置一个全局的降级方法,所有方法都可以走这个降级方法,至于某些特殊创建,再单独创建方法。

1 创建一个全局方法

        //全局降级方法
        public String paymentInfo_Global_FallbackMethod(){
    
    
            return "Global异常处理信息,请稍后再试,。。。";
        }

2 使用@DefaultProperties注解指定其为全局降级方法(默认降级方法)

        @RestController
        @Slf4j
        @RequestMapping("/consumer")
        @DefaultProperties(defaultFallback = "paymentInfo_Global_FallbackMethod")
        public class OrderHystrixController {
    
    
            ...
        }

3 业务方法不指定具体降级方法,就会使用默认降级方法

        @HystrixCommand
        public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    
    
            String result = paymentHystrixService.paymentInfo_TimeOut(id);
            return result;
        }

4 测试

在这里插入图片描述

代码耦合度的问题
解决:

1 修改order模块,这里开始,pay模块就不服务降级了,服务降级写在order模块即可。

  PaymentHystrixService接口是远程调用pay模块的,我们这里创建一个类实现改接口进行统一降级处理。

        @Component
        public class PaymentFallbackService implements PaymentHystrixService{
    
    
            @Override
            public String paymentInfo_OK(@PathVariable("id") Integer id) {
    
    
                return "----PaymentFallbackService fall back-paymentInfo_OK,...";
            }

            @Override
            public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
    
    
                return "----PaymentFallbackService fall back-paymentInfo_TimeOut,...";
            }
        }

2 确保配置文件中开启了feign的hystrix支持,最后让PaymentHystrixService的实现类生效,修改接口的@FeignClient注解

@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)

3 启动测试,启动order和pay正常访问OK接口

在这里插入图片描述

服务熔断
当某个服务出现问题:

需要关闭所有对此服务的访问【断路器】,然后调用服务降级。

当检测到该服务响应正常后,恢复调用链路。

继续修改pay模块
1修改Payservice接口,添加服务熔断相关的方法

        //服务熔断
        @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
    
    
                @HystrixProperty(name = "circuitBreaker.enable",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();//hutool工具
            return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber;
        }
        public String paymentCircuitBreaker_fallback(Integer id){
    
    
            return "id:"+id+",不能为负数,请稍后再试,。。。";
        }

	配置服务降级方法就不说了,对于配置的参数表示:

		1 如果并发超过10个或者10个并发中失败了6个,就会开启断路器
		2 在时间窗口期10秒之内会尝试请求,如果请求成功就会关闭断路器
2 修改controller,添加一个测试方法

        //服务熔断
        @GetMapping("/circuit/{id}")
        public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    
    
            String result = paymentService.paymentCircuitBreaker(id);
            log.info("****result:"+result);
            return result;
        }

3 测试结果:

在这里插入图片描述

总结补充
Hystrix所有可配置的属性
此外,所有的参数配置可以查看HystrixCommandProperties类当中的成员变量。

在这里插入图片描述
在这里插入图片描述

服务监控
HystrixDashboard
HystrixDashboard是Hystrix提供的准实时调用监控,它记录了所有Hystrix发起的请求的执行信息,并以图形化的形式显示。

HystrixDashboard的使用

1 创建项目,名称为cloud-consumer-hystrix-dashboard9001

2 pom文件

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

3 配置文件

        server:
          port: 9001
4 主启动类

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

5 修改所有pay模块(8001,8002,8003)添加一个pom依赖,我们之前都配过了

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

6 启动9001即可,访问: http://localhost:9001/hystrix

在这里插入图片描述

7 此时仅仅是可以访问HystrixDashboard,并不代表已经监控了8001,8002。如果要监控,还需要配置(8001为例)8001的主启动类添加

	/**
     * 此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
     * ServletRegistrationBean因为SpringBoot的默认路径不是 “/hystrix.stream"
     * 只要在自己的项目里配置上下的servlet就可以了
     */
    @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;
    }

8 到此,可以启动服务启动7001,8001,9001,然后在web界面,指定9001要监控8001:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43183496/article/details/108489132