这一章是一个系统性能案例研究:讲述了一个真实世界性能问题的故事,从最初的报告到最终解决。这个特定的问题发生在一个生产环境的云计算环境中;我选择它作为系统性能分析的一个常规示例。
我在本章的目的不是引入新的技术内容,而是利用叙事来展示工具和方法如何在实践中应用,即在真实的工作环境中。这对于那些尚未处理过真实系统性能问题的初学者应该特别有用,它提供了一个跟踪专家如何处理这些问题的视角,评论了在分析过程中专家可能会考虑的事情,以及为什么会这样。这并不一定是记录最佳可能的方法,而是为什么采取了某种方法。
所有姓名已被更改以保护无辜者。与实际服务器、在线或离线的任何相似之处纯属巧合。
13.1 Case Study: The Red Whale
你有新邮件了!
嘿,Brendan,我知道我们在这里不断切换话题,但如果你明天有时间的话,能否看一下这个NiftyFy服务器?它可能与你对性能的一些现有发现一致。Nathan看了一下,但无法确定原因。
这是来自销售代表詹姆斯的一封电子邮件,他将帮助台工单复制并粘贴到了邮件中。我有点烦躁;我正在同时解决另外两个案例,不想被打扰。
我在Joyent工作,这是一个云计算提供商。虽然我在工程部门工作,但我也是我们支持和运营团队性能问题的最终升级点。客户问题可能与任何运行在SmartOS Zones上的应用程序或数据库,或者Linux或Windows的KVM实例有关。
我决定立即着手解决这个新问题,并花大约15分钟来查看,希望能找到一些快速的答案。如果看起来可能需要更长时间,我就需要将其优先级与我正在处理的其他案例进行比较。
第一步是阅读帮助台工单,了解问题陈述。
13.1.1 Problem Statement
问题描述了软件版本和配置,并评论了CPU使用率的变化性。客户最近才转移到Joyent SmartMachines(SmartOS Zones),惊讶地发现他们可以使用系统工具观察物理CPU,包括由所有租户组合引起的利用率。
我扫描了他们的描述,找出以下信息:
- 他们认为存在性能问题的原因是什么?
- 他们的问题(如果有的话)可以用延迟或运行时间来表达吗?
对第一个问题的回答将告诉我问题可能有多真实,我可以用第二个问题来自行检查问题。许多工单最终只是关于系统度量标准的混淆,而不是真正的应用程序问题,所以尽早验证这一点可以节省时间。然而,这两个问题的答案并不总是一开始就可用。
从客户描述中,我了解到他们正在使用一个叫做Redis的应用程序,并且:
- 使用traceroute(1M)命令来测试到服务器的网络路径和延迟,并且报告了数据包丢失。
- 有时Redis的延迟超过一秒。客户怀疑这两个发现之间有关联。然而,第一个细节让我觉得问题实际上并不是真实的:在这些系统上,traceroute(1M)默认使用UDP协议,这是允许不可靠的,因此网络基础设施可能会丢弃那些数据包以优先处理更重要的TCP数据包。如果他们使用的是基于TCP的测试,数据包丢失不应该发生或者是可以忽略的。
第二点是有用的——我可以测量的东西。
根据之前具有类似细节的案例,我可以猜测我的最终结论将是以下之一,甚至可以预测每种情况的可能性:
- 60%:traceroute(1M)丢包是一个误导,而一秒的Redis延迟实际上是由某种应用程序级别的原因引起的。
- 30%:traceroute(1M)丢包是一个误导。导致一秒Redis延迟的是完全不同的问题。
- 10%:traceroute(1M)丢包与问题相关——网络实际上正在丢包。
第一个,最有可能(60%)的结果是那种以“哦,是的,它应该是这样的”结束的类型。对于客户来说可能是新的,因为他们刚学习Redis,但对于Redis专家来说是显而易见的。
13.1.2 Support
工单历史记录包含Joyent支持团队如何分析问题的详细信息。当他们得知客户正在使用第三方监控工具来分析Redis性能时,他们要求访问该工具,并确认延迟有时会像报告的那样急剧上升。他们还尝试使用traceroute(1M)来重现数据包丢失,但未能成功。他们指出,源位置可能很重要,如果traceroute(1M)采用不同的网络路径,一些路径可能比其他路径不太可靠(这是一个很好的猜测)。他们尝试从不同位置进行测试,但仍无法重现数据包丢失。然后,运维团队的Nathan接手了。他设置了curl(1)来测量延迟,使用附近的主机作为客户端,以最小化涉及的网络组件。通过在循环中调用curl(1),他最终能够捕获到一次超过200毫秒的延迟,虽然不是预期的一秒,但仍远远超过正常水平,他在测试中发现正常水平不到1毫秒。换句话说:一个异常值。他还使用自己的临时清单快速检查系统。他发现CPU正常,有足够的空闲资源,并且网络I/O是适度的,但没有引起问题。由于几个原因,问题似乎越来越不可能是由网络数据包丢失引起的:首先,Nathan在同一数据中心使用附近的客户端进行了测试。要在200毫秒的异常值中导致数据包丢失,必须存在我们数据中心内交换机和路由器的问题——考虑到它们的可靠性,这似乎不太可能发生。200毫秒的延迟对于这些系统来说太短,不足以触发TCP重传。顺便说一下,有两个特定的延迟会提示“TCP重传!”:1.125秒和3.375秒。这些奇怪的数字是由于内核TCP代码的一个怪异部分(在illumos内核的tcp_init_values()中)略微增加了1秒和3秒的值。我们可能应该修复那段代码——过去它曾让客户感到困惑,这不是一件好事。另一方面,这些奇怪的数字通常很有用,它们的奇怪值很快提示出TCP重传:“我有这些3.4秒的异常值……”然而,在这种情况下,显然不是TCP重传引起了问题——200毫秒太短了。尽管这可能排除了TCP重传(除非对于我来说,它们的操作方式有未知的未知),但并未排除网络问题。Nathan的数据中心测试意味着网络问题不太可能发生,但我意识到它们仍然是可能的。
13.1.3 Getting Started
我给詹姆斯发了一条聊天消息,告诉他我会立即查看这个问题。詹姆斯告诉我他希望我做什么:目前,怀疑是Redis本身出了问题,而我们的服务器没问题。詹姆斯准备把问题退回给客户,但希望我再次确认系统是否正常,也许可以通过我最近开发并成功使用过的一些新的DTrace脚本来实现。像以前一样,我会把我的发现交给詹姆斯,他会处理与客户和支持部门的沟通,让我专注于解决问题。
我还没有完成阅读支持历史记录,但我登录到目标系统(SmartOS)尝试运行了一些命令,以防万一是一个显而易见的问题。我的第一个命令是tail /var/adm/messages,这是我做为系统管理员以来的一个有用的习惯,因为它可以立即发现某些问题。但没有显示出什么异常。
然后我选择了一个基于已提及的丢失网络数据包的统计命令来运行:netstat -s 1 | grep tcp。这从一个屏幕显示自启动以来的摘要值统计信息,然后每秒打印另一个屏幕。自启动以来的摘要值统计信息
我花了几秒钟时间,特别关注了tcpListenDrop、tcpListenDropQ0和tcpRetransSegs。这些速率看起来并不异常。我将命令保持在窗口中运行,显示每个间隔的摘要,同时继续阅读帮助台系统中的支持票(有好几页长)。我意识到我不知道是否应该立即看到问题。我问詹姆斯高延迟的Redis请求发生频率如何。他说:“一直都有。”这不是我想要的答案!我希望这个问题能更好地量化,以帮助理解不断变化的netstat输出。我应该每秒、每分钟还是每小时都能看到它们?詹姆斯不知道,但说他会回复我。我读完支持票后,同时打开了几个终端窗口并行登录到系统中,脑海中浮现出一些想法:
“这可能不是我时间的良好利用。Nathan是一位经验丰富的性能分析师,支持团队的其他成员似乎已经进行了合理的调查。这感觉有点像钓鱼——希望我的一些特殊DTrace工具能捕捉到另一个问题。我会花,比如说,15分钟认真查看系统,如果没有发现任何问题,我就会把它交还给詹姆斯。”
“另一方面,我将有机会在另一个真实的问题上使用这些DTrace工具,并进一步开发它们。我对TCP的可观察性有很多想法,这是一个实现的机会。然而,工具开发并不比我需要解决的其他客户问题更重要,所以这可能应该等待。”
“嗯,Redis到底是什么?”我对Redis实际上是什么一无所知。我以前听说过它,但不记得它是做什么的。它是应用服务器、数据库、负载均衡器吗?我感觉自己像个白痴。我想要知道它在高层次上是做什么的,作为我即将检查的各种统计数据的背景。
我首先使用ps(1)查看系统,看看Redis进程或其参数的某些细节是否会让我想起。我找到了一个名为“redis-server”的进程,但这并没有触动我的记忆。通过快速的互联网搜索Redis(谷歌),我在不到一分钟的时间内找到了答案(来自维基百科):Redis是一个键值存储,设计用于仅在主内存中快速运行。
现在,问题描述听起来更加严重:如果这是内存中的操作,什么样的性能问题会导致它有时需要超过一秒的时间?这让我想起了不寻常的内核调度器错误,其中线程可能被阻塞在可运行状态那么长时间。我可以再次对内核调度器进行DTrace,并找出问题所在,但这需要时间。我应该检查系统是否有包含这些修复的内核版本。
13.1.4 Choose Your Own Adventure
此时我可以采取几种不同的方向:
1. 研究netstat统计数据,其中大部分我尚未阅读。此时,netstat已经运行了几分钟,并打印了约10,000个单独的统计数据。它打印的数字比我能阅读的速度还要快。我可以花大约10分钟的时间尽可能多地阅读,希望找到进一步调查的线索。
2. 使用我的DTrace网络工具并进一步发展它们。我可以从内核中挑选出感兴趣的事件,包括重传和数据包丢弃,并打印相关的细节。这可能比阅读netstat更快,并且可能会暴露netstat统计数据未涵盖的领域。我还希望进一步开发这些工具,供其他客户使用,并公开分享。
3. 浏览错误数据库,寻找以前的内核调度程序问题,并查找已修复问题的内核版本,然后检查系统是否运行了具有这些修复的内核版本。我还可以使用DTrace来调查可能的新内核调度程序问题。这种问题曾经导致数据库查询耗时一秒钟。
4. 退一步,检查整个系统的健康状况,以排除任何瓶颈。这可以使用USE方法来完成,并且对关键组合只需几分钟。
5. 创建一个Redis的理论模型,使用排队理论,用于建模延迟与负载之间的关系:以确定由于等待队列的尾部而自然发生的一秒延迟的情况。这可能很有趣,但可能非常耗时。
6. 查找在线Redis错误数据库,并搜索已知的性能问题,特别是一秒延迟的问题。也许有一个社区论坛或IRC频道我可以提问。
7. 使用DTrace深入研究Redis的内部,从读取延迟开始,然后逐步深入。我可以使用DTrace的pid提供程序,将我的zfsslower.d风格脚本应用于跟踪Redis读取操作,这样我就可以提供延迟参数,并只跟踪慢于,比如说,500毫秒的读取操作。这将是深入研究的良好起点。
我没有考虑的一个路径是对Redis的负载进行特征化,以防一秒读取只是大型读取,并且应该预计需要那么长时间。例如,客户端可能开始偶尔进行1GB的大型读取,这将显示为客户端监控软件中的延迟峰值。我排除了这个可能性,因为Nathan已经使用curl(1)进行了测试,并发现延迟可能会随着正常大小的读取而增加。
我选择了USE方法。过去它已经被证明是性能问题的一个良好起点。这也将有助于詹姆斯向客户解释,我们认真对待这个问题,并且已经完成了我们自己的系统健康检查。
13.1.5 The USE Method
正如第二章方法论中介绍的那样,USE方法是一种检查系统健康状况、识别瓶颈和错误的方式。对于每个资源,我会检查三个指标:利用率、饱和度和错误。对于关键资源(CPU、内存、磁盘、网络),只需检查几十个指标,远远少于我目前从netstat(1M)获得的10,000个。
CPU
我运行了fmdump(1M)来查看是否有任何CPU错误,以立即排除这些可能性。结果没有发现任何错误。
然后我使用vmstat(1M)的列检查了系统范围的CPU利用率和饱和度,然后使用mpstat(1M)检查了每个CPU。它们看起来都很好:有足够的空闲余量,没有单个热点CPU。
如果客户达到了云强加的CPU限制,我会使用kstat(1M)检查他们的使用情况和限制。结果显示他们远低于限制值。
Memory
物理错误类型应该已经在之前的fmdump(1M)中显示出来了,所以我转向了利用率和饱和度。
我之前在调查系统范围的CPU使用率时已经运行了vmstat 1,并注意到系统范围内有大量的空闲主存储器和虚拟存储器,并且页面扫描器未运行(一种饱和度度量)。
我运行了vmstat -p 1来检查匿名分页,这可能是由于云强加的限制而发生,即使系统具有内存余量。匿名页进入列api 不为零!
当应用程序增长过大超出了主存储器(或限制)并已被分页到物理交换设备(或者,如Linux所称,已被交换出)时,会发生匿名页进入。然后,当应用程序需要时,必须读回一个内存页。这会增加显着的磁盘I/O延迟,而不仅仅是主存储器I/O延迟,并且可能严重影响应用程序性能。一秒钟的读取,甚至更糟,很可能是由于匿名页进入造成的。
单个指标通常不会确认性能问题(除了许多错误类型)。然而,匿名页进入是一个非常好的单个指标,几乎立即确认了问题。我仍然想要再次核实,并使用prstat -mLc检查每个线程的微状态(来自线程状态分析方法):
DFL(数据错误时间)的高百分比表明,某些秒内,Redis服务器线程大部分时间都在等待来自磁盘的这些页进入操作,这些操作通常应该从主存储器中提供服务。
检查内存限制:
虽然当前内存使用量(RSS)低于限制(CAP),但其他列显示的证据表明它们频繁地超出了限制:45,091次(NOVER),导致总共有974,165兆字节的数据被分页出去(POUT)。
这看起来像是一个常规的服务器配置错误案例,特别是由于客户刚刚将Redis迁移到这个云端。也许他们没有更新配置文件以将其大小限制在新的限制之内。我给詹姆斯发送了一条消息。
尽管内存问题很严重,但我还没有证明它是导致一秒延迟的问题。理想情况下,我会测量Redis读取时间,并将同步阻塞在DFL上的时间表达为这个比例。如果一秒钟的读取花费了99%的时间被DFL阻塞,我们就确认了读取速度慢的原因,然后可以检查Redis内存配置以找出根本原因。
在此之前,我想完成运行USE方法检查表。性能问题通常是多方面的。
磁盘
运行iostat -En未显示任何错误。运行iostat -xnz 1显示利用率很低(%b),并且没有饱和(等待)现象。
我让iostat(1M)运行一段时间来寻找变化,看到了一波写入操作:
对于ZFS,它将写入操作批量处理到事务组(TXGs)中,这种行为是正常的。应用程序文件系统I/O是异步进行的,通常不受繁忙磁盘的影响。但至少通常情况下如此。在某些情况下,应用程序I/O可能会在TXG上被阻塞。
这里看到的磁盘I/O可能并不是由Redis引起的,它可能来自系统上的另一个租户,特别是因为Redis是一个内存数据库。
网络
网络接口看起来良好;我使用netstat -i和nicstat检查它们:没有错误,利用率低,没有饱和。
13.1.6 Are We Done?
由于内存使用情况非常明显,并且需要回到其他工作,我将问题交给了詹姆斯:“看起来像是一个内存配置问题——它们被匿名页进入阻塞了。”我附上了屏幕截图。看起来这个问题毕竟很快就解决了。
稍后,詹姆斯转达了客户的消息:
“你确定这与内存有关吗?内存配置看起来没问题。”
“一秒钟的读取仍然在发生。”
“大约每5分钟发生一次”(回答了我之前的问题)。
确定吗?!如果客户和我在一起,我会努力不表现出愤怒。很明显存在严重的内存问题。你的API和高达98%的DFL——系统陷入了内存地狱。是的,我确定!
嗯,仔细想想……我确信存在严重的内存问题。但我实际上还没有证明这就是导致读取延迟的问题。在这项工作中发现多个问题并不罕见。可能还有另一个问题实际上导致了读取延迟,而这个内存分页问题只是一个误导?更像是一个误导性的巨大问题!客户提到大约每5分钟发生一次的评论也与内存问题不一致。早些时候我看过,DFL时间几乎每秒都在发生。这表明可能确实存在第二个问题。
13.1.7 Take 2
理想情况下,我想要一个工具,显示以下内容:
- Redis读取延迟
- 同步时间组件的细分,显示读取过程中大部分时间都花费在哪里
我会运行这个工具,找出那些慢的一秒钟读取,然后查看这些读取中最大的组成部分是什么。如果是内存问题,这个工具会显示大部分时间都花费在等待匿名页面加载上。
我可以开始浏览Redis在线文档,看看是否存在这样的工具。如果有的话,可能需要一些时间来学习它,并得到客户的许可来运行它。通常使用全局区域的DTrace只需花费一点时间进行只读查看。
DTrace需要测量Redis的读取延迟。在Redis DTrace提供程序出现之前,我必须自己制定技术,基于Redis内部的工作方式。问题是,我不知道Redis内部是如何工作的,不久前我甚至忘记了它是什么。这种内部知识通常只有Redis开发人员或专家才能随时掌握。
如何快速了解Redis?我想到了三种方法:
- 使用DTrace syscall提供程序检查系统调用,并尝试从中找出Redis读取延迟。通常有一些巧妙的方法来找到这样的信息,例如跟踪在套接字上的accept()到close()延迟,或者检查send()和recv()数据。这将取决于使用的系统调用。
- 使用DTrace pid提供程序检查Redis内部。这将需要跟踪Redis的内部,而我对此一无所知。我可以阅读源代码,但这将耗费时间。通常更快的方法是进行堆栈搜索:从服务客户端I/O的系统调用开始,并打印用户级堆栈(DTrace ustack()操作)以查看代码路径的继承关系。与成千上万行源代码相比,这使我能够一窥正在使用的实际功能,并且我只需研究这些功能。
- 使用DTrace pid提供程序检查Redis内部,但通过在97 Hz(例如使用DTrace profile提供程序)的速率下对用户级堆栈进行分析,而不是基于I/O。我可以获取这些数据并生成火焰图,以快速了解常见的代码路径。
13.1.8 The Basics
我决定先看看有哪些系统调用可用:
有很多gtime()、pollsys()和write()。pollsys()显示Redis没有使用事件端口,因为如果是这样的话,它会使用portfs()。这让我想起了一件事。另一位工程师之前遇到过这个问题,Redis的开发人员已经推出了修复方案,提高了性能。我告诉了詹姆斯这件事,尽管我记得事件端口提供了大约20%的性能改进,而我目前正在追查一个持续一秒钟的异常值。
一个单独的forksys()看起来很奇怪,但这样的不经常出现可能是监控行为(fork一个进程然后执行系统stat命令)。来自这个输出的fdstat()和fdsync()调用更加可疑。这通常是文件系统调用;我原以为Redis只在内存中运行。如果文件系统出现了,那么磁盘也就出现了,这肯定会导致高延迟。
13.1.9 Ignoring the Red Whale
为了确认磁盘是否起作用,并暂时忽略内存问题,我决定检查系统调用的文件系统类型。这些调用可能是对伪文件系统(如sockfs)的调用,而不是基于磁盘的文件系统,如ZFS。
为了确认它们可能会增加足够的延迟,使延迟累积到一秒钟,我还会测量它们的延迟。
我迅速编写了一些DTrace单行命令。其中包括以下内容:
统计写入(write())系统调用的文件系统类型,例如进程名为“redis-server”(系统上只有一个这样的进程):
测量所有系统调用的延迟,作为总和(纳秒):
第一段代码显示大部分时间写入是到“sockfs”,即网络上。有时确实是到“zfs”。
第二个单行命令显示,有时系统调用(如write()、fdsync()和poll())会有数百毫秒的延迟。poll()的延迟可能是正常的(等待工作——我需要检查文件描述符和用户级堆栈),但其他的,特别是fdsync(),就值得怀疑了。
13.1.10 Interrogating the Kernel
在这一点上,我运行了一系列快速的自定义DTrace单行命令,以回答关于内核的各种问题。这包括从系统调用层移动到VFS层,使用fbt提供程序进行跟踪,通过探针参数可以检查其他内核内部结构。
这很快演变成了以下单行命令,它已经开始变得足够长,可以转换成脚本:
它每15秒打印一些摘要信息。第一个显示了Redis使用的VFS级别调用,它们的延迟总和以纳秒计。在15秒的摘要中,fop_poll()只花了42毫秒,fop_write()花了9毫秒。第二个摘要显示了写入的文件系统类型——在这个时间段内,它们全都是“sockfs”,即网络。
大约每5分钟,以下情况发生了:
第一个时间间隔的输出显示了fop_write()时间的增加,在15秒的时间间隔内达到了317毫秒,同时还有2,981个zfs写入操作。第二个时间间隔显示了write()耗时493毫秒,fsync()耗时625毫秒。
确定正在被写入和同步的ZFS文件非常简单,我已经使用我最喜欢的一个DTrace脚本发现了它:
输出显示了许多128 K字节大小的写入到一个名为temp-10718.rdb的文件中。在它被删除之前,我设法对其运行了ls(1)命令,以查看其大小:
如果它对ls(1)来说存活时间太短,我可以使用DTrace跟踪文件信息。(我已经编写了一个脚本来做到这一点,叫做sollife.d;请参阅DTrace书的第5章[Gregg 11]。)
这些文件名包含dump和temp-。它们的大小超过了800兆字节,并且进行了fsync()。这听起来像是一个糟糕的主意。
13.1.11 Why?
写入一个超过800兆字节的临时文件,然后进行fsync()操作,加上合并的延迟时间超过一秒,听起来肯定可能是Redis延迟的原因之一。每5分钟一次的频率与客户的描述相匹配。在互联网上搜索到了由Didier Spezia [2]撰写的有关临时文件的以下解释:
RDB类似于内存的快照,写入到磁盘上。在BGSAVE操作期间,Redis会写入一个临时文件。一旦文件完成并进行了fsync(),它就会被重命名为真实的转储文件。因此,在转储期间发生崩溃时,现有文件永远不会被修改。所有最近的更改都会丢失,但文件本身始终是安全的,永远不会损坏。
我还了解到Redis可以fork()这个BGSAVE操作,以便在后台运行。我之前看到过一个forksys(),但没有进行检查。
Redis的维基百科页面提供了更多信息[3]:
持久性可以通过两种不同的方式实现:一种称为快照,是一种半持久性耐用模式,其中数据集不时地从内存异步地传输到磁盘上。从1.1版本开始,更安全的替代方案是一个附加的只写文件(日志),在内存中修改数据集的操作被处理时会被写入。Redis能够在后台重新编写附加文件,以避免日志的无限增长。
这表明行为可以发生戏剧性的变化,从一个转储到一个日志。检查Redis配置文件:
噢,原来是5分钟间隔的起源。
还有更多内容:
我通过詹姆斯把这个问题发送给了客户,但再次没有收到关于这个问题的回复。
13.1.12 Epilogue
在处理这个问题时,我发现了三个性能问题,并成功地向客户提供了可行的建议:
内存分页:重新配置应用程序以保持在内存限制内(这样可能会发现内存问题是由fork()和BGSAVE操作引起的)。
pollsys():升级Redis软件到使用事件端口的版本,以提高性能。
BGSAVE配置:Redis每5分钟对一个800多兆字节的文件调用fsync()以进行持久化,这很可能是异常值的原因,并且可以进行调优以表现出截然不同的行为。
我仍然感到惊讶的是,存在比内存分页更糟糕的问题。通常情况下,一旦我找到了那么多的DFL时间,客户就会找到并修复配置,然后我就不再收到回复了。我还与Joyent的其他工程师交谈过,以便我们能够及时了解性能问题。其中一位已经有了与Redis相关的经验,并表示:“这只是一个糟糕的配置。Redis应该用于服务小型对象存储——比如一个名称服务——而不是800兆字节的数据库。”
我之前60%的直觉是正确的:“噢,是的,它应该这样做。”我现在对下次遇到Redis时的细节了解更多了,也许到那时我将能够执行一些我之前的想法,包括编写一个脚本来跟踪Redis的读取时间并表达同步延迟的细分。
(更新:是的,我和Redis再次见面了,并且我编写了这些脚本:redislat.d用于总结Redis延迟,redisslower.d跟踪异常值。)
13.2 Comments
这个案例研究展示了我在性能调查过程中的思维过程,以及我通常如何应用我在之前章节中描述的工具和方法,以及我使用它们的顺序。它还描述了性能分析实践的一些额外特征,包括以下几点:
-起初对目标应用程序了解很少是正常的,但你可以迅速了解更多并培养专业知识。
-犯错、走错路,然后重新找到正确方向,在性能分析过程中属于常规。
-在找到问题之前发现多个问题也是很正常的。
而且所有这些都是在时间压力下发生的!对于初学者来说,当你研究性能问题时感到迷茫可能会让人泄气。这种感觉也是正常的:你会感到迷茫,你会犯错,你经常会错误判断。引用丹麦物理学家尼尔斯·玻尔的话:
一个专家是一个在非常狭窄的领域里犯过所有可能犯的错误的人。
通过像这样的故事告诉你,我希望让你放心,错误和走错路都是正常的(即使对于最优秀的人也是如此),并向你展示一些技术和方法来帮助你找到正确的方向。
13.3 Additional Information
要了解更多系统性能分析案例,可以查看公司的错误数据库(或工单系统)以了解以前的性能相关问题,以及你使用的应用程序和操作系统的公共错误数据库。这些问题通常以问题描述开始,以最终修复结束。许多错误数据库系统还包括带有时间戳的评论历史记录,可以研究以查看分析的进展,包括探索的假设和走错的路线。
有时会定期发布一些系统性能案例研究,例如在我的博客上。重点关注实践的技术期刊,例如ACM Queue,在描述解决问题的新技术解决方案时经常使用案例研究作为背景。