简谈性能优化(上)

本文以及接下来的两篇文章会讨论一些性能优化相关的知识,分为上、中、下三个部分。第一部分讨论性能分析的基础内容,第二部分讨论实际的性能分析、调优及测试,第三部分讨论虚拟化环境和云计算环境下的性能。文章内容来自于阅读《图解性能优化》一书的相关笔记和知识整理以及自己的理解。

转在此处自己对于本书的豆瓣书评。

作者给出的是一种总揽大局的思维观念,而并非详细的性能解决方式。它只是提供了一些角度去考虑性能问题,怎样排查性能问题,怎样解决的途径和突破点可能在何处。书中的示例也并非适用于所有的架构,但可以类比相似的解决方案到其他系统。如果事先没有对网络知识有一定了解,就不能理解在网络过程中存在的性能瓶颈,对操作系统的内在结构不熟悉,也就无法体会中断处理、锁机制等等对性能开销带来的影响。所以工程应用的解决方案往往是科学问题,这些是计算系统架构的底层和基础。

《图解性能优化》重在图解,但同所有的图解类图书一般,图虽浅显但也局限。只是更容易去理解一种思路,并不能带来知识体系的丰富。对于硬件性能的优化,也没有机会去实践。作为软件开发人员,也给了一种全局观察整个架构的机会。方法是次要的,基础扎实可以创造方法,书是引路人,只是让我们走得更容易些。对于经验丰富的工程师而言,经验已经融入血液,遇到问题可以四两拨千斤,迅速定位。作者能给出浅显的经验和解决方式是很棒的,软技能也存在与书中很多地方,能讲出来已经是读者的一种幸运。——@Rainy

性能的基础知识

性能问题的发生往往归结于软件问题和硬件问题两个方面。这里的软件问题是指“应用服务”软件,深入到软件的核心,是各种算法带来的性能差距。经典算法和数据结构已经非常成熟,由软件造成的性能表现不佳也极可能是对算法应用的不合理。各种算法都有其相应的适用场景,对算法数据结构优缺点的把握则是设计良好软件和架构的基础。而算法也并非完全适应与某一个场景,重要的是“折中”思维。性能问题往往都是速度和成本的权衡,算法也亦然。例如索引可以加快查找速度,但少量查找时又显得多余,预见到未来查找的增加,进行数据索引还是有必要的过程。下面来简要概述与性能有关的一些算法及优缺点:

性能与算法

算法优点缺点改进变种
数组O(n)善于循环处理,按序存放、查找数据未知数组长度,浪费内存空间,数据增多时修改不易数组的数组,用一个数组来添加位置变量
链表O(n)管理容易变化的数据,增删数据方便需要访问动态计算的地址,无法直接同数组下标般找到位置,只能遍历双向链表
树O(logn)随数据增加复杂度增加缓慢,查找范围逐渐缩小数据更新不便,删除数据造成空位,影响性能,导致索引碎片化n叉树、B树、B+树、B*树
散列算法O(1)消除数据的不平衡,直接查找相同数据、相同散列值出现碰撞以链表结构连接,“重散列”
队列O(1)大量处理,先入队列,分割事务(缓冲)队列溢出的情况数组连接的环形结构的队列,用树结构实现快速查找的队列
栈O(1)只占用必要空间,无碎片适用情况少栈轨迹,以栈形式展现函数调用
快速排序O(nlogn)加快查找时间,了解重复情况对频繁查找有价值,对少量查找则费时间归并排序
缓存(回写)不用等待写入延时可能导致缓存丢失时出现数据不一致现象非易失性(Non-volatile)、电池备份来解决数据丢失
缓存(直写)数据较快地读取和写入响应变慢关机缓存步骤,DBMS日志实时写入

锁与性能

锁机制是为保护数据的完整性及保证数据同步而存在于并行处理中的一种方式,而当锁出现了锁等待,则会形成请求队列。造成请求堆积而导致性能下降,所以需要减少锁等待的发生。

