什么是服务降级?springCloud如何实现?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是服务降级?springCloud如何实现?相关的知识,希望对你有一定的参考价值。

参考技术A 服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。比如电商平台,在针对618、双11等高峰情形下采用部分服务不出现或者延时出现的情形。

二、实现方式

我在spring Cloud项目中,使用了两种方式处理降级操作。

(1)使用feign组件完成降级操作,到内容提供者无法提供服务时, 消费者会调用降级操作,返回服务不可用等信息,或者返回提前准备好的静态页面。 调用的降级处理方法如下:

1@Component

2public class FeignClientFallbackFactory implements FallbackFactory<SchedualServiceHi>  

3    //    打印日志

4    private static final Logger print = LoggerFactory.getLogger(FeignClientFallbackFactory.class); 

5    //降级处理方式 

6    @Override 

7    public SchedualServiceHi create(Throwable throwable) 

8        return new SchedualServiceHi()  

9            @Override

10            public String mm(@RequestParam("uname") String uname, @RequestParam("upwd") String upwd) 

11                print.info("fallback; reason was:", throwable);

12                return "服务报错了";

13            

14        ;

15    

16

(2)也可以使用zuul网关,在spring Cloud自定义一个类实现ZuulFallbackProvider接口,当出现问题,无法正常调用时 ,为服务提供回退响应。

1@Component

2public class MyfaultFallback implements FallbackProvider  

3    @Override 

4    public String getRoute() 

5//        表示为哪个服务提供回退,此处表示所有微服务。

6        return "*"; 

7     



9    @Override

10    public ClientHttpResponse fallbackResponse(String route, Throwable cause) 11        return new ClientHttpResponse() 

12            @Override

13            public HttpStatus getStatusCode() throws IOException

14//                fallback返回的状态码

15                return HttpStatus.OK;

16            

17

18            @Override

19            public int getRawStatusCode() throws IOException

20                //数字类型的状态码,本例返回的是200

21                return this.getStatusCode().value();

22            

23

24            @Override

25            public String getStatusText() throws IOException

26                //状态文本27                return "OK";

28            

29

30            @Override

31            public void close() 

32

33            

34

35            @Override

36            public InputStream getBody() throws IOException

37//                响应体38                return new ByteArrayInputStream("用户微服务不可用,请稍候再试".getBytes());

39            

40

41            @Override

42            public HttpHeaders getHeaders() 

43                HttpHeaders headers = new HttpHeaders();

44                headers.setContentType(MediaType.APPLICATION_JSON);

45                MediaType mt = new MediaType("application",

46                        "json", Charset.forName("UTF-8"));

47                headers.setContentType(mt);

48                return headers;

49            

50        ;

51    

52

三、效果展示

当我们访问zuul网关时,服务提供者没有开启,访问不到,就会进行降级处理,显示下面内容。

原文链接:https://zhuanlan.zhihu.com/p/69635613

SpringCloud——Hystrix服务容错(熔断与降级)

什么是Hystrix

在分布式环境中,不可避免地会有许多服务依赖项中的某些服务失败而导致雪崩效应,Hystrix是一个库,可通过添加等待时间容限和容错逻辑来帮助您控制这些分布式服务之间的交互,Hystrix通过隔离服务之间的访问点,停止服务之间的级联故障并提供后备选项来实现此目的,所有这些都可以提高系统的整体稳定性。

雪崩效应

在微服务架构中,一个请求需要调用多个服务是非常常见的。若一个服务在请求另一个服务中,出现大量的请求时,容器的线程资源就会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。

雪崩的根本原因来源于服务之间的强依赖,可以提前做好评估服务容错,解决方案大概可以分为以下几种:

请求缓存:支持将一个请求与返回结果做缓存处理;
请求合并:将相同的请求进行合并然后调用处理接口;
服务隔离:限制调用分布式服务的资源,某一个调用的服务出现问题不会影响其他服务调用;
服务熔断:牺牲局部服务,保全整体系统稳定性的措施;
服务降级:服务熔断以后,客户端调用自己本地方法返回缺省值。

环境准备

需要准备两个服务,一个服务可以调用另一个服务

请求缓存

安装Redis
需要添加如下两个依赖 redis和对象池依赖

// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis
implementation("org.springframework.boot:spring-boot-starter-data-redis:2.7.1")

// https://mvnrepository.com/artifact/org.apache.commons/commons-pool2  
implementation("org.apache.commons:commons-pool2:2.11.1")

需要在启动类加注解,在配置文件中修改,以及自定义redis的配置文件,最后,使用注解的方式,在接口上注解即可

请求合并

// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.10.RELEASE")



启动类需要加注解 @EnableCircuitBreaker 开启熔断注解

服务隔离

线程池隔离
通过每次都开启一个单独线程运行。它的隔离是通过线程池,即每个隔离粒度都是个线程池,互相不干扰。线程池隔离方式,等于多了一层的保护措施,可以通过hytrix直接设置,超时后直接返回
请求线程和调用Provider线程不是同一个线程,支持超时,支持熔断,支持同步和异步。资源消耗大,大量线程的上下文切换,排队,调度等,无法传递Http Header

信号量隔离
每次调用线程,当前请求通过计数信号量进行限制,当信号量大于最大请求数时,进行限制,调用fallback接口快速返回。信号量的调用是同步的,也就是说,每次调用都得阻塞调用方的线程,直到结果返回,这样就导致了无法对访问做超时(只能依靠调用协议超时,无法主动释放)
请求线程和调用Provider线程是同一个线程,不支持超时,支持熔断,同步调用,不支持异步,可以传递Http Header

服务熔断

服务熔断一般是指软件系统中,由于某些原因使得服务出现过载现象,为了防止造成整个系统故障,从而采用的一种保护措施,在很多地方称之为过载保护

添加依赖

// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.10.RELEASE")

    //声明需要服务熔错的方法
    //服务熔断
    @HystrixCommand(commandProperties = 
       //10s内请求数大于10个就自动启动熔断器,当请求符合熔断条件触发fallbackMethod 默认20个
        HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,
                value = "10"),
        //请求错误率大于50%就自动熔断器,然后 for 循环发起重试请求,当请求符合熔断条件触发 fallbackMethod
        HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,
                value = "50"),
        //熔断多少秒后去重试请求 ,默认 5秒
        HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,
                value = "5000"),
    , fallbackMethod = "selectProductByIdFallback")
    override fun getOne(id:String): String 
        return "这是商品One个$id"
    

服务降级

服务不可用了,直接快速返回托底数据,先保留核心业务,保证服务的可用,后续慢慢再去将服务修正
触发条件:
方法抛出非 HystrixBadRequestException 异常
方法调用超时
熔断器开启拦截调用
线程池/队列/信号量跑满

需要添加依赖

// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.10.RELEASE")

    //声明需要服务容错的方法
    //服务降级
    @HystrixCommand(fallbackMethod = "selectProductByIdFallback")
    override fun getTwo(id:String): String 
        return "这是商品Two个"+orderService.selectTwo(id)
    

Feign雪崩处理

服务提供者添加 openfeign 依赖,openfeign 默认集成了 hystrix依赖,所以无需另外添加

server:
  port: 9091

spring:
  application:
    name: service-consumer

eureka:
  client:
    register-with-eureka: false
    registry-fetch-interval-seconds: 10
    service-url:
      service-url:
        defaultZone: http://localhost:8761/eureka/

#Feign 开启 Hystrix 支持
feign:
  hystrix:
    enabled: true


import com.product_service.fallback.ProductServiceFallback
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.stereotype.Service
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable

@FeignClient("order-service", fallback = ProductServiceFallback::class)
@Service
interface OrderService 

    @GetMapping("/order/two/id")
    fun selectTwo(@PathVariable id : String): String

托底类

import com.product_service.service.OrderService
import org.springframework.stereotype.Component

@Component
class ProductServiceFallback : OrderService 

    override fun selectTwo(id: String): String 
        return "这是托底数据 id $id"
    

以上是关于什么是服务降级?springCloud如何实现?的主要内容,如果未能解决你的问题,请参考以下文章

重学SpringCloud系列七之服务熔断降级hystrix

springcloud-gateway-源码之降级篇

SpringCloud---熔断降级理解Hystrix实战

SpringCloud---熔断降级理解Hystrix实战

SpringCloud——Hystrix服务容错(熔断与降级)

SpringCloud——Hystrix服务容错(熔断与降级)