This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
<audio id="audio" title="04 | 性能工程三定律IT业和性能优化工作的“法律法规”" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/e6/38/e6e42842d89b3f64f681779d8cb0a238.mp3"></audio>
你好,我是庄振运。
在开篇的几讲里,我谈了性能工程的重要性以及所需要的知识面,接下来我们就正式地进入相关的学习。
不过不要着急,第一个模块我们并不会直接进入性能问题的现场,一上来就去解决问题,而是要先耐下心来,学习一些必备的基础知识。为什么呢?因为学习任何事情,打好坚实的基础是至关重要的。
古人云:“合抱之木,生于毫末;九层之台,起于累土。”
所以接下来的几讲,我们需要先学习一些基础知识,包括和性能工程相关的几个重要定律法则和数理基础。这一讲我先和你探讨三个定律法则:帕累托法则、阿姆达尔定律和利特尔法则。
## 帕累托法则
我想你可能知道帕累托法则,它也被称为 80/20 法则、关键少数法则,或者八二法则。
这个法则是基于我们生活中的认识产生的人们在生活中发现很多变量的分布是不均匀的——在很多场景下大约20%的因素操控着80%的局面。也就是说所有的变量中比较重要的只有20%,是所谓的“关键少数”。剩下的多数,却没有那么重要。
举例来讲在企业销售中根据帕累托法则大约“80的销售额来自20的客户”。认识到这一点对企业管理至关重要比如需要重视大客户的关系。
虽然帕累托法则在生活中很多方面都适用,但我们今天的重点是来看看**帕累托法则是怎么应用到我们IT界**的,尤其是怎么指导我们的代码开发和性能优化相关的领域的。
我总结了一下,这个法则可以有以下几个领域的指导。
<img src="https://static001.geekbang.org/resource/image/9d/1d/9d99b547cbf2074144203f2ec2806c1d.png" alt="">
**1.应用程序的使用**
一个应用程序往往可以提供很多功能。但是如果我们统计用户的使用情况会经常发现大约80%的用户使用集中在20%的程序功能。
所以,对我们开发程序的指导意义是,要花足够心思在最常用的少数功能模块上,对它的设计和实现都要充分地优化。
**2.程序代码开发时间的分配**
一个程序的开发过程中大约80%的代码开发只占用了20%的总体开发时间。一般来讲,一个应用程序开发时,一开始往往花不了多少时间就可以快速地搭建一个大体可以工作的原型。反而是后面的剩余代码和代码改进需要更多的时间。
也就是说80%的开发时间往往用在最精髓的20%代码上。帕累托法则对我们的指导意义是,对代码开发工作量的安排上,需要合理有序地规划好开发时间。
**3.程序代码的维护**
如果观察代码的维护和改进历史你经常会发现少数代码被不断地改动甚至经常被改得面目全非而多数代码几乎从第一次写完后就一成不变了。按照帕累托法则80%的代码演进和改动发生在大约20%的代码上。
对程序维护而言我们需要对这20%的代码尽量熟悉,这样才能对其他程序员的代码改动了如指掌,一目了然。
**4.程序代码的修正和纠错**
统计数字也表明所有的代码错误中差不多有80%的错误发生在大约20%的代码上。
所以根据帕累托法则代码修复和纠错时要重点修复最容易产生Bug的代码这样才能把保证整个应用程序的合理质量。
**5.客户流量的时间分布**
估计80的流量将在总时间段的特定20内发生。比如一个商业软件客户的流量峰值往往是上班时间开始的那几个小时比如上午9点到12点
所以,我们在应用程序设计和部署时,要充分考虑帕累托法则带来的影响,尤其是客户访问的峰值时段和空闲时段。
**6.程序代码的优化**
一个程序完成后必然会去运行如果我们统计代码的运行时间往往会发现程序的80%的时间是在运行大约20%的代码。也就是说,只有少数代码非常频繁地被调用。
所以,如果我们想提高程序的性能,最好找出这些少数代码,并做重点优化,这样就可以用很少的改动大幅度地提升整个程序和系统的性能。
那么现在,我们就从性能优化的角度,来看看如何参照帕累托法则,来规划我们性能优化工作的投入和产出。
假设我们的性能优化投入永远是按照代码的优先级来投入的也就是说总是要先优化最值得优化的代码。那么我们看到只要投入差不多20%的努力就能产出80%的性能优化产出,获得最大的投入产出比。
下图是一个根据帕累托法则来投入努力和产出效果的过程。
<img src="https://static001.geekbang.org/resource/image/bc/11/bc49ec2e4107878d6069c84252e92311.png" alt="">
假如先解决20%的最重要的问题就可以达到总体效果的80%。以后再花费80%的努力也只能解决剩下的20%的问题。
在应用帕累托法则的时候需要注意的是里面的80%或者20%都是大约数字,实际的场景千差万别,不可能是恰好这两个数字。这个法则的精髓是,我们的生活和自然界万物的分布不是均匀的,总有些因素比其他因素更重要。
## 阿姆达尔定律
接下来我们来看第二个定律。这个定律你可能会感觉有点陌生。
**阿姆达尔定律**Amdahls law / Amdahls argument是计算机科学界非常重要的一个定律和法则。它本来用于衡量处理器进行并行处理时总体性能的提升度。但其实阿姆达尔定律可以用在很多方面为了方便你理解我们就从一个简单的生活例子开始。
我们用洗衣服和晾衣服来举例。这里假设我们不用洗衣机而是用传统的方式先洗再晾。再假设洗衣服和晾衣服各需要10分钟那么整个过程进行完需要20分钟。
<img src="https://static001.geekbang.org/resource/image/21/f2/21936de65dad5d3821ae6312799529f2.png" alt="">
如果我们对晾衣服的过程进行优化从10分钟缩短到5分钟相当于进行了两倍优化。现在整个过程需要多长时间呢需要15分钟因为洗衣服的模块还是需要10分钟。
<img src="https://static001.geekbang.org/resource/image/42/7a/420a4b5cecbf15d13d4c7fc83211947a.png" alt="">
在这个基础上我们继续对晾衣服模块进行优化速度提升5倍从10分钟缩短到2分钟。整个过程现在需要12分钟完成。
<img src="https://static001.geekbang.org/resource/image/73/18/73e4fa8f29685a1dc120cf66d1a95218.png" alt="">
在这个基础上继续进行类推我们就会发现无论对晾衣服模块进行多大的优化整个洗衣服、晾衣服的过程所需的时间不会小于10分钟也就是整体加速比不会超过2。
根据阿姆达尔定律描述科学计算中用多处理器进行并行加速时总体程序受限于程序所需的串行时间百分比。譬如说一个程序50%是串行的其他一半可以并行那么最大的加速比就是2。无论用多少处理器并行这个加速比不可能提高到大于2。
所以在这种情况下,改进程序本身的串行算法可能比用多核处理器并行更有效。
用公式来讲假设一个系统的整体运行时间是1其中要进行优化加速的模块运行用时是P。如果对这个模块的加速比是N那么新系统的处理时间可以用下面的公式来表示。
<img src="https://static001.geekbang.org/resource/image/5e/af/5e654721a7dc896068afe5dc653b94af.png" alt="">
这里面1-P是未被加速的其他模块运行时间而N分之P是优化后的模块运行时间。它们的和就是新系统的总体运行时间。
相对于旧系统,运行时间的加速比就是:
<img src="https://static001.geekbang.org/resource/image/50/ed/50adf0c81433aa34ed91f08319504fed.png" alt="">
阿姆达尔定律对我们进行性能优化的指导意义有以下2点。
1. 优先加速占用时间最多的模块,因为这样可以最大限度地提升加速比。
1. 对一个性能优化的计划可以做出准确的效果预估和整个系统的性能预测。
下面这张图描述了不同的并行百分比场景下分别进行并行优化的曲线。不同的曲线对应不同的并行模块百分比。横轴是并行程度,也就是多少个并行处理器。纵轴是速度提升度。
<img src="https://static001.geekbang.org/resource/image/c4/30/c4fee8386932e98bcf2d20cb67de2130.png" alt="">
对每一条曲线我们都可以看到,超过一定的并行度后,就很难进行进一步的速度提升了。
另外说明一点阿姆达尔定律其实是另外一个定律的简化版本。这个更复杂的定律叫通用扩展定律USL, Universal Scalability Law你有兴趣的话可以去学习一下。
## 利特尔法则
接下来我们来看利特尔法则Littles Law。这个法则描述的是在一个稳定的系统中长期的平均客户人数N等于客户抵达速度X乘以客户在这个系统中平均处理时间W也就是说N=XW。
这个法则看起来有点不直观,但从整个系统的宏观角度仔细想想的话就容易理解了。
如下图所示客户按照一定的速度不断地进入我们的系统假设这个速度是每分钟X个客户。每个客户在我们系统里的平均处理时间是W分钟。一旦处理完毕客户就不会滞留在我们的系统里。
<img src="https://static001.geekbang.org/resource/image/40/89/408c046dc1722db99058ce0bbcf94389.png" alt="">
所以如果这个状态稳定也就是说我们的系统处理速度恰恰好赶上客户到达速度的话一方面系统没有空闲另外一方面客户也不需要排队在系统外等待。那么在这个稳定状态下我们的系统的总容量就恰好等于系统里面正在处理的客户数目。也就是说N就等于X和W的乘积。
我举一个服务器性能提升的例子来解释吧。
假定我们所开发的服务器程序可以进行并发处理,同时处理多个客户请求。并发的客户访问速度是**每分钟到来1000个客户**,每个客户在我们的服务器上花费的**平均时间为2分钟**。根据利特尔法则在任何时刻我们服务器系统里面将容纳1000×22000个客户。这2000个客户都在被服务。
过了一段时间由于客户群的增大并发的访问速度从每分钟1000客户增大到**每分钟2000个客户**。在这样的情况下,我们该如何改进我们系统的性能来应对呢?
根据利特尔法则,我们可以有两种方案来解决这一需求。
第一种方案是把客户的处理时间减半从2分钟减到1分钟。这样我们的系统容量可以不变客户滞留在我们系统的时间减半刚刚好可以适应访问速率加倍的要求。系统容量就等于2000客户每分钟乘以1分钟还是2000个客户。
第二种方案是扩大系统容量维持处理时间不变。因为客户访问速度加倍了所以系统容量也需要加倍变成4000。假如原来的系统需要500台服务器那么新系统就需要1000台服务器。
从这里可以引申出利特尔法则在性能优化工作中的两种用处:
1. **帮助我们设计性能测试的环境**。性能测试的内容我们后面会详细讲到,这里简单提一下。比如当我们需要模拟一个固定容量的系统,那么性能测试的客户请求流量速度和每个请求的延时都需要仔细考虑。
1. **帮助我们验证测试结果的正确性**。有时候,如果性能测试的工作没有仔细地规划,得出的测试结果会出奇得好,或者出奇得差,从而让我们抓脑壳。这时如果采用利特尔法则,就可以很快地发现问题所在之处。
## 总结
我们今天讨论的性能工程相关的三大法则,分别是帕累托法则、阿姆达尔定律和利特尔法则。
可以说这些法则就是IT业和性能优化工作的“法律法规”有了它们我们在实际工作中才能做到“有法可依有法必依”。熟悉并熟练应用这几个法则对我们的工作是会有很大的帮助的。
<img src="https://static001.geekbang.org/resource/image/74/dc/74b119d052157540473f3d75870c64dc.png" alt="">
孟子说:“不以规矩,不能成方圆。”熟悉并熟练应用这几个“规律法则”,对我们的工作是会有很大的帮助的。
## 思考题
帕累托法则可以用到很多场景下,除了本讲中讨论的场景,你还能想到什么场景可以使用帕累托法则呢?使用这个法则会帮助你对问题的把握和找寻解决思路吗?
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。

