深圳幻海软件技术有限公司 欢迎您!

设计稳定的微服务系统时不得不考虑的场景

2023-02-28

我们的生产环境经常会出现一些不稳定的情况,如:大促时瞬间洪峰流量导致系统超出最大负载,load飙高,系统崩溃导致用户无法下单“黑马”热点商品击穿缓存,DB被打垮,挤占正常流量调用端被不稳定服务拖垮,线程池被占满,导致整个调用链路卡死这些不稳定的场景可能会导致严重后果。大家可能想问:如何做到均匀平滑的

我们的生产环境经常会出现一些不稳定的情况,如:

  • 大促时瞬间洪峰流量导致系统超出最大负载,load 飙高,系统崩溃导致用户无法下单
  • “黑马”热点商品击穿缓存,DB 被打垮,挤占正常流量
  • 调用端被不稳定服务拖垮,线程池被占满,导致整个调用链路卡死

这些不稳定的场景可能会导致严重后果。大家可能想问:如何做到均匀平滑的用户访问?如何预防流量过大或服务不稳定带来的影响?

介绍

下面两种方式是在面对流量不稳定因素时常见的两种方案,也是我们在设计高可用的系统前不得不考虑的两种能力,是服务流量治理中非常关键的一环。

流量控制

流量是非常随机性的、不可预测的。前一秒可能还风平浪静,后一秒可能就出现流量洪峰了(例如双十一零点的场景)。每个系统、服务都有其能承载的容量上限,如果突然而来的流量超过了系统的承受能力,就可能会导致请求处理不过来,堆积的请求处理缓慢,CPU/Load 飙高,最后导致系统崩溃。因此,我们需要针对这种突发的流量来进行限制,在尽可能处理请求的同时来保障服务不被打垮,这就是流量控制。

熔断降级

一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。

现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。

Q:不少同学在问了,那么是不是服务的量级很小就不用进行流量控制限流防护了呢?是不是微服务的架构比较简单就不用引入熔断保护机制了呢?

A:其实,这与请求的量级、架构的复杂程度无关。很多时候,可能正是一个非常边缘的服务出现故障而导致整体业务受影响,造成巨大损失。我们需要具有面向失败设计的意识,在平时就做好容量规划和强弱依赖的梳理,合理地配置流控降级规则,做好事前防护,而不是在线上出现问题以后再进行补救。

在流量控制、降级与容错场景下,我们有多种方式来描述我们的治理方案,下面我将介绍一套开放、通用的、面向分布式服务架构、覆盖全链路异构化生态的服务治理标准 OpenSergo,我们看看 OpenSergo 是如何定义流控降级与容错的标准,以及支撑这些标准的实现有哪些,能帮助我们解决哪些问题?

OpenSergo 流控降级与容错 v1alpha1 标准

在 OpenSergo 中,我们结合 Sentinel 等框架的场景实践对流控降级与容错场景的实现抽象出标准的 CRD。我们可以认为一个容错治理规则 (FaultToleranceRule) 由以下三部分组成:

  • Target: 针对什么样的请求
  • Strategy: 容错或控制策略,如流控、熔断、并发控制、自适应过载保护、离群实例摘除等
  • FallbackAction: 触发后的 fallback 行为,如返回某个错误或状态码

那我们看看针对常用的流控降级场景,OpenSergo 具体的标准定义是什么样的,他是如何解决我们的问题的?

首先提到的,只要微服务框架适配了 OpenSergo,即可通过统一 CRD 的方式来进行流控降级等治理。无论是 Java 还是 Go 还是 Mesh 服务,无论是 HTTP 请求还是 RPC 调用,还是数据库 SQL 访问,我们都可以用这统一的容错治理规则 CRD 来给微服务架构中的每一环配置容错治理,来保障我们服务链路的稳定性。让我们来详细看看OpenSergo在各个具体场景下的一个配置。

流量控制

以下示例定义了一个集群流控的策略,集群总体维度每秒不超过 180 个请求。示例 CR YAML:

apiVersion: fault-tolerance.opensergo.io/v1alpha1
kind: RateLimitStrategy
metadata:
  name: rate-limit-foo
spec:
  metricType: RequestAmount
  limitMode: Global
  threshold: 180
  statDuration: "1s"
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

这样一个简单的 CR 就能给我们的系统配置上一个流量控制的能力,流控能力相当于应用的一个安全气囊,超出系统服务能力以外的请求将被拒绝,具体逻辑可由我们自定义(如返回指定内容或跳转页面)。

熔断保护

以下示例定义了一个慢调用比例熔断策略,示例 CR YAML:

apiVersion: fault-tolerance.opensergo.io/v1alpha1
kind: CircuitBreakerStrategy
metadata:
  name: circuit-breaker-slow-foo
spec:
  strategy: SlowRequestRatio
  triggerRatio: '60%'
  statDuration: '30s'
  recoveryTimeout: '5s'
  minRequestAmount: 5
  slowConditions:
    maxAllowedRt: '500ms'
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

