Go 性能:你知道的越多,不知道的也就越多

计算机性能是一门令人激动的,富于变化同时又充满挑战的领域。

系统性能是对整个计算机系统的性能的研究,包括主要硬件组件和软件组件。所有数据路径上和从存储设备到应用软件上所发生的事情都包括在内,因为这些都有可能影响性能。对于分布式系统来说,这意味着多台服务器和多个应用。如果你还没有关于你的环境的一张示意图,用来显示数据的路径,赶紧找一张或者自己画一张。它可以帮助你理解所有组件的关系,并确保你不会只见树木不见森林。

系统性能的典型目标是通过减少延时降低计算成本来改善终端用户的体验。降低成本可以通过消除低效之处、提高系统吞吐量和进行常规性能调优来实现。

下面是系统性能的一些重要概念

延时

对于某些环境,延时是被唯一关注的性能焦点。而对于其他环境,它会是除了吞吐量以外,数一数二的分析要点。

作为延时的一个例子,图 2.3 显示了如 HTTP GET 请求的网络传输,其响应时间被分成连接延时和数据传输时间两部分。

%title插图%num

延时是操作执行之前所花的等待时间。在这个例子里,操作是网络服务的数据传输请求。在这个操作发生之前,系统必须等待建立网络连接,这就是这个操作的延时。响应时间包括了延时和操作时间。

因为延时可以在不同点测量,所以通常会指明延时测量的对象。例如,网站的载入时间由三个从不同点测得的不同时间组成 :DNS 延时、TCP 连接延时和 TCP 数据传输时间。DNS 延时指的是整个 DNS 操作的时间,TCP 连接延时仅仅指的是初始化时间(TCP 握手)。

由于延时是一个时间上的指标,因此可能有多种计算方法。性能问题可以用延时来进行量化和评级,因为是用相同的单位来表达的(时间)。通过考量所能减少或移除的延时,预计的加速也可以被计算出来。这两者不能用 IOPS 指标很准确地描述出来。

时间的量级和缩写列在了表 2.1 中,可作为参考。

%title插图%num

如果可能,其他的指标也会转化为延时或者时间,这样就可以进行比较了。如果必须在 100 个网络 I/O 和 50 个磁盘 I/O 之间做出选择,怎样才能知道哪个性能更好?这是一个复杂的选择,因为其中包含了很多因素 :网络跳数、网络丢包率和重传率、I/O 的大小、随机或顺序的 I/O、磁盘类型,等等。但是如果你比较的是 100ms 的网络 I/O 延时和 50ms 的磁盘 I/O 延时,那差别就很明显了!

时间量级

我们可以对时间进行量化的比较,同时最好对时间和各种来源的延时的合理预期有本能的认识。系统各组件的操作的时间量级差别巨大,表 2.2 中提供的延时示例,从访问 3.5GHz 的 CPU 寄存器的延时开始,阐释了各种操作时间量级的差别。表中所示的是发生单次操作的时间均值,等比放大为一个假想的系统,将 1 个 CPU 周期的 0.3ns(十亿分之一秒的三分之一 1)放大为现实生活中的 1 秒。

%title插图%num
%title插图%num

正如你所见,1 个 CPU 周期的时间是很短暂的。0.5 米差不多是你的眼睛到这个页面的距离,光线走过这段距离需要的时间大约是 1.7ns。在这段时间里,现代的 CPU 已经执行了 5 个 CPU 周期,处理了若干个指令。

权衡

你应该知道某些性能权衡关系。图 2.4 展示的是好 / 快 / 便宜“择其二”的权衡关系,右图所示的是对应于 IT 项目的术语。

%title插图%num

许多 IT 项目选择了及时和成本低,留下了性能问题在以后解决。当早期的决定阻碍了性能提高的可能性时,这样的选择会变得有问题,例如,选择了非最优的存储架构,或者使用的编程语言或操作系统缺乏完善的性能分析工具。

一个常见的性能调优的权衡是在 CPU 与内存之间,因为内存能用于缓存数据结果,降低 CPU 的使用率。在有着充足 CPU 资源的现代系统里,交换可以反向进行 :CPU 可以压缩数据来降低内存的使用。

调优的影响

性能调优实施在越靠近工作执行的地方效果最显著。对于工作负载驱动的应用程序,这意味着调优性能的地方就在应用程序本身。表 2.3 展示了一个软件栈的例子,说明了性能调优的各种可能。

%title插图%num