View File

@@ -0,0 +1,143 @@
<audio id="audio" title="05 | 概率统计和排队论:做性能工作必须懂的数理基础" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/58/02/58e283997d7eedf36b1e1c031adc7b02.mp3"></audio>
你好,我是庄振运。
上一讲我们讲了和性能优化有关的三大基础定律法则。今天我们继续打基础,讲一点统计方面的数理知识,包括重要的**概率统计**和**排队论**。
或许你对概率统计和排队论有点发怵,但这些内容是必须学会的,因为它们很重要。因为它们是性能测试和优化这座高楼大厦的地基。地基打不好,性能测试和优化也不会做得很好。
而且我想强调的是你完全没有必要惧怕因为你只需要学习一部分最基础的知识这些知识对多数人和多数场合大体就够了。还记得上一讲的帕累托法则吗根据帕累托法则这一讲的内容或许占不到平时教科书内容的20%但却可以覆盖80%以上的应用场合。
## 概率和置信区间
今天的内容我们先从概率和置信区间讲起。
**概率**Probability也称几率和机率是一个在0到1之间的实数是对随机事件发生之可能性的度量。这个你应该都懂不需要我多说。
但概率论中有一个很重要的定理,叫贝叶斯定理,我们做性能测试和分析中经常需要用到,所以我们稍微讲讲。
**贝叶斯定理**Bayes theorem描述的是在已知一些条件下某事件的发生概率。比如如果已知某癌症与寿命有关合理运用贝叶斯定理就可以通过得知某人年龄来更加准确地计算出他患上该癌症的概率。
具体来讲对两个事件A和B而言“发生事件A”在“事件B发生”的条件下的概率与“发生事件B”在“事件A发生”的条件下的概率是不一样的。
然而这两者的发生概率却是有确定的关系的。就是A事件发生的概率乘以A事件下B事件发生的概率这个乘积等于B事件发生概率乘以B事件下A发生的概率。听起来有点拗口可如果用公式来表示的话其实很简单。
<img src="https://static001.geekbang.org/resource/image/0e/01/0e2e128d5a44743f1b20edb58b2da201.png" alt="">
贝叶斯定理的一个用途在于**通过已知的任意三个概率函数推出第四个**。
另外一个重要的概念是置信区间。**置信区间**Confidence intervalCI是对产生样本的总体**参数分布**Parametric Distribution中的某一个未知参数值以区间形式给出的估计。相对于后面我们要讲到的点估计指标比如均值中位数等置信区间蕴含了**估计精确度**的信息。
置信区间是对分布(尤其是正态分布)的一种深入研究。通过对样本的计算,得到对某个总体参数的区间估计,展现为总体参数的真实值有多少概率落在所计算的区间里。比如下图是一个标准正态分布的图,阴影部分显示的是置信区间[-1.7,1.7]占了91%的概率。
<img src="https://static001.geekbang.org/resource/image/e3/b0/e3500b3104e42f0c906eb5587f02d9b0.png" alt="">
不难理解置信水平越高置信区间就会越宽。一般来说如果需要涵盖绝大多数的情况置信区间一般会选择90%或者95%。
了解了概率和置信区间,我们下面去看看如何分析大量数据。
## 数理统计的点估计指标
做性能测试和优化的过程中会产生大量的数据,比如客户请求的吞吐率,请求的延迟等等。获得这些大量数据后,如何分析和理解这些数据就是一门学问了。通常我们需要处理一下这些数据来求得另外的指标,以方便描述和理解。
描述性统计分析是传统数据分析的基础,这个分析过程可以产生一些描述性指标,比如平均值、中位数、最大值、最小值、百分位数等。
这些描述性指标通常也被称为“**点估计**”,相对于前面讲到的置信区间,是用一个样本统计量来估计参数值,比较容易理解。这些点估计指标分别有不同的优点和缺点。
**平均值**Mean或称均值平均数是最常用测度值它的目的是确定一组数据的均衡点。但不足之处是它容易受极端值影响。比如公司的平均收入如果有一两个员工有特别高的收入会把大家的平均收入拉高就是平时我们经常调侃的“被平均”。
需要注意的是我们有好几种不同的平均值算法。我们平时比较常用的是算术平均值就是把N个数据相加后的和除以N。但是还有几种其他计算方法分别适用不同的情况。比如几何平均数就是把N个数据相乘后的乘积开 N次方。
**中位数**Median又称中值将数值集合划分为相等的上下两部分一般是把数据以升序或降序排列后处于最中间的数。它的优点是不受极端值的影响但是如果数据呈现一些特殊的分布比如二向分布中位数的表达会受很大的负面影响。
**四分位数**Quartile是把所有数值由小到大排列并分成四等份处于三个分割点位置的数值就是四分位数。 从小到大分别叫做第一四分位数,第二四分位数等等。四分位数的优点是简单,固定了三个分割点位置。缺点也正是这几个位置太固定,因此不能更普遍地描述其他位置。
**百分位数**Percentile可以看作是四分位数的扩展是将一组数据从小到大排序某一百分位所对应数据的值就称为这一百分位的百分位数以Pk表示第k个百分位数。比如常用的百分位数是P90P95等等。百分位数不容易受极端值影响因为有100个位置可以选取相对四分位数适用范围更广。
几个特殊的百分位数也很有意思比如P50其实就是中位数P0其实就是最小值P100其实就是最大值。
还要注意的是,面对同一组数据,平均值和中位数以及百分位数这些点估计指标,谁大谁小是不一定的,这取决于这组数据的具体离散程度。
比如我在面试的时候我经常问来面试的人一个问题就是平均值和P99哪个比较大答案就是不确定。
**方差/标准差**VarianceStandard Variance描述的是变量的离散程度也就是该变量离其期望值的距离。
## 重要的分布模型
以上的几个描述性的**点估计统计指标**很简单,但是描述数据的功能很有限。如果需要更加直观并准确的描述,就需要了解分布模型了。
举例来讲,假设我们有一个系统,观察对客户请求的响应时间。如果面对一万个这样的数据,如何对这个数据集合进行描述呢?这时候用分布模型来描述就很合适。
我们简单提一下几个最重要的分布模型,包括泊松分布、二项式分布和正态分布。
**泊松分布**Poisson distribution适合于描述单位时间内随机事件发生的次数的概率分布。如某一服务设施在一定时间内收到的服务请求的次数等。
具体讲如果随机变量X取0和一切正整数值在n次独立试验中出现的次数x恰为k次的概率PX=k就是
<img src="https://static001.geekbang.org/resource/image/0a/f9/0a7765813ce1a4fdd02079c47e6873f9.png" alt="">
公式中λ是单位时间内随机事件的平均发生次数。像下面这个图,表示的就是λ=5的分布。红色部分是P(X=4)的概率约为0.17。
<img src="https://static001.geekbang.org/resource/image/19/42/195f8c16c7462871a0705461841d9542.png" alt="">
当n很大且在一次试验中出现的概率P很小时泊松分布近似二项式分布。
**二项分布**Binomial distribution是n个独立的是/非试验中成功的次数的离散概率分布。
这里通常重复n次独立的伯努利试验Bernoulli trial。在每次试验中只有两种可能的结果而且两种结果发生与否互相对立并且相互独立。也就是说事件发生与否的概率在每一次独立试验中都保持不变与其它各次试验结果无关。
当试验次数为1时二项分布服从比较简单的0-1分布。
在n重伯努利试验中假设一个事件A成功的概率是p, 那么恰好发生 k 次的概率为:
<img src="https://static001.geekbang.org/resource/image/37/f1/37d156e7e163181ff25d4a14716119f1.png" alt="">
比如下图就是一个二项分布的图图中红色的是P(X=5)的概率约为0.18。
<img src="https://static001.geekbang.org/resource/image/8b/ec/8b0d08564e9868f17fb9c69f62446cec.png" alt="">
**正态分布**Normal distribution也叫高斯分布Gaussian distribution。经常用来代表一个不明的随机变量。
正态分布的曲线呈钟型,两头低,中间高,左右对称,因此经常被称之为钟形曲线。比如下图:
<img src="https://static001.geekbang.org/resource/image/37/d8/37ecaee54e21b987cda50c0cb0e510d8.png" alt="">
一个正态分布往往记为N(μ,σ^2)。其中的期望值μ决定了其位置,其标准差σ决定了分布的幅度。概率密度函数如下:
<img src="https://static001.geekbang.org/resource/image/61/d1/61b9b73ec360fc63a1ee5a22d3aa32d1.png" alt="">
当μ = 0σ = 1时的正态分布是标准正态分布。上图就是一个标准正态分布线段的值代表了置信区间。比如在期望值附近左右各一个标准差的范围内差不多可以囊括68.2%的概率各两个标准差的范围内囊括95.4%的概率各三个标准差的范围内囊括99.7%的概率。
正态分布的重要性在于,大多数我们碰到的未知数据都呈正态分布状。这意味着**我们在不清楚总体分布情况时,可以用正态分布来模拟**。
好了,我们这里学习了三个重要分布。如果你看不懂或者记不住这三个分布的公式也没有关系,你只要知道每个分布的大概适应场景就可以了。实际的工作中,很多工具都能帮助我们分析,很少需要我们去具体推导。
## 排队的理论
上面谈到的三个分布经常被应用到排队理论中而排队理论在性能工程方面是非常重要的。计算机系统中的很多模块比如网络数据发送和接收、CPU的调度、存储IO、数据库查询处理等等都是用队列来缓冲请求的因此排队理论经常被用来做各种性能的建模分析。
**排队论**Queuing Theory也被称为随机服务系统理论。这个理论能帮助我们正确地设计和有效运行各个服务系统使之发挥最佳效益。
排队论的系统里面有几个重要模块,比如顾客输入过程、队列、排队规则、服务机构等。几个模块之间的关系大体上可以用下面这张图来表示。
<img src="https://static001.geekbang.org/resource/image/f2/89/f2088a63dfc4756ecc12d765c0e30389.png" alt="">
主要的输入参数是到达速度、顾客到达分布、排队的规则、服务机构处理速度和处理模型等。
排队系统的输出也有很多的参数,比较重要的是排队长度、等待时间、系统负载水平和空闲率等。所有这些输入、输出参数和我们进行的性能测试和优化都息息相关。
排队的模型有很多,平时我们用得多的有**单队列单服务台**和**多队列多服务台**。系统里面各个模块的模型都可以变化,排队论里面还有很多延伸理论。
## 总结
要想精通任何一门学问和工作牢固的基础是必须的。对IT工作包括设计系统、编写程序、系统维护和性能优化而言牢固的数学基础会使我们的工作如虎添翼。这正如古人赞赏梅花时所说得“不经一番寒彻骨怎得梅花扑鼻香“。
我们也常说“根深才能叶茂”,今天讲的内容,包括概率统计和分布模型的知识,都是这样的基础和根基,希望你能牢牢掌握。
## 思考题
- 你们公司的系统和提供的服务中,有没有性能方面的指标要求?
- 这种指标要求是怎么表述的?比如是平均值,还是某些百分位数?
- 为什么要这样规定指标要求?
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。

