You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 lines
5.4 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 25 | 稳定性实践:开关和预案
在稳定性保障中,限流降级的技术方案,是针对服务接口层面的,也就是服务限流和服务降级。这里还有另外一个维度,就是业务维度,所以今天我们就从业务降级的维度来分享,也就是**开关和预案**。
## 如何理解开关和预案
**开关,这个概念更多是业务和功能层面的,主要是针对单个功能的启用和停止进行控制,或者将功能状态在不同版本之间进行切换。**
在业务层面,就像我们前面经常提到的大促场景案例,我们会关闭掉很多非核心功能,只保留交易链路的核心功能。比如我们认为商品评论是非核心功能,这时就会通过开关推送这种方案将这个功能关闭。当用户访问商品详情页时,这个接口就不再被调用,从用户角度来说,就是在大促峰值时刻看不到所浏览商品的评论列表。
在功能层面,我们技术架构中会使用缓存技术,但是要考虑到缓存有可能也会出现故障,比如不可访问,或者数据错乱异常等状况,这时我们就会考虑旁路掉缓存,直接将请求转到数据库这一层。
这里有两种做法:一种做法是通过我们上一篇介绍到的降级手段,也就是我们常说的熔断,自动化地旁路;另一种做法,比如在数据异常情况下,请求是正常的,但是数据是有问题的,这时就无法做到自动化旁路,就要通过主动推送开关的方式来实现。
**预案,可以理解为让应用或业务进入到某种特定状态的复杂方案执行,这个方案最终会通过开关、限流和降级策略这些细粒度的技术来实现,是这些具体技术方案的场景化表现。**
我们还是接着上面的这个案例来讨论。因为每个业务或应用都会有自己的开关配置,而且数量会有很多,如果在大促前一个个推送,效率就会跟不上,所以我们就会针对某个应用的具体场景,提供批量操作的手段,通过预案场景将同一应用,甚至多个应用的开关串联起来。
比如上面提到的商品详情页,我们不仅可以关闭商品评论,还可以关闭商品收藏提示、买家秀、店铺商品推荐、同类型商品推荐以及搭配推荐等等。有了场景化的预案,管理和维护起来就会更容易。
除了业务层面的预案,我们还可以将预案应用到应急场景下,比如上面提到的缓存故障异常。在真实场景下,要考虑得更全面,比如缓存能够支撑的业务访问量是要远远大于数据库的,这时我们就要做功能降级,这就要考虑数据库是否能够支撑住这么大的请求量(通常情况下肯定是支撑不住的)。所以,遇到这种场景,我们首要考虑的是限流,先将业务流量限掉三分之一甚至是一半,然后再将功能降级到数据库上。
这样就又涉及到多种策略的串行执行。如果没有预案都是单个执行的话,效率肯定会低,而且还可能涉及到多个应用都会执行相同的业务降级策略,这时就必须要有预案来统一管理,提前梳理好哪些应用需要在这种场景下执行对应的开关、限流和降级策略。
## 技术解决方案
技术方案上并不复杂开关的字段主要以Key-Value方式管理并从应用维度通过应用名管理起来这个对应关系就可以放到统一的控制台中管理。
下图是整个开关和预案管理,以及推送的示意图,我们一起分步骤看一下。
![](https://static001.geekbang.org/resource/image/b6/f6/b6f09f054d05cf429f5e3b40e73c1df6.jpg)
1.**开关管理**
通过上述我们所说的Key-Value方式保存与代码中的具体Field字段对应起来。这里就又会涉及到我们上篇内容中讲到的Spring的AOP和注解技术。
如下面代码所示我们通过注解方式定义了一个开关testKey它与控制台中配置的Key相对应并获取对应的Value取值在业务运行阶段我们就可以根据这个值来决定业务执行逻辑下面是简化的示例。
```
@AppSwitcher(key="key1",valueDes = "Boolean类型")
private Boolean key1;
代码中直接调用AppName对应的开关配置进行不同业务逻辑的实现
Boolean key1 = MoguStableSwitch.isStableSwitchOn("key1");
if (key1)
{
//开关打开时业务逻辑实现
}else
{
//开关关闭时业务逻辑实现
}
```
2.**开关推送**
当在控制台上修改开关值后会推送到微服务的配置中心做持久化这样当应用下次重启时依然可以获取到变更后的值。还有另外一种方式就是通过HTTP的方式推送这种情况的应用场景是当第一种情况失败时为了让开关快速生效预留的第二个接口。
3.**配置变更**
应用中引入的开关SDK客户端会监听对应配置的变更如果发生变化就会马上重新获取并在业务运行时生效。
4.**预案执行**
就是多个开关策略的串行执行,会重复上面这几个关键步骤。
关于开关和预案的内容,我们今天就介绍到这里。留一个问题,我们在上篇文章中介绍到限流降级方案的难点,请你思考一下,我们今天讲的开关预案这个内容,可能会遇到哪些难点呢?欢迎留言与我讨论。
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!