服务降级和服务熔断万字讲解,从0到1

转载服务降级和服务熔断万字讲解,从0到1,边学边实战! - 知乎 (zhihu.com)

整理笔记

熔断VS降级

相同点:

目标一致 都是从可用性和可靠性出发,为了防止系统崩溃;

用户体验类似 最终都让用户体验到的是某些功能暂时不可用;

不同点:

触发原因不同 服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考

服务熔断

熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。

这种牺牲局部,保全整体的措施就叫做熔断。

服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。

服务降级

服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。

服务降级是指 当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。说白了,就是尽可能的把系统资源让给优先级高的服务。

资源有限,而请求是无限的。如果在并发高峰期,不做服务降级处理,一方面肯定会影响整体服务的性能,严重的话可能会导致宕机某些重要的服务不可用。所以,一般在高峰期,为了保证核心功能服务的可用性,都要对某些服务降级处理。比如当双11活动时,把交易无关的服务统统降级,如查看蚂蚁深林,查看历史订单等等。

服务降级主要用于什么场景呢

当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用。

降级的方式可以根据业务来,可以延迟服务,比如延迟给用户增加积分,只是放到一个缓存中,等服务平稳之后再执行 ;或者在粒度范围内关闭服务,比如关闭相关文章的推荐。

实现服务降级需要考虑几个问题

1)那些服务是核心服务,哪些服务是非核心服务 2)那些服务可以支持降级,那些服务不能支持降级,降级策略是什么 3)除服务降级之外是否存在更复杂的业务放通场景,策略是什么?

自动降级分类

1)超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况

2)失败次数降级:主要是一些不稳定的api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况

3)故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)

4)限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。

服务熔断案例

当前系统中有A,B,C三个服务,服务A是上游,服务B是中游,服务C是下游。它们的调用链如下:

一旦下游服务C因某些原因变得不可用,积压了大量请求,服务B的请求线程也随之阻塞。线程资源逐渐耗尽,使得服务B也变得不可用。紧接着,服务A也变为不可用,整个调用链路被拖垮。

像这种调用链路的连锁故障,叫做雪崩。

正所谓刮骨疗毒,壮士断腕。在这种时候,就需要我们的熔断机制来挽救整个系统。熔断机制的大体流程和刚才所讲的考试策略如出一辙:

这里需要解释两点:

1.开启熔断

在固定时间窗口内,接口调用超时比率达到一个阈值,会开启熔断。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的默认方法,达到服务降级的效果。

2.熔断回复

熔断不可能是永久的。当经过了规定时间之后,服务将从熔断状态回复过来,再次接受调用方的远程调用。

服务熔断的实际应用

Spring Cloud Hystrix很好的实现了熔断机制

pring Cloud Hystrix是基于Netflix的开源框架Hystrix实现,该框架实现了服务熔断、线程隔离等一系列服务保护功能。

对于熔断机制的实现,Hystrix设计了三种状态:

1.熔断关闭状态(Closed)

服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。

2.熔断开启状态(Open)

在固定时间内(Hystrix默认是10秒),接口调用出错比率达到一个阈值(Hystrix默认为50%),会进入熔断开 启状态。

进入熔断状态后, 后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法。

3.半熔断状态(Half-Open)

在进入熔断开启状态一段时间之后(Hystrix默认是5秒),熔断器会进入半熔断状态。

所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。

如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断开启 状态。

三个状态的转化关系如下图:

熔断VS降级

相同点:

目标一致 都是从可用性和可靠性出发,为了防止系统崩溃;

用户体验类似 最终都让用户体验到的是某些功能暂时不可用;

不同点:

触发原因不同 服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;

Hystrix简介

Hystrix:英 [hɪst'rɪks] 美 [hɪst'rɪks] ,翻译过来是“豪猪”的意思。 在分布式环境中,不可避免地会出现某些依赖的服务发生故障的情况。Hystrix是这样的一个库,它通过添加容许时延和容错逻辑来帮助你控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点,阻止跨服务的级联故障,并提供了退路选项,所有这些都可以提高系统的整体弹性。

Hystrix的设计目的:

通过第三方客户端的库来为访问依赖服务时的潜在故障提供保护和控制;
防止在复杂分布式系统中出现级联故障;
快速失败和迅速恢复;
在允许的情况下,提供退路对服务进行优雅降级;
提供近实时的监控、报警和操作控制;

接下来我们将通过对《模拟RPC调用(Feign)》一章中的 message-center 项目进行改造,演示如何使用Hystrix,eureka服务注册中心以及message-service服务提供者无需更改。

使用Hystrix

引入Hystrix依赖

在 pom.xml 文件中引入Hystrix依赖:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>

    <properties>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Eureka-Client 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- Feign 依赖 -->
        <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>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <!-- SpringCloud 版本控制依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

修改启动类

在MessageCenterApplication启动类上增加@EnableCircuitBreaker注解:

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class MessageCenterApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(MessageCenterApplication.class).web(WebApplicationType.SERVLET).run(args);
    }

}

这里我们在启动类中又增加了@EnableCircuitBreaker注解,用来开启断路器功能。如果你觉得启动类上的注解个数有点多的话,可以使用一个@SpringCloudApplication 注解来代替@SpringBootApplication(或者@EnableEurekaServer)、@EnableDiscoveryClient、@EnableCircuitBreaker这三个注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}

修改Controller

接下来,我们为MessageCenterController中的getMsg()接口增加断路器功能,修改部分代码如下:

@GetMapping("/msg/get")
    @HystrixCommand(fallbackMethod = "getMsgFallback")
    public Object getMsg() {
        String msg = messageService.getMsg();
        return msg;
    }

    public Object getMsgFallback() {
        return "祝您 2019 猪年大吉,'猪'事如意!";
    }

先启动Eureka,再启动一个8771端口的message-service服务,最后启动message-center。待启动完成之后,Eureka注册中心实例注册信息如下:

此时,访问 http://localhost:8781/api/v1/center/msg/get ,返回如下结果表明服务调用成功:

然后,停掉message-service服务,再次请求 http://localhost:8781/api/v1/center/msg/get ,返回结果如下:

可以看出fallback中的信息被直接返回了,表明Hystrix断路器调用成功。

注意:fallback方法的签名需要和原方法保持一致。

/**
     * 获取消息详情
     */
    @GetMapping("/api/v1/msg/detail/{id}")
    @HystrixCommand(fallbackMethod = "getDetailFallback")
    public MessageEntity getDetail(@PathVariable(name = "id") Long id) {
        return messageService.getById(id);
    }

    /**
     * 获取消息详情退路
     */
    public MessageEntity getDetailFallback(Long id){
        return null;
    }

Feign结合Hystrix

以MessageService的Feign客户端为例,为其添加Hystrix断路器功能。

修改Feign客户端

通过配置@FeignClient注解的fallback属性来位MessageServiceClient指定一个自定义的fallback处理类(MessageServiceFallback)。

@FeignClient(name = "message-service", fallback = MessageServiceFallback.class)
public interface MessageServiceClient {

    @GetMapping("/api/v1/msg/get")
    public String getMsg();

}

创建Fallback处理类

MessageServiceFallback需要实现MessageServiceClient接口,并且在Spring容器中必须存在一个该类型的有效Bean。在这里,我们使用@Component注解将其注入到Spring容器中。

@Component
public class MessageServiceFallback implements MessageServiceClient {

    @Override
    public String getMsg() {
        System.out.println("调用消息接口失败,对其进行降级处理!");
        return "消息接口繁忙,请稍后重试!";
    }

}

修改配置

在新版本的Springcloud中,Feign默认关闭了对Hystrix的支持,需要在application.yml进行配置:

feign:
  hystrix:
    enabled: true

当message-service服务不可用时,请求 http://localhost:8781/api/v1/center/msg/get,返回结果如下:

查看后台日志,打印如下内容,表明fallback方法被成功调用了:

监控Hystrix

启用健康监控

Actuator是Springboot提供的用来对应用系统进行自省和监控的功能模块,借助于Actuator开发者可以很方便地对应用系统某些监控指标进行查看、统计等。

若要使用Actuator对Hystrix 流进行监控,除了需在工程POM文件中引入spring-boot-starter-actuator依赖:

<!-- Actuator 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

还需要在application.yml 中添加如下配置:

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

启用Hystrix-Dashboard

使用Hystrix一个最大的好处就是它会为我们自动收集每一个HystrixCommand的信息,并利用Hystrix-Dashboard通过一种高效的方式对每一个断路器的健康状态进行展示。

值得注意的是,在使用HystrixCommand对RibbonClient进行包装的时候,你需要确保你配置的Hystrix超时时间要比Ribbon的超时时间长,包括由它们引起的重试时间,举个例子:如果你的Ribbon连接超时时间是1秒,并且Ribbon会连续重试请求3次,那么你的Hystrix连接超时时间需要配置成稍大于3秒。

引入Hystrix-Dashboard依赖

在 pom.xml 文件中引入Hystrix-Dashboard依赖:

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

修改启动类

在MessageCenterApplication启动类上增加@EnableHystrixDashboard注解:

@EnableFeignClients
@SpringCloudApplication
@EnableHystrixDashboard
public class MessageCenterApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(MessageCenterApplication.class).web(WebApplicationType.SERVLET).run(args);
    }

}

仪表盘界面

启动应用,访问 http://localhost:8781/hystrix ,打开Hystrix-Dashboard监控首页。

在这里配置好需要监控的Hystrix流地址 http://localhost:8781/actuator/hystrix.stream ,开始监控。

服务熔断和服务降级的区别

1、触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;

2、管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)

3、实现方式不太一样,服务降级具有代码侵入性(由控制器完成/或自动降级),熔断一般称为自我熔断。

限流:限制并发的请求访问量,超过阈值则拒绝; 降级:服务分优先级,牺牲非核心服务(不可用),保证核心服务稳定;从整体负荷考虑; 熔断:依赖的下游服务故障触发熔断,避免引发本系统崩溃;系统自动执行和恢复

应用场景

主要是高并发下的服务雪崩问题

服务降级

1、在高并发情况下,防止用户一直等待,使用服务降级方式(返回一个友好的提示直接给客户端,不会去处理请求,调用fallback本地方法),目的是为了用户体验

比如秒杀–当前请求人数过多,请稍后重试。(在tomcat中没有线程进行处理客户端请求的时候,不应该让用户一直转圈等待。)

服务熔断

默认阈值为10个,熔断机制和服务降级一起使用。

例如保险丝,服务熔断的目的是为了保护服务,在高并发情况下,如果请求达到了一定的极限(可以自己设置阈值),如果流量超出了设置的阈值,会自动开启保护服务功能,使用服务降级方式返回一个友好的提示。

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值