天天看点

微服务架构 — 服务治理 — 服务限流、服务降级、服务熔断

目录

服务限流

服务降级

服务熔断

c ⇄ s 的异常问题:c 的请求太多,超出 s 的服务能力,导致 s 不可用。例如:dos 攻击,企图耗尽被攻击对象的资源,让目标系统无法响应直至崩溃。因此,s 需要能够进行自我保护,例如:s 对 c 限流,保护 s 的服务资源。

限流通常在网关或网络层面实施。对各类请求设置最高的 qps 阈值,当请求高于阈值时直接阻断。常用的限流算法有滑动计数,漏斗限流和令牌桶限流三种。

滑动计数限流:按时间片(比如 1 秒)定义滑动窗口,计数器记录当前窗口的请求次数,达到阈值就限流,窗口滑动后计数器归零。可采用循环队列数据结构实现。

漏斗限流:维护一个队列,所有请求进队列,按 fifo 服务,队满溢出则丢弃请求。

令牌桶限流:按固定速率往桶中存入令牌,服务前先从桶中取令牌,取到令牌才服务。

限流策略有很多,最简单的比如当单位时间内请求数过多时,丢弃多余的请求。另外,也可以考虑分区限流。仅拒绝来自产生大量请求的服务的请求。例如:商品服务和订单服务都需要访问促销服务,商品服务由于代码问题发起了大量请求,促销服务则只限制来自商品服务的请求,来自订单服务的请求则正常响应。

微服务架构 — 服务治理 — 服务限流、服务降级、服务熔断

c ⇄ s 的异常问题:s 自身出现异常,或者由于资源有限需要对部分 c 请求故意表现为异常(类似限流),为了不影响其他服务功能,主动关闭服务的一些功能。

当下游服务停止工作后,如果该服务并非核心业务,则上游服务应该降级,以保证核心业务不中断。比如:网上超市下单界面有一个推荐商品凑单的功能,当推荐模块挂了后,下单功能不能一起挂掉,只需要暂时关闭推荐功能即可。

简而言之,降级类似于把部分代码注释掉,牺牲部分功能。这要求 s 在实现时,需要具备感知异常的能力,并对关键逻辑实现开关控制。实际场景中,对异常的感知通常由熔断器实现。

c ⇄ s 的异常问题:当 c 发现 s 出现异常(比如:大量超时),由 c 主动出击,暂停对 s 的请求。

当一个服务因为各种原因停止响应时,调用方通常会等待一段时间,然后超时或者收到错误返回。如果调用链路比较长,可能会导致请求堆积,整条链路占用大量资源一直在等待下游响应。所以当多次访问一个服务失败时,应熔断,标记该服务已停止工作,直接返回错误。直至该服务恢复正常后再重新建立连接。

c 对 s 熔断后,那么原本需要调用 s 实现的逻辑怎么办呢?c 可以使用 mock 数据、缓存数据、缺省数据等替代,或者干脆就是抛异常返回错误信息。此时,如果 c 也是一个服务,它相当于做了服务降级。所以我们经常看到服务熔断和服务降级一起出现(hystrix 的断路器在实现时就是把熔断和降级方案打包实现的)。但本质上它们不是一回事,降级发生在 s,熔断发生在 c。之所以配合实现,是因为许多微服务模块同时承担 c 和 s 两种角色。

微服务架构 — 服务治理 — 服务限流、服务降级、服务熔断

服务熔断的设计有两个关键点:

判断何时熔断:通常使用无锁循环队列计数来实现。c 对每次请求 s 的正常、异常(失败、拒绝、超时)返回计数,当异常返回次数超过设定阈值时进行熔断。

何时从熔断状态恢复:处于熔断状态时,c 每隔一段时间(比如 5 秒),允许部分请求通过,若这部分请求正常返回,就恢复熔断。