# 可降级设计

接上文书，服务各接口要考虑熔断与降级，这更偏向于技术手段及具体的接口或服务，我们的系统由众多的服务组成，在系统层面上也必须考虑整体的可降级设计，而这更偏向于业务设计。

我们看到很多的产品在发生故障时直接挂维护页，系统整体下线，这种做法简单，但也很粗暴，业务上的损失不说，对产品本身的品牌声誉也会造成很大的影响，再往大了说甚至会导致公司破产，笔者撰写此章节时（2018年8月）正值国内大量P2P企业暴雷跑路期间，这些倒闭的P2P企业中有一部分其实是经营状况良好的，但由于这期间投资者的恐慌心里加上系统没有可降级的设计，在出现一些局部Bug或是受到恶意攻击时系统整体瘫痪进而导致了挤兑。笔者当前服务的是家互金头部企业有比较大的体量，但即便如此在这期间平台只要停运1天我们就可能面临资金流动性问题。

技术服务于业务，要为业务开展提供强有力的保障，在一定程度上也决定了公司的生死，但客观的规律告诉我们Bug是避免不了的，我们能做的只是尽可能降低Bug的发生几率及减少Bug的影响范围，前者多为工程质量要求这里不展开，而后者正是要求我们要严肃认真思考架构系统的降级方案。

我们首先要明确的是降级的场景，最普遍的有以下两个：

* 某个接口或服务发生比较严重的Bug，这种情况下如果该服务有能适配当前生产系统的早期版本则应该执行回滚操作，如果无法适配则要进行降级，关闭依赖此接口或服务的上层业务
* 并发压力导致系统整体负载过高，影响业务操作，这种场景常用的手段是限流，如果限流解决不了那就要考虑降级，这时的降级是丢卒保帅，自动或手工地关停非必须服务以确保我们的核心业务正常运作

分析上面两个场景可知可降级设计最核心的是要明确各服务的业务边界、依赖关系及重要度，我们拿车贷通举例，如上文介绍我们最终将它分成CRM、信贷系统、风控系统、营销系统、论坛等子系统，各子系统边界清晰，服务间的依赖也比较明确，即CRM作为基础子系统被其它子系统依赖，信贷依赖于风控，营销与论坛没有依赖。用于服务划分这样的粒度足够了，但要对于降级处理，我们必要依赖到接口级别，比如风控系统中有一个风控预演服务，这一服务只为风控建模评估使用，不会参与风控审核流程，所以如果这个服务宕机对信贷整体业务是没有任何影响的。目前笔者没发现有比较好的开源服务依赖自动化管理工具，现阶段我们只能通过人工标注的方式来管理服务接口的依赖，形成应急响应手册交由运维查阅，在发生故障时通过此手册快速定义受影响的范围并针对性下线部分服务，在个别页面给出维护提示，当然实际情况会更复杂些，因为我们部分接口本身会有降级流程的，这些接口的依赖接口异常后未必会要下线，这种情况我们也需要考虑。

比如下图是车贷通的依赖关系示例：

| 系统/ 服务                  | 关联业务       | 业务等级 | 依赖系统/服务                | 依赖接口          | 备注                    |
| ----------------------- | ---------- | ---- | ---------------------- | ------------- | --------------------- |
| CRM/basic               | 用户注册、手机登录  | 高    | message/sms            | PUT /sms      | 注册、登录是关键业务流程          |
| CRM/basic               | 找回密码、修改密码  | 低    | message/sms            | PUT /sms      |                       |
| loan/apply              | 贷款申请成功短信提醒 | 低    | message/sms            | PUT /sms      | APP自带提醒，短信为辅助         |
| loan/audit              | 贷款审核       | 高    | risk-management/credit | \*            | 贷款审核依赖风控系统审核授信服务的所有接口 |
| loan/contract           | 生成电子合同     | 低    | e-signature/           | PUT /contract | 电子合同很重要，但业务上允许异步、后补   |
| loan/repayment          | 每月还款提醒     | 中    | message/sms            | PUT /sms      |                       |
| marketing/customer-care | 生日祝福、活动公告  | 低    | message/sms            | PUT /sms      |                       |

通过这个示例可以看到，如果短信发送的接口出问题影响面很广并且有高优先级的业务依赖，风控审核授信服务也一样，但生成电子合同的接口业务上没有太高要求，从中可以给我们的降级设计指明方向：

* 找出重点保障的接口/服务，以进行更严格的容错设计及质量测试，比如短信发送接口
* 明确所依赖的业务，针对性地降级处理，比如在系统资源紧张时可以临时下线风控预演系统（因为它不是核心业务），比如短信发送异常时关闭各关联业务的入口请求并做好通告

这一依赖关系粒度还不够细，理想的情况是接口对接口，是要找出诸如短信发送接口异常影响的所有接口而非这些接口对应的服务，这样才能做最小化地降级，但这很有难度，目前没看到有类似成熟的案例。笔者设想可以通过线上系统的接口调用跟踪自动发现接口依赖关系，以此为基础结合人工标注、优先级设定及对应的降级处理从而实现智能化降级流程，当然要落地还有很多待解决的问题。

上面我们所谓的降级都是指发生异常的情况，但实际项目中更多还是计划内停服维护的正常降级。比如银行的支付网关升级导致我们的支付系统无法正常服务，再比如我们的某些服务数据体量过要做分库分表导致不得不停服等情况。对于这些可预测的降级首先肯定还是需要有上述的依赖关系说明来明确影响范围，然后再与业务、产品充分沟通达成一致，做好预案，包含降级业务范围、时间、时长、公告内容、客服话术、回滚方案等。

优雅的降级设计是一个复杂的、系统性的工程，本文也只是点到了大概。技术为降级提供了可能，但要实现真正意义的可降级架构更需要技术之外，让业务人员来明确我们的各业务版块、让产品人员根据我们的业务形态合理地设计产品，在顶层设计上不要出现边界不清、责任不明。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gudaoxuri.gitbook.io/microservices-architecture/wei-fu-wu-hua-zhi-ji-shu-jia-gou/services-fallback.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
