<audio id="audio" title="21 | 高性能设计，一切都围绕着契约精神" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/yy/5d/yy882558928ef8a1f751401b854b065d.mp3"></audio>

你好，我是乔新亮。这一讲，我们来聊聊如何实现架构的高性能设计。

前面我们讲过，产品思维有两个核心关键词：“契约精神”和“洞察人性”。其实高性能设计，也和契约精神是密切相关的。我将其总结为：高性能设计，一切围绕着契约精神。

你可能会想，高性能设计不就是可以支撑大流量、高并发的架构设计吗？和契约精神又有什么关系？

其实关系很大。所谓的高性能，实际上，是与业务强相关的。比如，对于一台网络游戏服务器来说，可以支撑 400 名玩家同时在线，就算高性能；对于一台流媒体服务器来说，可以支撑 10,000 用户同时在线观看，就算高性能。

当然，数据可能不准确，但逻辑大体如此。在实际的业务场景中，还会有许多其他技术指标被引入。比如游戏需要关注连接稳定性、视频需要关注延时，等等。

明确了性能和业务的关系，下面我们就来聊聊，如何进行高性能设计，也借此加深对契约精神的认知和理解。

## 契约精神是高性能架构设计的“拦路虎”

首先，我们要清楚，高性能设计可以大体拆解为两大步骤：

1. 清晰描述、定义性能目标；
1. 设计并实现这个目标。

而高性能架构的设计目标，是通过三类指标来具体定义的，分别是：

1. 系统响应时间，一般指服务/交易处理的时间，也包括网络响应时间；
1. 系统吞吐量，一般指系统的每秒交易量，通常需要结合并发量共同描述；
1. 系统容量，通常代表系统的可用资源数量，包括硬盘容量、网络带宽等。

但要注意：虽然我们有三类高性能指标，但彼此不能孤立地看待，否则就会出现问题。比如，在定义系统响应时间目标时，如果不与系统吞吐量关联起来，就会变得缺乏实践意义 —— 一旦流量的压力高峰到来，系统往往就不遂人愿了。

这意味着，我们要学会识别架构设计中的组件（或服务），首先弄清哪些组件需要明确高性能指标，再针对性地用以上三个指标做清晰定义。

除此之外，对于系统响应时间，我们还有一个更直观的监控指标，叫做 Top 百分数 （Top Percentile），简称 TP。比如， TP 90 = 2s，意思是，90% 的请求的响应时间都在 2s  内；那么  TP  99 = 2s 的意思就是 99%  的请求的响应时间都在  2s 内；我们一般说的  RT  =  2s，指的是平均响应时间，可以作为参考，但实际意义可能并不大。我个人一般会重点看  TP  90  和  TP  99 的数据。

当我们明确了  TP  90  或者  TP  99 这一有关系统响应时间的指标时，一个交付给用户的“契约”就出现了。守好诸多类似的契约，也就是保证了高性能设计。但学习需要适当地进行延展思考，比如此时，我们应该多问自己一句：这个契约意味着什么？

对于没有经验的程序员或架构师来说，这里其实存在一个隐含的假设，某种意义上，也算是一种侥幸心理：如果该系统在业务流量低峰场景下，满足了响应时间等性能指标，也就意味着，该系统在任何场景下，都能满足这些指标。

你可能会觉得有点绕， 那我换个说法来描述刚刚签订的高性能“契约”：本系统、组件、服务承诺在任何情况、任何资源、任何压力高峰下，都保证  TP  90  =  2s 。

是不是立刻就有了不一样的感觉？好像契约发生了变化，光是读出来，就让人心里一抖。

其实到此时，还谈不上契约是否发生了变化，因为打从一开始，这个契约就是不明确、不清晰、不具体的。

注意，这里还没有谈架构设计和研发能力，问题就已经出现了。很多时候，我们会被工作中出现的一些实际问题所困扰，其根源往往不在于相关责任人缺乏设计能力，而在于签订的“契约”并不明确。团队不可能实现和保卫一个“空中花园”。

所以，我总说，高性能设计，一切围绕着契约精神。所以接下来，我们的内容都将围绕着“如何将契约描述清楚”这件事来展开。

## 有上限的“契约”才能交付

我曾经培养过许多架构师。一开始在做高性能设计时，他们常常会这样描述给用户的“契约”：

“该架构最高支持 200 万并发流量，TP 90 = 2s 。”

