当我 1989 年加入 Oracle 公司时,性能优化(大家称之为“Oracle 调优”)尚非易事。 只有少数人声称他们能做得很好,并以此获得很高的咨询率。情况迫使我进入“Oracle 调优”领域时,我却毫无准备。与20多年前 Oracle 的经历非常相似,最近我被引荐入“MySQL 调优”领域。
它唤起了我的许多回忆,那时我大约13岁,多么艰难的开始学习代数。在那个年纪,我不得不强烈地依赖于试错才能完成。我记得看到一个方程,比如 3x + 4 = 13,基本上磕磕绊绊得到答案,x=3。
解决简单的方程式,试错法速度缓慢、不好用,随着问题变得复杂,却不再成立,例如:3x + 4 = 14,接下来呢?问题在于我还没有把代数思考清楚。直到15岁时,詹姆斯·哈基(James R. Harkey)老师指引我走上解决该问题的道路。
在高中时,哈基先生教导我们使用他所谓的公理化方法来求解代数方程。 他教给我们一套每次都有效的步骤(而且给了我们大量的作业作为练习)。此外,通过执行这些步骤,随着解答我们必须记录下我们的想法。使用一系列可靠且可重复的步骤,我们不仅思考得很清楚,还向阅读我们作业的人证明我们思考得很清楚。
给哈基先生的作业类似如下:
3.1x + 4 = 13 // 待求解方程 3.1x + 4 - 4 = 13 - 4 // 减去相等的值 3.1x = 9 // 加法逆运算,化简 3.1x ∕ 3.1 = 9 ∕ 3.1 // 除以相等的值 x ≈ 2.903 // 乘法逆运算,化简
哈基先生解决代数、几何学、三角学和微积分的公理化方法就是这样:一次只需一小步,合乎逻辑的、可证明的、可审查的一步。这是我第一次真正掌握数学。
自然,当时我并没有意识到,却证明是我在课后的世界中取得成功至关重要的一项技能。在生活中,我发现了解事物很重要,但向别人证明事物更重要。没有良好的证明技术,很难成为一名优秀的顾问、一名优秀的领导者,甚至是一名优秀的员工。
自1990年代中期以来,我的目标一直是为 Oracle 性能优化创建类似的严格方法。最近,我将目标的范围扩展到Oracle之外:“创建一个计算机软件性能优化的公理化方法。”我发现没有多少人喜欢我这样说,所以换而言之:“我的目标是帮助你清楚地思考如何优化你的计算机软件的性能。”
什么是性能?
搜索 performance
一词可以得到超过5亿次点击的概念,涉及从自行车比赛,到许多公司如今正在尝试避免的、可怕的员工评估流程。大多数热门话题都与本文的主题有关:计算机软件执行您要执行的任务所花费的时间。
任务,一个面向业务的工作单位,是一个很重要的概念。任务可以嵌套:“打印发票”是一项任务;“打印一张发票”(一个子任务)也是一个任务。对于计算机用户而言,性能通常是指系统执行某些任务所花费的时间。响应时间是任务执行的持续时间,以每次任务的时间来衡量,例如:“每次点击的秒数”。 例如,我在 Google 搜索单词 performance
的响应时间为0.24秒。 Google 网页直接在浏览器中显示了该数据。以此向我证明 Google 重视我对 Google 性能的看法。
有些人关心另一种性能衡量标准:吞吐量,在指定时间间隔内完成的任务执行次数,例如“一秒内的点击次数”。 通常,负责团队绩效的人比单独贡献者角色的人更关心吞吐量。例如,单个会计师通常更关心每日报告的响应时间是否会需要该会计师推迟下班。账户中心的经理还关心系统是否能够处理组内所有会计师要处理的数据。
响应时间 vs 吞吐量
吞吐量和响应时间通常具有倒数关系,但不完全如此。真正的关系微妙地复杂。
例一:想象一下,在某些基准测试种,吞吐量是每秒1000个任务。那么,您的用户的平均响应时间是多少?人们很容易认为平均响应时间是每个任务1/1000=.001秒,但并非一定如此。
想象一下,处理此吞吐量的系统具有1000个并行、独立、同质的服务通道(也就是说,它是一个具有1000个独立、同等服务能力的系统,每个都在等待服务的请求)。在这种情况下,每个请求可能都恰好消耗了1秒。
现在,您就知道每个任务的平均响应时间介于0到1秒之间。但是,仅凭吞吐量测量数据,您不能得出响应时间。您必须单独度量它(我仔细地在此句中包含 exclusively
这个词,因为有些数学模型可以计算给定吞吐量的响应时间,但模型需要更多输入,而不仅仅是吞吐量)。
反之也同样成立。你当然可以反过来证明该例子。然而,一个更惊人的例子会更有趣。
例二:您的客户要求你正在编写的新任务,在一台单CPU计算机上实现每秒100次任务的吞吐量。假如您编写的新任务只需0.001秒即可在客户的系统上执行完毕。您的程序能否会满足客户所需的吞吐量?
人们很容易认为,如果可以在千分之一秒内运行一次任务,那么毫无疑问,能够在一秒钟内运行该任务至少100次。如果任务请求被很好地串行化,你的程序可以在循环内,一个接一个地执行客户要求的100次任务,此时你是对的。
但是,如果有100个不同的用户登陆到你的单CPU计算机,每秒100次任务随机出现在您的系统该怎样?最终,CPU调度程序和串行资源(例如 Oracle latch、lock 以及存储缓冲区的可写访问)的可怕现实可能会限制您的吞吐量,使其数量大大少于所要求的每秒100次任务。如此可能可行,也可能不行。仅凭响应时间测量数据,您不能得出响应时间。你必须单独度量它。
响应时间和吞吐量不一定是倒数。要了解两者,需要对它们都进行度量。哪个更重要?对于特定情况,您可以从不同角度合理的回答。在许多情况下,答案是两者都是至关重要的测量数据,都需要管理。例如,系统所有者可能面临以下业务要求,对于给定任务,不仅要99%及以上的执行,响应时间必须小于等于1.0秒,且系统必须支持10分钟内持续不低于1000次任务执行的吞吐量。
百分位指标
在上一节中,我使用“99%及以上的执行”短语来衡量响应时间期望。许多人更习惯于“平均响应时间必须为r秒或更短”这样的描述。百分位方式的描述需求更符合人类的经验。
例三:假设每天在你计算机上执行的某些任务响应时间的公差为1秒。进一步假设 table 1 中显示的数字列表表示该任务执行10次测得的响应时间。每列的平均响应时间均为1.000秒。你认为哪一个更好?
尽管 table 1 中的两列具有相同的平均响应时间,但两列的特征却大不相同。List A,90%的响应时间小于等于1秒。List B,只有60%的响应时间小于等于1秒。反而言之,List B 代表一组40%不满意的用户体验,但 List A(具有与 List B 相同的平均响应时间)仅有10%的不满意率。
List A 第90百分位数响应时间是.987秒;List B 为1.273秒。这些关于百分位数的陈述比仅仅说每个列表代表1.000秒的平均响应时间更具参考价值。
正如 GE 所说,“我们的客户会感受到方差,而不是平均值”[4]。将响应时间目标表示为百分位,可以得出更具说服力的需求规约,以符合最终用户的期望:例如,“快件跟踪”任务至少99.9%的执行必须小于0.5秒内完成。