这个 CR 的语意就是:在 30s 内请求超过 500ms 的比例达到 60% 时,且请求数达到 5 个,则会自动触发熔断,熔断恢复时长为 5s。

想象一下,在业务高峰期。当某些下游的服务提供者遇到性能瓶颈,甚至影响业务。我们对部分非关键服务消费者配置一个这样的规则,当一段时间内的慢调用比例或错误比例达到一定条件时自动触发熔断,后续一段时间服务调用直接返回 Mock 的结果,这样既可以保障调用端不被不稳定服务拖垮,又可以给不稳定下游服务一些“喘息”的时间,同时可以保障整个业务链路的正常运转。

流控降级与容错标准的实现

Sentinel 介绍

下面介绍一款支持 OpenSergo 流控降级与容错标准的项目 Sentinel 。

Sentinel 是阿里巴巴开源的,面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、流量整形、熔断降级、系统自适应保护等多个维度来帮助开发者保障微服务的稳定性。

Sentinel 的技术亮点:

  • 高度可扩展能力:基础核心 + SPI 接口扩展能力,用户可以方便地扩展流控、通信、监控等功能
  • 多样化的流量控制策略(资源粒度、调用关系、流控指标、流控效果等多个维度),提供分布式集群流控的能力
  • 热点流量探测和防护
  • 对不稳定服务进行熔断降级和隔离
  • 全局维度的系统负载自适应保护,根据系统水位实时调节流量
  • 覆盖 API Gateway 场景,为 Spring Cloud Gateway、Zuul 提供网关流量控制的能力
  • 云原生场景提供 Envoy 服务网格集群流量控制的能力
  • 实时监控和规则动态配置管理能力

一些普遍的使用场景:

  • 在服务提供方(Service Provider)的场景下,我们需要保护服务提供方自身不被流量洪峰打垮。这时候通常根据服务提供方的服务能力进行流量控制,或针对特定的服务调用方进行限制。我们可以结合前期压测评估核心接口的承受能力,配置 QPS 模式的限流,当每秒的请求量超过设定的阈值时,会自动拒绝多余的请求。
  • 为了避免调用其他服务时被不稳定的服务拖垮自身,我们需要在服务调用端(Service Consumer)对不稳定服务依赖进行隔离和熔断。手段包括信号量隔离、异常比例降级、RT 降级等多种手段。
  • 当系统长期处于低水位的情况下,流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。这时候我们可以借助 Sentinel 的 WarmUp 流控模式控制通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,而不是在一瞬间全部放行。这样可以给冷系统一个预热的时间,避免冷系统被压垮。
  • 利用 Sentinel 的匀速排队模式进行“削峰填谷”,把请求突刺均摊到一段时间内,让系统负载保持在请求处理水位之内,同时尽可能地处理更多请求。
  • 利用 Sentinel 的网关流控特性,在网关入口处进行流量防护,或限制 API 的调用频率。

阿里云微服务解决方案

在阿里云上提供了一款完全遵循 OpenSergo 微服务标准的企业级产品 MSE,MSE 服务治理的企业版中的流量治理能力我们可以理解为是一个商业化版本的 Sentinel ,我们也简单总结了一下 MSE 流量治理与社区方案在流控降级与容错场景下的一个能力对比。

下面我将基于 MSE 来演示一下,如何通过流量控制与熔断降级来保护我们的系统,可以从容地面对不确定性的流量以及一系列不稳定的场景。

  • 配置流控规则

我们可以在监控详情页面查看每个接口实时的监控情况。

我们可以点击接口概览右上角的“新增防护规则”按钮,添加一条流控规则:

我们可以配置最简单的 QPS 模式的流控规则,比如上面的例子即限制该接口每秒单机调用量不超过 80 次。

  • 监控查看流控效果

配置规则后,稍等片刻即可在监控页面看到限流效果:

被拒绝的流量也会返回错误信息。MSE 自带的框架埋点都有默认的流控处理逻辑,如 Web 接口被限流后返回 429 Too Many Requests,DAO 层被限流后抛出异常等。若用户希望更灵活地定制各层的流控处理逻辑,可以通过 SDK 方式接入并配置自定义的流控处理逻辑。

总结

流控降级与容错是我们设计稳定的微服务系统时不得不考虑的场景,如果我们设计每一套系统都要花许多心思来设计系统的流控降级与容错能力,这将会成为让我们每一个开发者都头疼的问题。那么我们接触与设计了那么多系统的流控降级,有没什么通用的场景、最佳实践、设计标准与规范乃至参考实现可以沉淀的?

本文从场景出发简单介绍了 OpenSergo 的流量控制与熔断保护标准,同时也介绍了 Sentinel 流量防护的背景和手段,最后通过示例来介绍如何利用 MSE 服务治理的流量防护能力来为 您的应用保驾护航。