View File

@@ -0,0 +1,114 @@
<audio id="audio" title="06 | 性能数据的分析:如何从大量数据中看出想要的信号?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ca/35/caaaaeb5a525e71830cbe2d1b38e1035.mp3"></audio>
你好,我是庄振运。
我们这一讲来谈谈如何分析我们所得到的性能数据。现代的应用程序和互联网服务系统都比较复杂,要关心的性能参数也很多,所以你从各种渠道得到的性能相关的数据量往往很大。那么要如何从大量的数据中找出我们所关心的特征和规律呢?这就需要你对数据做各种分析和对比了。
这一讲要解决的核心问题就是:**如何从大量数据中看出想看的信号?**
当人沉浸在大量数据中时,是很容易迷失的。而“不识庐山真面目”的原因,当然是“只缘身在此山中”了。但这不能作为借口,我们需要练就“慧眼识珠”的本领,做到对各种性能数据一目了然,才能够做出一针见血的分析。
为了帮助你练就这样的本领,今天我们首先讲一下常见的算法复杂度和性能分析的目的,然后针对一个性能指标来分析,再延伸到对多个性能指标进行对比分析,最后谈谈进行数据分析的几个教训和注意点。
## 算法的时间复杂度
先简单地聊一下算法的时间复杂度Time Complexity。复杂度一般表示为一个函数来定性描述该算法的期待运行时间常用大O符号表述。
考虑程序和算法的时间复杂度时,大家通常关注的是某个解决方案属于哪个时间复杂度。具体来讲,有六种复杂度是比较普遍的,这里按照从快到慢的次序依次介绍:
1. 常数时间O(1):判断一个数字是奇数还是偶数。
1. 对数时间O(Log(N)):你很熟悉的对排序数组的二分查找。
1. 线性时间O(N):对一个无序数组的搜索来查找某个值。
1. 线性对数时间O(N Log(N)):最快的排序算法,比如希尔排序,就是这个复杂度。
1. 二次时间O(N^2):最直观也最慢的排序算法,比如冒泡,就是这个复杂度。
1. 指数时间O(2^N) 比如使用动态规划解决旅行推销员问题。这种复杂度的解决方案一般不好。
把这几个算法复杂度放在一张图中表示出来,你可以清楚地看出它们的增长速度。
<img src="https://static001.geekbang.org/resource/image/1e/00/1e07480a265a7f017463bffba2293b00.png" alt="">
大体上来讲前四种算法复杂度比较合理而后面两种也就是N平方和指数时间就不太能接受了因为在数据量大的时候运行时间很快就超标了。
## 性能数据分析的目的
说完常见的算法复杂度,我们再来看看做性能数据分析的目的是什么。
性能相关的数据有很多种比如系统和模块的运行时间、客户访问延迟、客户滞留时间、服务吞吐率、程序的CPU占用时间等等。最常见的性能数据就是客户的访问延迟、吞吐量和运行时间。比如我们如果去分析某个应用程序或者代码模块的运行时间往往就会立刻暴露其相应的性能。
当收集到性能数据以后我们首先需要判断它们的值到底是正常还是不正常这就需要经验和知识才能判断。比如一个简单的数据库服务查询一般端到端的延迟也就几百毫秒。如果这个值是10秒钟那么就不太正常。发现不正常的数据一般就需要做更多的分析和测试来发现原因比如是网络延迟数据库的服务延迟抑或是其他问题。
再举一个例子如果我们是在测量硬盘的访问时间如果发现这个指标超过1秒那么很可能磁盘这边出异常了。
如果观测到针对某个指标的一系列性能数据那就需要判断这个指标有没有随着时间或者其他变量的变化而变差Regression和变好Improvement然后需要根据这个判断进行进一步的分析及采取措施。
我们还经常需要对某个性能指标做预测。这种情况就需要研究数据的趋势Trend。根据情况做些预测分析比如根据这个指标的历史数据来进行曲线拟合。
有时候某个性能指标会出现问题,比如如果应用程序有内存消耗和内存泄漏,那么我们就需要测量更多的相关指标来做深层的分析,来发现到底是哪个模块,哪行代码导致了内存泄漏。
我们也经常需要把几个性能指标的数据联系起来一起分析。比如发现系统的性能瓶颈在哪里是在CPU的使用上、网络上还是存储的IO读写上等等。如果应用程序和系统性能出了问题那么考察多个性能指标的数据和它们的关系可以帮我们做根因分析发现真正的问题所在。
## 对一个时间序列的分析
一般来讲,一个性能指标,按照时间顺序得到的观测值,可以看作是一个时间序列。很多分析就是针对这个时间序列进行的。
首先需要指出的是性能数据的时间序列往往不是均匀平滑的反而会有各种有规律的峰值。比如客户对一个网站的访问量是随着时间变化而变化的。每天24小时都不同对多数互联网系统来讲白天上班时间的访问量比较大每周7天里面工作日流量比较大而节假日比如新年的流量又和其他时间不同。所以需要你根据具体的情况来决定要不要做特殊的考虑。
再有一点就是对网站而言客户响应时间往往需要考虑百分位的数字比如P90、P95、P99甚至P99.9的用户响应时间。因为这些数字可以保证一个系统的响应时间是不是满足了绝大多数用户的要求。
那么,针对一个性能数据的时间序列,我们要如何看数据的规律和趋势呢?
经常使用的方法是进行**线性回归分析**Linear Regression。线性回归是通过拟合自变量与因变量之间最佳线性关系来预测目标变量的方法。线性回归往往可以预测未来的数据点。比如根据过去几年的每月消费支出数据来预测明年的每月支出是多少。
注意所谓的“最佳”线性关系是指在给定形状的情况下没有其他位置会产生更少的误差。如下图所示以平面点为例如果有N个样本点线性回归算法就是求一条直线Y=f(X)。使得各点到这个曲线的距离的绝对值之和最小。
<img src="https://static001.geekbang.org/resource/image/02/c1/0276bc0587f50bee356b49bee5b369c1.png" alt="">
除了研究数据的趋势和未来预测,还有几种重要的分析,比如**分类**Classification、**聚类**Clustering以及**决策树**Decision Tree。分类是将类别分配给数据集合帮助更准确地预测和分析。聚类是把相似的东西分到一组。决策树也叫分类树或回归树每个叶节点存放一个类别****每个非叶节点表示一个特征属性上的测试。
## 对不同时间序列的分析
在一大堆性能数据面前,经常需要比较各个性能指标的时间序列来确定一个系统和服务的瓶颈,也就是最制约系统性能扩展的资源。
在多数情况下瓶颈资源是常用的几种比如CPU、网络、内存和存储。但是有些情况下其他不太常见的资源也可能成为瓶颈比如转换检测缓冲区TLBTranslation Lookaside Buffer这个我们以后会讲到
如果几个时间序列在时间上是一致的但是对应不同的性能指标比如一个是CPU的使用率另一个是吞吐率。我们有时候需要研究时间序列的相关性Correlation of time series从中可以得出很多有用的观察推断。
数据的相关性是指数据之间存在某种关系,可以是正相关,也可以是负相关。两个数据之间有很多种不同的相关关系。比如,我们经常需要计算两个随机矢量 X 和 Y 之间的协方差covX, YCovariance)来衡量它们之间是正相关还是负相关,以及它的具体相关度。
## 数据分析的教训和陷阱
性能数据的分析并不容易,一不小心就会落入各种陷阱或者踩到坑。下面举几个需要特别注意的方面。
**第一是数据的相关和因果关系。**
有时候几个时间序列之间可以很清楚地看出有很强的相关性质,但是对它们之间的因果关系却不能判定。换句话说,通过单纯的数据分析可以证实数据的相关性,但是还需要其他知识才能更准确地判断谁是因、谁是果。这一点我们必须非常清楚,因为在很多性能问题讨论和根因分析的场合,我们非常容易武断地犯这样的错误,而导致走弯路。
更复杂的情况是有时候系统性能变坏,是因为几个指标互为因果,或者构成**环形因果**,也就是互相推波助澜。实际分析起来非常有挑战性,这就需要我们对整个系统和各个性能指标了如指掌。
**第二是数据的大小和趋势。**
面对性能相关的数据并判断它们是“好”还是“坏”是很难的。经常听到有人问一个问题:
“客户平均访问逗留时间多长比较好?”
这个问题没有一个简单的答案。这取决于每个网站的特性,以及我们想要实现的目标。对一个网站而言很正常的逗留时间,可能对另一个网站而言非常糟糕。在很多情况下,比单纯数字大小更重要的是数据的趋势,比如某个时期是上升还是下降,变化的幅度有多大等等。
**第三是数据干净与否。**
如果数据集合来自多个数据源,或者来自复杂的测试环境,我们需要特别注意这些数据里面有没有无效数据。如果不能剔除无效数据,那么整体数据就“不干净”,由此而得出的结论经常会“失之毫厘,谬以千里”。
**第四是对性能数据内在关系的理解。**
性能数据分析的核心就是要理解各个性能指标的关系并且根据数据的变化来推断得出各种结论比如故障判别、根因分析。如果简单地把性能数据当作普通的时间序列来分析那就往往没有抓住精髓。举个简单例子Linux系统的空闲内存其实就是一条时间序列它或许显示快到0了看起来性能问题出在这里。但是稍微了解Linux系统内存管理知识的人就知道这个指标非常不可靠。
## 总结
性能工程和优化离不开对大量性能数据的研究和分析,那么如何“拨开云雾见天日”,看出里面的端倪和问题呢?我们这一讲就讨论了几种情况,包括对一个和多个时间序列的分析;也讨论进行数据分析的时候需要注意的地方。
古人讲“格物致知”;对我们来讲,性能数据就是我们要“格”的物。只有合理而系统地分析这些数据,才能收获“守得云开见月明”的恍然大悟之感。
## 思考题
对数据的统计分析和处理需要遵循科学的方法,否则,如果处理不当,根据数据得出的结论会严重误导你。回想一下过去的工作中,有没有这样的例子?从这些例子中有没有学到教训?
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。

