什么是软件的性能?该怎么衡量与优化?

分类: 架构设计

保留所有版权,请引用而不是转载本文(原文地址 https://yeecode.top/blog/135/ )。

我们写代码、聊架构的时候,经常把"高性能"三个字挂在嘴边。但你要是真被人问一句"高性能到底指什么",不少人会愣一下。今天咱们就把这个词掰开揉碎,看看它背后到底对应着软件质量的哪些维度,以及我们平时是怎么衡量、又该怎么去优化它的。

什么是软件的性能

先说一个反直觉的点:在软件工程那套权威的《ISO/IEC 25010》质量模型里,其实压根没有"性能"这个特性维度。

那"性能"是从哪来的?它其实是个俗称,主要对应着软件质量模型里的两个大维度:效率(efficiency)和可靠性(reliability)。一个软件如果在效率和可靠性上都表现不错,我们才会说它是"高性能"的。

具体点说,在 ISO 25010 里,效率又拆成了三个子特性:

  • 时间效率(Time behaviour):执行功能时,响应时间、处理时间、吞吐率达标的情况。
  • 资源利用率(Resource utilization):执行功能时,占用的资源数量和类型达不达标。
  • 容量(Capacity):系统各项参数的最大上限达不达标。比如能存多少条数据、撑多少并发用户、通信带宽多大、事务吞吐多少、数据库多大。

而可靠性则拆成了四个子特性:

  • 成熟度(Maturity):正常操作下满足可靠性需求的程度。
  • 可用性(Availability):要用的时候,系统可操作、可访问的程度。
  • 容错性(Fault tolerance):哪怕硬件或软件出了故障,系统还能按预期跑的程度。
  • 可恢复性(Recoverability):出了中断或故障,能不能把受影响的数据恢复回来、把系统状态重新建起来。比如故障后计算机要关一阵子,关多久,就看可恢复性。

所以,“高性能"的软件,得在这七个子特性上都有好表现。说大白话就是:处理能力强、响应快、容量大、故障率低、不容易崩、崩了恢复也快。

为什么要死磕高性能?因为咱们国家的互联网用户群体太庞大了。海量的软件——尤其是互联网软件——得扛住巨量用户的访问:更短时间响应用户操作、用更少的资源服务更多人、存下更多用户的数据。这对软件的性能,提出了极高的要求。

怎么衡量软件的性能

聊完了"高性能"到底指什么,接下来我们逐个认识那些被归到"性能"名下的具体指标。日常里衡量软件性能,最常被提起的就是下面这三个。

吞吐量

“吞吐量"这个词最早是从电信网络那边借来的,指的是在一条通信信道上,单位时间里能成功传送的平均数据量。挪到软件系统里,它的意思也差不多:软件系统在单位时间里,能接收和发出多少数据量。

不过要注意,吞吐量是个挺"模糊"的概念。不同系统、不同请求,对应的数据量不一样,操作复杂度也不一样,所以很难拿吞吐量去横向比较两个不同的系统。

日常里,我们更常用几个更具体的指标来代表吞吐量,最典型的就是 TPS 和 QPS:

  • TPS(Transaction Per Second):每秒处理的事务数。这里的事务,一般指一次完整的操作,包含请求、变更、返回等全流程。
  • QPS(Queries Per Second):每秒进行的查询数。

TPS 和 QPS 是有关联的,但这个关联并不固定。比如我们把"呈现一个页面"当成一个事务,那一个 TPS 里往往就包了好几个 QPS——因为一个页面通常要查 HTML、CSS、图片等好几个资源。所以 TPS 和 QPS 之间怎么换算,得看具体的业务场景。

也正因为不同系统处理的事务、查询的内容千差万别,TPS 和 QPS 很难用来精确比出两个系统谁强谁弱;它们更多是用来衡量"同一个系统"在不同时间、不同环境下的性能变化。

正因为吞吐量这么"虚”,本书后面统一用"吞吐量"这个词,来代表系统处理用户请求的能力。

并发数

说完吞吐量,另一个高频词就是"并发数"了。不过"并发数"和吞吐量一样,也是个挺宽泛的概念,它底下其实包含了好几样东西:

  • 并发用户数:同时使用软件功能的用户人数。但这里面,有些用户可能只是登录了,并没真在操作。
  • 并发连接数:软件承载的连接数量。这些连接里,有些正在传数据,有些仅仅只是保持着连接。
  • 并发请求数:软件同时扛着的请求数量。这些请求里,有的可能只是要个静态资源,有的可能要做读写操作。
  • 并发线程数:这是衡量系统内部运行情况的指标,指软件内部跑着的线程数。不同业务操作,触发的线程数也不一样。

你看,上面这四样,没有哪一个是绝对清晰、绝对准确的——它们各自都有"含混"的地方。

所以本书同样做了个统一约定:不再去纠结某一种具体的并发数,而是统一用"并发数"这个词,来代表系统同时服务的调用方有多少。

平均响应时间

前面讲的吞吐量和并发数,都是衡量软件系统的重要指标。但站在一个"用户"的角度——这个用户可能是人,也可能是另一个系统——他其实根本感知不到这两个指标。用户作为一个个体,既不知道系统的吞吐量高低,也不知道此刻并发数是多少。用户能感受到的,是另一个指标:响应时间。

响应时间,指的是用户发出调用请求,到收到系统回应,这中间花的时间。这个时间越短,体验就越好。

放大到整个系统上,对应的指标就是平均响应时间,也就是系统服务的所有请求的响应时间的平均值。

系统内部往往由很多模块组成,每个模块也都有自己的响应时间。我们想提升系统的平均响应时间,通常就是从提升各个模块的响应时间入手。这时候,就要请出阿姆达尔定律(Amdahl’s Law)了。

阿姆达尔定律描述的是:当系统中某个模块的执行速度被提升时,整个系统的执行速度能提升多少。

它先定义了"加速比"这个概念。假设我们优化了某个模块 $m$,让它的平均响应时间从 $T_{m,old}$ 缩短成了 $T_{m,new}$,那么这次优化带来的模块加速比 $r_m$ 就是:

$$r_m=\frac{T_{m,old}}{T_{m,new}}$$

模块优化完之后,系统的平均响应时间也会跟着变短。而系统平均响应时间的变化,取决于下面两个因素:

  • 增强比例 $p$:优化之前,被优化的模块的平均响应时间,占系统平均响应时间的比例。这个值总是小于等于 1。
  • 模块加速比 $r_m$:就是上面那个对模块做优化带来的加速比。

于是,系统优化后的新平均响应时间 $T_{s,new}$ 可以这样算:

$$T_{s,new} = T_{s,old} \times \left [ (1-p) + \frac{p}{r_m} \right ]$$

其中 $T_{s,old}$ 是系统原来的平均响应时间。

而因为这次模块优化,给整个系统带来的加速比 $r_s$ 则是:

$$r_s = \frac{T_{s,old}}{T_{s,new}} = \frac{1}{\left [ (1-p) + \frac{p}{r_m} \right ]}$$

从这个公式能看出来一个很实在的结论:想提高系统的整体加速比,就该盯住那些"平均响应时间占比高"的模块,想办法把它们的加速比尽量提上去。把力气花在刀刃上,才最划算。

怎么优化软件的性能

把上面三个指标串起来看,优化软件性能的思路就很清楚了:用户最终感知的是响应时间,而响应时间由系统里各个模块的响应时间决定。阿姆达尔定律告诉我们,优化的性价比最高处,永远是那些"平均响应时间占比高"的模块——把有限的精力投在刀刃上,整体加速比才上得去;反过来,花大量力气去优化一个占比很小的模块,对系统整体的改善微乎其微。

具体到落地手段,比如缓存、并发编程、数据库调优、IO 优化、高可用设计等等,每一块都有一套相当系统的玩法。这些内容在《高性能架构之道(第二版)》里做了完整的展开。


在AI编程迅猛发展的今天,编码能力则逐步弱化,而架构能力则成了每个开发者更为核心的能力。聊完软件的性能和它的衡量、优化,如果你觉得架构、性能这些话题有意思,强烈推荐一本书《高性能架构之道(第二版)》。

这是一本理论联系实际的架构书,系统讲了怎么从顶层把软件架构好:覆盖分布式、并发编程、数据库调优、缓存、IO、高可用、前端性能优化等众多知识,最后还拿一个真实项目完整走了一遍架构全过程,把书里的方法真正落了地。

高性能架构之道(第二版)

《高性能架构之道(第二版)》

这本书还在台湾地区出了繁体版,叫《巨型服务架构》——繁体版嘛,贵得有点离谱。

就先聊到这儿。

我是软件架构师易哥。可以关注我,我会偶尔冒个泡,分享点编程干货!

可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。

作者书籍推荐

作者书籍推荐 作者书籍推荐