对应用程序层级进行调优,可能通过消除或减少数据库查询获得很大的性能提升(例如,20 倍)。在存储设备层级进行调优,可以精简或提高存储 I/O,但是性能提升的重要部分在更高层级的操作系统栈代码,所以对存储设备层级的调优对应用程序性能的提升有限,是百分比量级的(例如,20%)。

在应用程序层级寻求性能的巨大提升,还有一个理由。如今许多环境都致力于特性和功能的快速部署,按每周或每天将软件的变更推入生产环境。 因此,应用程序的开发和测试倾向于关注正确性,在部署前留给性能测量和优化的时间很少甚至没有。之后当性能成为问题时,才会去做这些与性能相关的事情。

虽然发生在应用程序层级的调优效果最显著,但这个层级不一定是观测效果最显著的层级。数据库查询缓慢最好从其所花费的 CPU 时间、文件系统和所执行的磁盘 I/O 方面来考查。使用操作系统工具,这些都是可以观测到的。

合适的层级

不同的公司和环境对性能有着不同的需求。你可能加入过这样的公司,其分析标准要比你之前所见过的严格得多,甚至可能听都没听过。或者是这样的公司,你觉得很基本的分析被认为很高端甚至从未使用过(这是好消息 :事情简单轻松!)

这并不意味着某些公司做的是对的,某些做的是错的。这取决于性能技术投入的投资回报率(ROI)。拥有大型数据中心或大型云环境的组织可能会雇用一个性能工程师团队来分析所有的事情,包括内核内部和 CPU 性能计数器,并频繁使用各种跟踪工具。他们还可能对性能进行正式建模,并对未来的增长进行准确预测。对于每年在计算上有数百万花费的环境来说,雇用这样一个性能团队是值得的,因为他们进行的优化就是投资回报。小型创业公司的计算开支不大,可能只进行表面的检查,利用第三方监测方案来检查性能和提供警报。

何时停止分析

做性能分析时的一个挑战是如何知道何时停止。有这么多的工具,有这么多的东西要检查!

当我教性能课程时(最近我又开始教了),我给我的学生一个有三个原因的性能问题,我发现有些学生在找到一个原因后就停止了,有些则是两个,有些则是三个。有些学生则继续努力,试图为性能问题找到更多的原因。谁的做法是正确的?说你应该在找到所有三个原因后就停止,可能很容易,但对于现实生活中的问题,你并不知道原因的数量。

这里有三种情况,你可以考虑停止分析,并提供了一些个人的例子。

当你已经解释了大部分性能问题的时候。一个 Java 应用程序消耗的 CPU 资源是原来的 3 倍。我发现的第一个问题是异常堆栈消耗了 CPU。然后我量化了这些堆栈的时间,发现它们只占整个 CPU 占用的 12%。如果这个数字接近 66%,我就可以停止分析了。但在这种情况下,在 12% 的情况下,我需要继续寻找。

当潜在的投资回报率低于分析的成本的时候。我所处理的一些性能问题可以带来每年数千万美元的收益。对于这些问题,我可以证明花几个月的时间(工程成本)进行分析是合理的。其他的性能问题,比如说微服务,可能是以数百美元计算的,甚至不值得花 1 个小时的工程时间来分析它们。例外情况可能包括 :当我没有更好的事情可做时(这在实践中从未发生过),或者如果我怀疑这可能是日后更大问题的隐患,值得在问题扩大之前进行调试时。

当其他地方有更大的投资回报率的时候。即使前两种情况没有得到满足,其他地方有更大的投资回报时经常需要优先考虑。如果你是全职的性能工程师,根据潜在的投资回报率对不同的问题进行有选择的分析可能是一项日常工作。

性能推荐的时间点

环境的性能特性会随着时间改变,更多的用户、新的硬件、升级的软件或固件都是变化的因素。一种环境,受限于速度 10Gb/s 的网络基础设施,当升级到 100Gb/s 时,很可能会发现磁盘或 CPU 的性能变得紧张。

性能推荐,尤其是可调优的参数值,仅仅在一段特定时间内有效。一周内从性能专家那里得到的好建议,可能到了下一周,经过一次软件或硬件升级,或者用户增多后就无效了。

在网上搜索找到的调优参数值对于某些情况可能能快速见效。但如果对于你的系统或者工作负载并不合适,它们也可能会对性能有所损害,或者合适过一次,就不再合适了,或者只是作为软件的某个 bug 修复升级之前暂时的应急措施。这和从别人的医药箱里拿药吃很像,那些药可能不适合你,或者可能已经过期,或者只适合短期服用。