View File

@@ -0,0 +1,157 @@
<audio id="audio" title="07 | 性能数据的展示:一图胜千言,说出你的数据故事" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/53/bf/536102f14909ec2f72310c8ad0b3c1bf.mp3"></audio>
你好,我是庄振运。
这一讲我们来探讨一下如何把性能数据合情合理地展示出来,让别人一目了然。如果你想有效地说服别人,那么你展示的过程就要像讲一个有趣的故事,娓娓道来,让别人爱听才行。
数据的展示根据场景有不同的目的,所以不能千篇一律,需要量体裁衣。每一种场景下,数据展示要根据你的**具体目的**、**听众的特点**和**内容的特点**而采用合适的图表。然后用这些图表做支持,把一个精美的数据分析的“故事”讲出来。
## 性能数据展示的目标和目的
我们先理清一下性能数据展示的目的是什么。
我们前面讲过,性能工作相对复杂,牵扯的模块和构件较多,而且有时候也要牵扯几个不同的部门。数据分析有时是为了性能优化,有时是为了根因分析等等。所以性能数据展示的目的也就有很多种,主要有如下三种:
1. 向上级报告性能趋势和流量预测的结果;
1. 向运维部门描述性能问题的根因分析;
1. 向开发部门建议性能提升和代码优化。
目标不同,听众不同,如何展示数据自然也就不能相同。但不管如何,都要做到有根有据,条理清楚,层次分明。这样大家才会被你和你展示的数据所说服。具体来讲,你希望你的听众:
1. 同意你的理论方法和过程;
1. 信服你的推理分析;
1. 理解问题的核心;
1. 看出问题的根因;
1. 同意你的建议和方案;
## 性能数据展示的挑战和难点
目的清楚了,下面就是怎么做了。但是我们必须认识到,相对于一般数据的展示,性能数据的展示有其独到的特点、挑战和难点:
- **数据量大** :做性能测量时往往性能指标很多,每个指标一般都是一个时间序列。一个复杂系统/性能问题有几十甚至几百个性能指标是经常遇到的,所以总的数据样本经常以百万以上计。
- **数据复杂**:几十或几百的性能指标互相交互和影响,需要考虑它们之间的复杂关系。
- **性能问题复杂**:性能分析不是简单地死扣数据,还需要考虑互联网系统的协议,计算机的设计,和软硬知识的结合。
- **牵扯的模块多**:很多性能问题都不是孤立的,都和其他模块和子系统,甚至客户请求有关系。
## 数据展示的经验
在考虑用什么方式来展示数据时,的确有些讲究,这就需要多借鉴别人的经验。在这方面,我总结了下面六条经验。
1. **按客人来备菜**:既然展示的听众不同,所以千篇一律的用同一种展示方法绝不可行。比如向领导和管理层汇报时,就要注重宏观层次,技术不要钻地太深。
1. **有啥菜吃啥饭**:要根据手头数据的特点来决定展示方法。比如你有好几组相关的数据,有很有趣的趋势,那就要用线图来展示趋势和相关性。
1. **给足上下文**:很多工程人员容易犯的错误,就是想当然地以为别人也都了解问题的背景,然后一上来就展示很多细节。其实除了你自己,没有第二个人更了解你要解决的问题和要展示的数据,所以一定要给足背景介绍和上下文信息。
1. **用图讲故事**:人人喜欢听故事,而且是有趣的故事。如果你能把整个分析和推理的过程,变成一个引人入胜和图文并茂的故事来讲,那我保证你的展示会非常地成功。
1. **和听众交互**:尽量鼓励听众参与讲故事的过程。有两种类型的数据叙事:叙述型和探索型。叙述型是通过描述告诉观众具体结论;而探索型是鼓励观众探索数据以得出结论。虽然探索型叙事稍微多花一点时间,但若能成功运用,听众更容易被说服;因为结论是他们自己得出的,而不是你告诉他们的。
1. **总结重要点**:在数据展示的最后,一定要简洁明了地总结你的展示。比如你希望听众最后只记住三句话,是哪三句呢?根据你的展示目的,这三句或是相关数字,或是趋势,或是问题本质,或是解决方案。
## 数据图表的种类
数据往往是枯燥的,所以我们要想办法变枯燥未有趣。用图表来展示数据就是一个好方法,但关键是要用合适的图表来展示不同的数据。
虽然数据图表的种类很多但常用的就10种左右。我来简单地给你总结一下这几种常用的图表分别适合什么情况和表示什么样的数据。
### 表格Table
表格你一定经常用,它的优点是可以结构化的方式显示大量信息;不幸的是,这个优点恰恰也是缺点。很多用户其实对数据的趋势比具体的数值更有兴趣,这种情况下用表格就不是那么直观。
### 线图Line Chart)
如果我们希望针对一个变量,显示一段时间内这个变量的变化或趋势,线图就最合适了。比如我们经常表示的时间序列图就是最直白的线图。
另外,它也适用多个变量的情况,可以很直观地显示两个或多个变量之间的关系,比如趋势和相关性。
### PDF和CDF图
对于一个变量的概率数据,我们经常会显示这两个互相关联的图。二者可以看作是稍微特殊的线图。
**PDF**概率密度函数Probability Density Function是连续型随机变量的概率密度函数或简称为密度函数。就是一个描述这个随机变量的输出值在某个确定的取值点附近的可能性的函数。
**CDF**: 累积分布函数 (Cumulative Distribution Function)又叫分布函数是概率密度函数PDF的积分。换句话说PDF就是CDF的导数。CDF能完整描述一个实随机变量X的概率分布。
我们举一个前面讲过的例子比如标准正态分布。它的PDF和对应的CDF是这个样子。
<img src="https://static001.geekbang.org/resource/image/53/e3/533c87181e922b207e52fc8d323521e3.png" alt="">
### 面积图Area Charts
面积图类似于线图,但两者之间有细微的差别。面积图的重点是阴影线下方的区域。
如果想用面积图表示几组数据,那么具体也有两种选择:可以选择采用叠加面积图或非叠加面积图。
比如下图就是一个叠加面积图,它显示了几个产品在不同季度的单季产量和总产量。
<img src="https://static001.geekbang.org/resource/image/6b/bb/6bad8b4e214f7d9d91170646119cf0bb.png" alt="">
### 柱状图和条形图Bar Charts
用于比较不同类别的数量,比较容易理解。如果你想表示好几个变量,那么也可以选择叠加方式来显示。
比如下面这个柱状叠加图,显示的是和上面的面积图同样的数据,只是表示的方法不同。
<img src="https://static001.geekbang.org/resource/image/81/5f/81f1a8237cdd53cb631d08693e978a5f.png" alt="">
### 散点图Scatter Plots和气泡图Bubble Charts
**散点图**显示沿两个轴绘制的两个变量的值用点的模式揭示它们之间存在的任何相关性。比如两个变量分别是CPU使用量和客户吞吐率那么我们可以期望散点图会显示比较强的同一趋势。
**气泡图**类似于散点图,但它可以显示三个数据项之间的变化。除了两个变量分别为是横轴和纵轴外,气泡的大小代表第三个变量。
<img src="https://static001.geekbang.org/resource/image/26/31/26eb07e8905372a40c41c49b64dfc131.png" alt="">
我们举一个例子。比如一个公司里面有十个互联网产品,每个产品运行在不同数目的服务器上面。这些产品分别有不同的内存使用率和网络使用率。假设我们想分析一下产品的内存和网络的使用情况,然后决定下一个季度购买什么样的服务器。我们就可以用气泡图来表示,网络和内存的使用率来作为横轴和竖轴,气泡的大小代表每个产品的服务器数目。
通过这个气泡图,我们非常直观地发现,某个产品的气泡比其他产品都大,而且它的两种资源使用率都很低。整体来言,下个季度新采购的服务器可以不需要那么多内存和网络资源。
### 饼图和圆环图Pie Charts Donut Charts
当需要显示比例数据或者百分比时,饼图最佳。由于饼图表示零件与整个实体之间的大小关系,因此零件需要总和必须为有意义的整体。
一个适合饼图表示的性能数据例子是客户请求的来源分布。但你在使用时需要注意的是,饼图最好用来显示六个或更少的类别。如果太多类别的话反而描述不清楚。
举一个前面讲面积图时候用过的例子,公司的四种产品在春季的销售分布,就可以用下面这个饼图表示。
<img src="https://static001.geekbang.org/resource/image/54/02/54e07c61e57f08f398769c2d10499702.png" alt="">
### 树形图Treemaps
树形图对于显示类别和子类别之间的层次结构和比较值非常有用,同时也能保留较多细节。树形图可以帮助我们很直觉地感知哪些区域最重要。另外,还可以通过将颜色编码的矩形嵌套在彼此内部,来更好地实现目的,并用加权以反映它们在整体中的份额。
比如下面这个树形图,它描绘了一个国外的产品,采用不同营销渠道的价值,然后按国家/地区细分。
<img src="https://static001.geekbang.org/resource/image/39/bc/39ccc1ee89312d7d7d78009ad66311bc.png" alt="">
这里的营销渠道包括Email、Social Media、AdWords等。从这个图中你一眼就能看出从营销渠道上来看AdWords是最成功的营销渠道因为它对应的面积最大。但是从国家层面来讲美国United States是所有渠道中最有价值的目的地同样是因为对应的面积最大。
### 热图Heatmaps
热表以表格格式来表示数据,其中每个格子是用颜色,而不仅仅是用数字来展示。这些颜色分别对应包含定义的范围,如绿色代表小的值,黄色代表一般的值和红色代表大的值。
比如分析几台服务器的在一天里面CPU的使用率。我们可以把每台服务器在每个时段的CPU使用率分为小、较小、中等、较大和大等几个范围。然后相应地着色。
我们看下图横坐标代表时段纵坐标是服务器每个值就是CPU使用率。
<img src="https://static001.geekbang.org/resource/image/0e/f4/0ea22fae8afe53bad9763d75a811b6f4.png" alt="">
虽然每个使用率其实是数字但是把数字编码为颜色的好处是颜色编码格式使数据更容易理解。比如我们马上就可以看出早上10点的时候服务器1和5的CPU使用率很高因为它们的格子是红色。
## 总结
<img src="https://static001.geekbang.org/resource/image/b6/ab/b65ebe300caf5f7abd6bd79ac70abcab.png" alt="">
我们都学过宋朝的词人柳永的词,他有两句词是这么写的:
“便纵有千种风情,更与何人说?”
这里他其实是在感叹自己虽有满腹经纶和深厚情感,但无人可以诉说。我们虽然不是词人,但在做过性能测试或者根因分析后,可能经常会有很多新奇的发现,希望向同事和领导讲解。
但是性能问题往往牵涉很广,描述起来并不容易,别人可能很难理解。这时候我们的感觉就是“我有千种风情”,可是如何说啊?
希望通过这一讲,能让你对在图文并茂地来“诉说”这方面能有些提升。
## 思考题
- 对本讲介绍的几种图形,你对哪些比较熟悉并经常使用?
- 哪些是不熟悉的但觉得可能会很有用的?
- 对不熟悉的图形,你能不能花十几分钟时间去仔细学习一下并尝试使用呢?
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。