在不考虑业务需求的情况下，这个契约看似是没问题的。这意味着：对于第 1 名连接服务器的用户来说，TP 90 = 2s ；但对于第 300 万名连接服务器的用户来说，契约又是什么呢？答案是，没有，或者说比较模糊。

**如果目标不清晰，隐患就埋下了。高性能设计非常看重系统响应时间的一致性，尤其是在不同的服务阶段，并发量和吞吐量发生变化的时候。**

对于管理者或架构师而言，理想的契约应该是“保证设计流量内的用户 TP 90 = 2s，超出并发限制的用户，则暂时不在契约承诺的范围内。”。

这就要求我们通过四大步骤去思考所谓高性能架构的设计问题：

第一步，当服务器不超过 200 万并发用户时，TP 90 = 2s 。

第二步，当连接服务器的并发用户数量超过 200 万，达到 250 万时，保证有 200 万用户的 TP 90 = 2s ，拒绝其他用户的连接请求。

第三步，为设计容量外的用户提供服务器排队机制，并附带具体、明确的系统提示。

第四步，3 分钟内完成扩容，保证并发用户数量小于等于 250 万时，任何在线用户的 TP 90 = 2s。

其实，这样才构成了一个可以履行的契约：无论流量波动如何，该架构始终支持 200 万用户的 TP 90 = 2s；高峰时期，其他用户会被拒绝访问或进行排队，但系统能在三分钟内完成扩容，支持 250 万并发在线用户，并且保证其中任何一个用户的 TP 90 = 2s  。

在某种程度上，这也是对业务诉求的精确表达，对于业务发展来说至关重要。很多同学设计的架构和契约，压根没有控制上限。他们想当然地认为，流量不可能出现太大的变化或波动。对于用户来说，这无异于一张“空头支票”。

所以说，要做高性能设计，一定要明确目标，并交付给用户；没有清晰的目标，也就没有针对性的设计，怎么能实现高性能的架构呢？

目标清晰后，我们再来看看，高性能架构如何设计并落地。

## 实现高性能架构的关键技术点

落地也不难，有三项工作最为关键，分别是：

1. 为架构做好“保护系统”；
1. 使架构具备扩容能力；
1. 提升系统各组件处理能力。

**保护系统，是为应对容量规划外的过载而设计的，通过流量控制来具体实现。**

所谓流量控制，就是当实际并发压力，超过设计性能的时候，人为阻断服务器连接，告知用户需要排队或“稍后再试”。

经常玩游戏的同学可能知道，对于网络游戏来说，流量控制是个基础设计，基本上所有的服务器都有“排队机制”。

流量控制有两种具体的实践，一种是面向连接数做控制，一种是面向用户数做控制。前者让用户在不断尝试连接时，有一定成功的可能；后者则保证用户对系统的期望是一致的 —— 要么可以登录、要么不能登录。具体应该选择哪种方式，取决于业务的实际诉求。

**而对于扩容能力来说，一般要包括储备额外的计算资源和具备快速弹性扩容能力。**

你可能会说，既然已经有计算资源了，为什么不提前进行扩容呢？

工作经验比较丰富的同学可能会知道其中的“隐情”：一般来说，该做的系统扩容，通常很早就完成了，架构设计真正缺乏的是应急手段。毕竟，你不能“不分青红皂白”，将每个系统的应急扩容都提前做好。一个经营稳健的企业，是不会允许这样的开销出现的。

另一个关键要素在于扩容速度。扩容工作是需要一小时、一分钟，还是一秒钟完成，其差别非常之大。“天下武功，唯快不破”，就算架构设计做得不好，如果响应够快，很多情况下，也是能解决问题的。

无论是利用公有云扩容，还是私有云扩容，目标都应该是一致的。想象一下这样的场景：

双十一来了，你通过监控平台，看到在线用户数量快速增长，很快突破了 200 万，流量控制机制开始生效，新用户进入排队序列。你考虑了 3 秒钟，然后做了一个决定：系统需要扩容。于是，你轻轻地输入一个数字，按下回车。3 秒钟后，排队序列消失了。你对旁边的同学说，继续监控吧！然后悠闲地端起茶杯，离开了座位。

这将是一种多么美妙的工作状态？更棒的是，以上场景完全有可能实现。

至此，我们聊过了契约，也聊过了应急处理，也就意味着，我们把握住了高性能设计的“头”和“尾”。最后，我们再简单谈一下“中间”部分，也就是对系统各组件处理能力的提升。

在高性能设计中，对于每个组件/服务都要确定目标，进行设计，然后进行评审和测试，确保满足性能需求。对于架构负责人来说，性能设计一定要尽早开始，具体工作内容包括：