如果仅仅是出于要了解有哪些参数可调以及哪些参数在过去是需要调整的,那么浏览这些性能建议是有用的。针对你的系统和工作负载,这项工作就变成了考虑这些参数是不是要调,以及调整成什么值。如果其他人不需要调整那个值,或者调整了但并未将经验分享出来,那么你有可能漏掉了重要的参数。

负载与架构

应用程序性能差可能是因为软件配置和硬件的问题,也就是它的架构和实现问题。另外,应用程序性能差还可能是由于有太多负载,而导致了排队和长延时。负载和架构见图 2.5。

%title插图%num

如果对架构的分析显示只是工作任务在排队,处理任务没有任何问题,那么问题就可能出在施加的负载太多上。在云计算环境里,这是需要引入更多的服务器实例来处理任务的征兆。

举个例子,架构的问题可能是一个单线程的应用程序在单个 CPU 上忙碌,从而导致请求排队,但是其他的 CPU 却是可用且空闲的。在这个例子里,性能就被应用程序的单一线程架构限制住了。架构的另一个问题可能是一个程序的多个线程争夺一个锁,这样只有一个线程可以向前推进,而其他线程在等待。

负载的问题可能会是一个多线程程序在所有的 CPU 上都忙碌,但是请求依然排队的情况。在这个例子里,性能可能被限制于 CPU 的性能,或者说是负载超出了 CPU 所能处理的范围。

指标

性能指标是由系统、应用程序,或者其他工具选定的统计数据,用于测量感兴趣的活动。性能指标用于性能分析和监测,可以由命令行提供数据,也可以由可视化工具提供图表。

常见的系统性能指标如下。

吞吐量 :每秒的数据量或操作量。

IOPS :每秒的 I/O 操作数。

使用率 :资源的繁忙程度,以百分比表示。

延时 :操作时间,以平均数或百分数表示。

吞吐量的使用取决于上下文环境。数据库吞吐量通常用来度量每秒查询或请求的数目(操作量)。网络吞吐量度量的是每秒传输的比特数或字节数(数据量)。IOPS 度量的是吞吐量,但只针对 I/O 操作(读取和写入)。再次重申,上下文很关键,上下文不同,定义可能会有不同。

缓存

缓存被频繁使用来提高性能。缓存是将较慢的存储层的结果存放在较快的存储层中。

把磁盘的块缓存在主存(RAM)中就是一例。

一般使用的都是多级缓存。CPU 通常利用多级硬件缓存作为主缓存(L1、L2 和L3),开始是一个非常快但是很小的缓存(L1),后续的 L2 和 L3 逐渐增加了缓存容量和访问延时。这是一个在密度和延时之间经济上的权衡。缓存的级数和大小的选择以CPU 芯片内可用空间为准,确保达到最优的性能。

一个了解缓存性能的重要指标是每个缓存的命中率—所需数据在缓存中被找到的次数(hits,命中)与总访问次数(hits+misses)的比例。

命中率 = 命中次数 /(命中次数 + 失效次数)

命中率越高越好,更高的命中率意味着更多的数据能成功地从较快的介质中访问获得。

%title插图%num

98% 和 99% 之间的性能差异要比 10% 和 11% 之间的性能差异大很多。由于缓存命中和失效之间的速度差异(两个存储层级),导致了这是一条非线性曲线。两个存储层级速度差异越大,曲线越陡峭。

已知的未知

已知的已知、已知的未知、未知的未知在性能领域是很重要的概念。下面是详细的解释,并提供了系统性能分析的例子。

已知的已知 :有些东西你知道。你知道你应该检查性能指标,你也知道它的当前值。举个例子,你知道你应该检查 CPU 使用率,而且你也知道当前均值是10%。

已知的未知 :有些东西你知道你不知道。你知道你可以检查一个指标或者判断一个子系统是否存在,但是你还没去做。举个例子,你知道你能用剖析检查是什么致使 CPU 忙碌,但你还没去做这件事。

未知的未知 :有些东西你不知道你不知道。举个例子,你可能不知道设备中断可以消耗大量 CPU 资源,因此你对此并不做检查。在性能领域,“你知道的越多,你不知道的也就越多”。这和学习系统是一样的原理:你了解的越多,你就能意识到未知的未知越多,然后这些未知的未知会变成你可以去查看的已知的未知。

链接:https://mp.weixin.qq.com/s/8Ls2BRdelgxniXXgjgICUQ
(版权归原作者所有,侵删)

本文链接:http://www.yunweipai.com/42135.html

Go 性能:你知道的越多,不知道的也就越多
%title插图%num
滚动到顶部