View File

@@ -0,0 +1,136 @@
<audio id="audio" title="08 | 经验总结:必须熟记的一组常用性能数字" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/c0/b2/c0e5d19ef81c83d09ee25e15955262b2.mp3"></audio>
你好,我是庄振运。
今天这一讲是”数理基础“这一部分的最后一讲,我在这一讲会给你总结一组性能相关的常用的数字。这些数字在做性能和设计方面的工作时经常用到。它们就像九九乘法表一样,我希望你能熟记在心。
记住这些数字的好处是,每次看到一个性能相关的数据的时候,我们立刻就能知道这个性能数据有没有问题。
举个简单例子如果我们看到一个硬盘的IO读写延迟经常在500毫秒左右我们立刻就知道这里面有性能问题。反之如果硬盘IO读写延迟小于1毫秒我们可以马上推断——这些IO读写并没有到达硬盘那里是被操作系统缓存挡住了。这就是大家常说的“对数字有感觉”。
人们常说“腹有诗书气自华”。同理,如果我们能对系统和程序运行中常见的性能指标了如指掌,就有可能达到那种“一眼就看出问题”的大师级别。
为了方便理解和记忆我把这些数字分成几大类分别是存储、CPU、操作系统、内存和网络等并且会给出具体的单个数值。
## 有言在先
但是我必须强调说明的是,我之所以给出具体的单个数值,是为了方便你记忆,并让你对性能指标“有感觉”。因为**单个值**比给出**数值范围**更直观。
比如传统硬盘的IO延迟如果我冠冕堂皇地说“IO延迟的大小取决于很多因素比如硬盘型号、IO大小、随机还是连续、磁头离数据的远近等从小于1毫米到几秒钟不等。“这样的说法当然对但是并不能帮助你找到数字的感觉所以直观指导意义不是很大。
所以我想强调,我给出的数字仅供参考,帮助你记忆和理解,更重要的目的是**让你对不同环境下的性能数据有所感觉**。你要更加注重它们之间的量级比较比如SSD的随机IOPS的性能可以轻松地达到普通硬盘HDD的1000倍以上。
至于具体的性能数字的值大小,却也可能对一个非常具体的场景不那么匹配。这有几个原因:
1. 因为市场上有很多种类和很多厂家的产品具体的值都不一样比如SSD的一些性能指标就是如此。
1. 因为每个具体场景都不同比如IO的读写大小。还有就是我们的技术不断进步就如同CPU的频率具体的值是一直在变的。
这些性能数据多半和**延迟**有关所以要弄清楚这些延迟的单位。你应该都知道一秒钟是1000毫秒ms一毫秒是1000微秒us一微秒是1000纳秒ns
## 存储相关
我们先看存储相关的性能数据。存储有很多种常用的是传统硬盘HDD, Hard Drive Disk和固态硬盘SSD, Solid State Drive。硬盘的厂家和产品多种多样而且具体的配置也有很多种比如大家熟悉的磁盘阵列RAID)。我们这里仅仅选取最普遍的硬盘和最简单的配置。
值得一说的是SSD。最近几年SSD的技术发展和市场演化非常迅速。随着市场规模的增大和技术的进步SSD的价格已经极大地降低了。在很多大规模的在线后台系统中SSD几乎已经成了标准配置。
SSD的种类很多按照技术来说有单层SLC和多层MLCTLC等。按照质量和性能来分有企业级和普通级。根据安装的接口和协议来分有SAS、SATA、PCIe和NVMe等。
对所有的存储来说,有三个基本的性能指标。
1. IO读写延迟。一般是用4KB大小的IO做基准来测试
1. IO带宽一般是针对比较大的IO而言
1. IOPS就是每秒钟可以读写多少个小的随机IO。
下面这个表格列出了几种存储介质和它们的性能数值。
<img src="https://static001.geekbang.org/resource/image/46/65/4601c4eb6ecc8e48643d189e7af72565.jpg" alt="">
我们这里考虑三种情况: 传统硬盘SATA SSD和NVMe SSD。你可以看到一般传统硬盘的随机IO读写延迟是8毫秒的样子IO带宽大约100MB每秒而随机IO读写一般就是每秒100出头。
SSD的随机IO延迟比传统硬盘快百倍以上IO带宽也高很多倍随机IOPS更是快了上千倍。
## CPU和内存相关
再来看看CPU。说起CPU相关的性能数字就必须先说CPU的时钟频率也就是主频。主频反映了CPU工作节拍也就直接决定了CPU周期大小。
**主频和周期大小。<strong>比如基于英特尔Skylake微处理器架构的i7的一款其主频为4GHz那么每一个时钟周期Cycle大约**0.25纳秒</strong>ns
CPU运行程序时最基本的执行单位是指令。而每一条指令的执行都需要经过四步指令获取、指令解码、指令执行、数据存入。这些操作都是按照CPU周期来进行的一般需要好几个周期。
**CPI和IPC**
每个指令周期数CPI和每个周期指令数IPC其实是孪生兄弟衡量的是同一个东西。
CPIcycles per instruction衡量平均每条指令的平均时钟周期个数。它的反面是 IPCinstructions per cycle。虽然一个指令的执行过程需要多个周期但IPC是可以大于1的因为现代CPU都采用流水线结构。一般来讲测量应用程序运行时的IPC如果**低于1**这个运行的系统性能就不是太好需要做些优化来提高IPC。
**MIPS**
MIPS就是每秒执行的百万指令数。
我们经常会需要比较不同CPU硬件的性能MIPS就是一个很好的指标一般来讲MIPS越高CPU性能越高。MIPS可以通过主频和IPC相乘得到也就是说MIPS=主频×IPC。这个很容易理解比如一个CPU频率再高IPC是0的话性能就是0。假设一个CPU的主频是4GHzIPC是1那么这个CPU的**MIPS就是4000**。注意的是MIPS是理论值实际运行环境数量一般小于这个值。
**CPU缓存**
一般CPU都有几级缓存分别称为L1、L2、L3按这个顺序越来越慢也越来越大当然成本也越来越低。L3有时候也称为LLCLast Level Cache因为L3经常是最后一级缓存。多核CPU的情况下一般L1和L2在核上而L3是各个核共享的。
我用下面的表格来表示一款2GHz主频的CPU进行寄存器和缓存访问的一般延迟分别用时钟周期数和绝对时间来表示同时也给出在每个CPU核上面的字节大小。重复一下数字仅供参考因为每款CPU都不同。
<img src="https://static001.geekbang.org/resource/image/7d/3d/7d5c3088fbd1463637ffb0641fc68b3d.jpg" alt="">
比如一般L3的访问需要40个时钟周期2GHz主频的话就是20纳秒大小一般是每个核平均下来2MB的样子。
为了方便对比,我们把内存的性能也放在同一个表格里。
值得一提的是现在的NUMA非统一内存访问Non-Uniform Memory Access处理器会有**本地**和**远端内存**的区别,当访问本地节点的内存是会快一些。
## 操作系统和应用程序相关
我们刚刚谈了硬件方面,下面看看软件,也就是操作系统和应用程序。
首先,你需要弄清楚如下的几个重要概念和指标。
**1.指令分支延迟**
CPU需要先获取指令然后才能执行。获取下一条指令时需要知道指令地址如果这个地址需要根据现有的指令计算结果才能决定那么就构成了指令分支。CPU通常会采取提前提取指令这项优化来提高性能但是如果是指令分支那么就可能预测错误预先提取的指令分支并没有被执行。
指令分支判断错误Branch Mispredict的时间代价是很昂贵的。如果判断预测正确可能只需要一个时钟周期如果判断错误就需要十几个时钟周期来重新提取指令这个延迟一般在**10纳秒**左右。
**2.互斥加锁和解锁**
互斥锁Mutex也叫Lock是在多线程中用来同步的可以保证没有两个线程同时运行在受保护的关键区域。使用互斥锁的时候需要加锁和解锁都是时间很昂贵的操作每个操作一般需要几十个时钟周期**10纳秒**以上。
**3.上下文切换**
多个进程或线程共享CPU的时候就需要经常做上下文切换Context switch。这种切换在CPU时间和缓存上都很大代价尤其是进程切换。在时间上上下文切换可能需要几千个时钟周期**1微秒1us级别**。在缓存代价上多级CPU缓存和TLB缓存都需要恢复所以可能极大地降低程序线程和进程性能。
## 网络相关
互联网服务最终是要面向终端客户的,客户和服务器的延迟对用户的服务体验至关重要。
网络的传输延迟是和地理距离相关的。网络信号传递速度不可能超过光速一般光纤中速度是每毫秒200公里左右。如果考虑往返时间RTTRound Trip Time那么可以大致说每100公里就需要一毫秒。北京到深圳约2,000公里RTT就是20毫秒上海到乌鲁木齐或者美国的东西海岸之间距离差不多4,000公里所以RTT是40毫秒左右中国到美国比如北京到美国西海岸旧金山差不多10,000公里RTT就是100毫秒。
在数据中心里面一般的传输RTT不超过半毫秒。如果是同一个机柜里面的两台主机之间那么延迟就更小了小于0.1毫秒。
仔细想想的话你就会发现直线距离本身还不够因为数据是通过骨干网光纤网络传播的。如果光纤网络绕路的话那么实际的RTT会超过以上估算数值。
另外要注意的是传输延迟也取决于传输数据的大小因为各种网络协议都是按照数据包来传输的包的大小会有影响。比如一个20KB大小的数据用1Gbps的网络传输仅仅网卡发送延迟就是0.2毫秒。
下面这个表格就总结了几种环境下的端到端的距离和RTT。
<img src="https://static001.geekbang.org/resource/image/d0/cd/d0c2d6ebd3efa2dd8666cb26fb8002cd.jpg" alt="">
## 总结
今天讲了几十个平时经常用到的性能数字,希望起到抛砖引玉的效果。你可以在此基础上,在广度和深度上继续扩展记忆。
<img src="https://static001.geekbang.org/resource/image/82/d8/82ee900f120d3717e67da7ac54a6ffd8.png" alt="">
宋代诗人苏轼曾经作诗夸奖朋友:“前身子美只君是,信手拈来俱天成”,这里的“子美”是唐朝大诗人杜甫的字。这两句是夸朋友写文章写得好,能自由纯熟的选用词语或应用典故,用不着怎么思考,不必费心寻找,如同杜甫转世。
我们如果对各种性能数据足够熟悉,如掌上观纹,自然也就能达到那种对性能问题的分析信手拈来的境界。
## 思考题
假设你们公司有个互联网服务要上线服务的要求是用户端到端响应时间不能超过40毫秒。假设服务器在武汉那么对上海的用户可以达到响应时间的要求吗
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。