- 需求早期收集
- 容量分析
- 估算与建模
- 技术研究
- 设计、开发、跟踪
- 测试计划执行
- 风险与绩效管理
- 实时监控与容量管理

工作内容和流程可能有些多，但这更多属于标准化的研发管理流程，这里列出来仅供参考，实际执行的时候，需要参考具体的业务和企业情况做调整。

**在这中间，有一点需要额外注意，我们称之为“对系统资源的争抢问题”。**

对于一个组件或服务，并发压力增大，响应时间却没有变化，意味着在请求的处理过程中，没有发生对资源的争抢和排队。同理，当响应时间随着并发压力的增大而变长时，一般都意味着这些请求引起了对系统资源的争抢。

**对于无状态的服务，理论上可以通过集群扩容，无限增加系统的并发处理能力，简单、直接地解决问题；**

**但对于有状态的数据服务而言，比如缓存或数据访问，就要考虑资源争抢问题，并针对性地设计、处理**。

所以，高性能架构在设计落地时，一个重要的任务，就是去发现那些可能出现资源争抢的模块，并一一进行隔离。

谈到“隔离”，在架构维度有两种方案，一种是在应用层进行隔离，也就是说，在业务功能层面就开始隔离；一种是基础软件层面进行隔离，比如与数据库相关的“读写分离”概念，就是在基础软件层面进行隔离。

对应到具体的实施方法上，有三种主要的“隔离”技巧，你可以多做了解：

1. 缓存机制，适用于部分场景，可以解决数据库资源的争抢问题；
1. EDA 架构，适用于处理时间较长的代码逻辑，需要提前区分哪些模块可以做同步处理，哪些模块可以做异步处理；
1. 提前进行预处理，以空间换时间，这也是一种卓有成效的处理手段。

当然了，方法还有很多，听完这节课后，你可以单独再做了解，并将了解到的方法，在评论区分享给大家。

做好隔离后，我们也要注意提升架构的可扩展性，具体方法可以参考[《架构设计，专业分工和协作精神的体现》](https://time.geekbang.org/column/article/317135)，这里不再重复。

至此，关于高性能设计的三个最重要的步骤就讲完了，我们总结一下，分别是：

1. 为架构做好“保护系统”：做好系统的流量控制；
1. 使架构具备扩容能力：储备额外的计算资源，提升弹性扩容的速度；
1. 提升系统各组件处理能力：识别高并发情境中的资源争抢情况，同时注意保留架构的可扩展性。

最后，我们也要对测试工作保持关注。可能你在 PRE  环境做过压测，但后来发现，实际的业务复杂度是远远超过想象的。

针对这种问题，行业内的解决方案更偏向“全链路生产压测”，说白了，就是在生产环境准备数据、进行压测。如果一个系统通过了全链路压测，那就可以基本确认没有性能问题了。

## 结语

从我的角度来看，**技术行业发展到今天，基本不存在太多的技术挑战了。**

如果你能将业务问题抽象为一个技术问题，那么不管是寻求同事的帮助，还是 Google、看书、到知识平台付费学习，都能解决你的疑惑。

所以，在理清高性能架构设计的整体思路后，困惑、焦虑，应该从你的认知中消失。具体到数据库设计、缓存设计、队列使用等技术细节，我认为都不是问题。关键之处，是要守住契约，按照我们今天所讲的三大步骤尝试落地。

过去的几年间，我曾在多个企业内建设高性能的 IT 系统架构，很好地服务了用户，使用的就是我们今天所讲的各个方法和思维框架。我个人感觉，过程也是相对轻松的。

需要注意的是，如果时间充足且落实到位，系统确实不会出现高性能问题。可是实际情况是，团队没有时间做完整的高性能设计，没有预算做全链路压测，所以埋下了隐患。

这时，我建议相关负责人要去识别最关键的服务，针对性地进行设计、测试，确保关键服务没有问题，并且，为非关键服务提供降级和熔断处理的开关。

另外一个比较常见的情况，是企业决策层将高性能的设计问题和技术问题混为一谈：看似是技术能力太过欠缺，其实是契约和设计没有做好。**任何复杂问题都可以被拆解为简单问题，只要拆解得足够细致。一定要牢记这一点，这种思维能力是技术人的安身立命之本。**

当然，如果你有问题或想交流的内容，也不要犹豫，立刻在评论区写出来，我会认真回复。

我们下一讲再见。