对 DB 而言,提高对表加锁的 SQL 处理速度,可以尽快释放锁。或对行加锁来并行执行,就可以通过分割锁的方式来减少等待时间。

响应与吞吐

考虑性能时,响应与吞吐是两个重要的概念。响应是应答快慢,而吞吐是处理数量。有的系统偏重于响应,而有的偏重于吞吐。通过升级硬件来提高响应速度,一般也会提高吞吐,但升级不是无限的,有它的瓶颈和上限。吞吐不够时,增加响应只是增加了空转的硬件,并不能解决问题。所以当出现性能问题时,要判断是响应问题还是吞吐问题,对症下药。

性能分析的基础

要进行性能分析首先要进行性能测量,找出问题所在。而性能测量也就是性能分析的原则,首先要从时间和位置两个角度考虑,也就是“分段查找”的思想。从时间角度是测量某个时间段内的性能信息来进行分析,而位置角度则是测量可能发生性能问题的位置进行定点测量,各个击破。并且在测量过程中,也要考虑性能测量工具的负载对系统的影响。避免对性能信息进行误判。

作者将性能信息分为三类:

  1. 概要形式。获得的是某段时间内的平均值,适合快速掌握初步信息。
  2. 事件记录形式。获得的是“某时某刻谁做了什么”之类的详细信息,对系统压力较大。不适合经常在生产环境中使用。
  3. 快照形式。记录某一瞬间的信息,适合查找引起性能问题的原因。

三类信息获得之后进行结合分析,来找出问题所在。而获取三类信息的相应工具和命令,会在下面给出。

等待队列理论

在性能方面,“等待队列理论”具有很强的代表性。首先,队列中的等待时间称为“访问等待时间”,有如下关系:

响应时间 = 访问等待时间 + 服务时间

等待队列可以表示为”M/M/1”。分别表示请求到达时间的特征,服务时间的特征,处理的并行程度(1 指线性处理)。因为请求是完全随机的,所以出现短暂的大量请求,也会产生等待队列。

假设处理时间是 1 秒,每小时处理的条数是 3000 条。

1
2
3
ρ(平均使用率) = [1(处理时间)×3000(处理条数)]/3600(单位时间) = 0.83
等待时间/1秒 = 0.83/(1-0.83)= 4.88
响应时间 = 4.88(等待时间)+1(处理时间)

由上面的式子可以看出,当平均使用率增加的时候,等待时间呈指数级别增加。

在 CPU 使用率的统计工具中,有时可以看到尖峰的出现。频繁的尖峰出现往往是系统出现问题的前兆,但少数尖峰的出现是允许存在的,使用超线程可以改善此现象。然而在批处理中不应该存在这样的情况,处理时间久也不会导致等待队列的变长,由于不能通过等待队列的情况来判断性能问题,这时就应判断单个处理器的时间长度了。

当调查引起性能问题的原因时,需要确定一些必要的检测信息。而对于需要获得哪些信息,并没有统一的标准。需要按照实际情况去确认。

获取性能信息的 OS 命令

对于获取性能信息的方式,需要了解一些获得信息的 OS 命令。对于 Linux 主要通过内置的命令来获得,Windows 大都是获取相应信息的图形化界面。此外有时还需要其他的工具或软件,例如对网络进行性能分析时,需要使用 Wireshark 来进行抓包分析。下面简要介绍相关命令,具体使用可查阅相关手册(提供的是获得信息的方式和思路,而非详细的使用和操作步骤)。

Linux

对于 Linux 而言,获取性能信息的 OS 命令可以根据性能信息的分类如下:

  1. 获取概要信息:

    1
    sar, vmstat, netstat, iostat, profiler
  2. 获取快照信息:

    1
    ps, netstat, top, pstack
  3. 事件记录形式的信息:

    1
    数据包转储程序, strace

Windows

Windows 的性能信息工具往往隐藏在控制面板的各个角落,比较有用的有任务管理器、性能监视器、资源监视器等。


关于性能优化的基础部分谈到这里,第二部分将会谈到实际的性能优化、分析及调优。