高性能设计-契约精神
高性能设计-契约精神

高性能设计-契约精神

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

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

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

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

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

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

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

对于系统响应时间,我们还有一个更直观的监控指标,叫做 Top 百分数 (Top Percentile),简称 TP。比如, TP 90 = 2s,意思是,90% 的请求的响应时间都在 2s 内;那么 TP 99 = 2s 的意思就是 99% 的请求的响应时间都在 2s 内;我们一般说的 RT = 2s,指的是平均响应时间,可以作为参考,但实际意义可能并不大。

当我们明确了 TP 90 或者 TP 99 这一有关系统响应时间的指标时,一个交付给用户的“契约”就出现了。守好诸多类似的契约,也就是保证了高性能设计。

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

描述刚刚签订的高性能“契约”:本系统、组件、服务承诺在任何情况、任何资源、任何压力高峰下,都保证 TP 90 = 2s 。

这个契约就是不明确、不清晰、不具体的。

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

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

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

对于管理者或架构师而言,理想的契约应该是“保证设计流量内的用户 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. 为架构做好“保护系统”:做好系统的流量控制;
  2. 使架构具备扩容能力:储备额外的计算资源,提升弹性扩容的速度;
  3. 提升系统各组件处理能力:识别高并发情境中的资源争抢情况,同时注意保留架构的可扩展性。

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

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

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

一般来说,该做的系统扩容,通常很早就完成了,架构设计真正缺乏的是应急手段。毕竟,你不能“不分青红皂白”,将每个系统的应急扩容都提前做好。一个经营稳健的企业,是不会允许这样的开销出现的。

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

双十一来了,你通过监控平台,看到在线用户数量快速增长,很快突破了 200 万,流量控制机制开始生效,新用户进入排队序列。你考虑了 3 秒钟,然后做了一个决定:系统需要扩容。于是,你轻轻地输入一个数字,按下回车。3 秒钟后,排队序列消失了。你对旁边的同学说,继续监控吧!然后悠闲地端起茶杯,离开了座位。这将是一种多么美妙的工作状态?更棒的是,以上场景完全有可能实现。

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

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

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

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

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

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

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

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

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

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

做好隔离后,我们也要注意提升架构的可扩展性。

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

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

任何复杂问题都可以被拆解为简单问题,只要拆解得足够细致。一定要牢记这一点,这种思维能力是技术人的安身立命之本。

发表评论

邮箱地址不会被公开。