性能的测量
性能只有在你决定测量性能的时候性能才是重要的。但一些人发现在测量性能的时候,很难确定需要测量哪个度量值,而且就算他们手头上有了这些信息之后也不知道该怎么办。结果导致了很多人开始竭尽全力地获得所有相关信息。这当然也导致了系统负载过重和获得一些看起来没有意义的信息。在这样的情况下,一些人完全放弃了测量,开始凭着他们的直觉对系统性能调优。
我们当然不能这么干,而应该系统地并且一步一步地对它进行测量。首先,理解为什么要测量性能和通过这些工作你想达到一个什么目标。如果你没有一个目标,那么就没有办法去完成了。
接下来你需要理解你测量的东西和它们的意义。这可能需要创建一个模型用于跟踪你的数据。只有通过结合数据和模型,你才能获得有价值的信息。例如,预报天气需要一些数据:气温,湿度,大气压力等等。即使我知道它们的每一个值,如果我没有该地区的气候模型我还是不能预报那个地区的天气情况。原始度量值不易理解,在一个有意义的模型中度量值会更易于理解。
测量的变量
让我们开始看看我们的模型需要收集那些度量值信息。我们需要理解系统一些最基本的东西是:
反应时间(R)
吞吐量(X)
资源利用率(U)
服务请求(D)
反应时间 用于测量完成一个特定请求需要花费多少时间。它是一个非常重要的度量值因为它是用户体验的一个指数。尽管这样,你必须确保你理解你测量的是什么--系统级的反应时间和组件级的反应时间完全不同(因为系统级包括像队列时间这样的变量)。
它同时也是不容易测量的度量值,因为它比其它的度量值更容易变化。因此你必需了解反应时间的分布。如果应用对你大部分用户的反应时间是2秒钟,而对10%用户的反应时间却是10秒钟,在这种情况下,你必须知道这个反应时间的分布,才能精确地评估该问题和解决它。这就要测量它们的反应时间并且得到它们的标准偏差,理想的情况是用一个柱状图把反应时间的分布显示出来。
吞吐量 指出系统在一段时间内能执行的交易量。它是系统处理负载能力的一个很好的指数,并且通常跟反应时间结合在一起。由于它不是以用户为中心的测量,所以对于一些非交互的系统或批处理工作,它是最值得考虑的。
资源利用率 是用于测量系统特定元素被利用了多少。这个度量值是系统的最底层情况的一个指数,因此对于容量规划是有用的。它也是非常容易理解的度量值,许多人通常都是从处理器和内存的利用率开始入手的,但它不是测量系统性能中最有用的。
我们发现更多使用的是处于请求中的资源。我们使用称为 服务请求 (D)的计算度量值显示特定资源或服务将怎样被利用。服务请求用以下公式计算:
D=U/X
这给了我们一个比较清晰的资源利用率,对于吞吐量是规范化的。
相互关联的度量值
上面这些度量值之间都有关系,理解它们的关系是创建性能模型重要的第一步。为了清楚理解它们,我们能够以图表的形式画出这些关系(见下图)
通过这个图,我们可以更清楚看到一些东西。我们注意吞吐量(X)和反应时间(R)经常是成正比增长的。在实验室设置中,或者对于非交互的应用,我们通常将想获得最高的吞吐量。对于用户驱动的生产环境,我们通常想最大化吞吐量,而保持大部分请求时间低于或等于某个反应时间。例如,当保持95%的请求反应时间等于或少于2秒的时候,我们可能想最大化我们的吞吐量。由于这些限制,我们可能发现我们能够达到每秒100个交易的最大吞吐量。
细看这个图,我们发现资源利用率通常控制着系统行为。这里有一个资源论点,认为资源竞争导致了吞吐量的急剧下降和提高了反应时间,吞吐量下降的量和增加的反应时间量是相同的,形成了扣环图。扣环图引起应用性能的服务下降,因为系统花费大部分的时间管理资源竞争而不是服务请求。创建一个系统性能模型看你的应用中这三个度量值是怎么个情况是很重要的。你也想知道:哪个度量值引起负载飙升以及这个度量值的精确值?知道了引起应用负载飙升的值对于在产品监控工具中设置报警值是非常有用的。
度量值与系统模型
确定了测量的度量值,我们现在准备开始把这些数据放到我们的模型中。
常用软件系统一般由四个主要过程组成的:客户请求处理,包括发起的请求和这些请求可能绑定的会话;请求执行管理,请求被指派到执行线程前排队等候的地方;应用程序,包括所有程序的代码;底层服务服务,包括了常用的元素,像JDBC和 JMS,也有在你的应用和外界之间的连接。当然,所有这些元素都可能运行在某平台或者虚拟机中,比如JVM,而JVM则使用操作系统资源如处理器CPU,内存,物理磁盘和网络连接。下图是一个J2EE模型。
我们现在能够看到怎样在每一层上测量前面讨论过的度量值。我们需要测量和理解反应时间在各个层中的分布,这些层包括客户请求和处理层,应用代码层(在组件,方法或语句层细节中),还有服务。在客户请求处理层中吞吐量是最重要的--我们必须知道我们的系统能处理多少用户负载。在系统中资源利用率是通过很多不同点(操作系统,执行线程,服务等)来测量的,所以我们能关联这些信息并且看到系统中不同元素是怎么互相影响的。
测量的开销
天底下没有免费的午餐。在任何时候,当你实时地测量这些度量值时,你总会给系统增加一些负载。通过了解由于我们测量引起的负载,我们将能够在打算获得的信息量和可能增加的负载之间作出明智的选择。测量这些负载的最好方法是使用前面提到过的服务请求来计算。
在创建系统性能的准确模型时,必须理解在测量时产生负载的影响。J2EE应用是由一些相互联系的系统组成的,并且这些系统在运行时有轻微的不同。处理它的唯一办法是确保锁定你能锁定的一切东西--你不想你的性能测量由批处理任务组成,这些批处理任务会在你的服务器中的某一台突然启动。定期的重做基准测试也是一个好办法。这将确保你很快意识到系统性能的突然下降,性能突然下降会使你的数据无效。
测试与分析
在建立了测试模型,明确了个组件的测试重点后,便可以应用早期提到的性能测试和监控方法获得测试数据,再对测试数据进行分析即可。
一个i/o评估的小例子
通常,我们很容易观察到数据库服务器的内存和CPU压力。但是对I/O压力没有直观的判断方法。磁盘有两个重要的参数: Seek time、 Rotational latency。正常的I/O计数为:
①1000/(Seek time+Rotational latency)*0.75
在此范围内属正常。当达到85%的I/O计数以上时则基本认为已经存在I/O瓶劲。理论情况下,磁盘的随机读计数为125、顺序读计数为225。对于数据文件而言是随机读写,日志文件是顺序读写。因此,数据文件建议存放于RAID5上,而日志文件存放于RAID10或RAID1中。
下面假设在有4块硬盘的RAID5中观察到的Physical Disk性能对象的部分值:
Avg. Disk Queue Length 12
Avg. Disk Sec/Read .035
Avg. Disk Sec/Write .045
Disk Reads/sec 320
Disk Writes/sec 100
Avg. Disk Queue Length,12/4=3,每块磁盘的平均队列建议不超过2。
Avg. Disk Sec/Read一般不要超过11~15ms。
Avg. Disk Sec/Write一般建议小于12ms。
从上面的结果,我们看到磁盘本身的I/O能力是满足我们的要求的,原因是因为有大量的请求才导致队列等待,这很可能是因为你的SQL语句导致大量的表扫描所致。在进行优化后,如果还是不能达到要求,下面的公式可以帮助你计算使用几块硬盘可以满足这样的并发要求:
Raid 0 -- I/Os per disk = (reads + writes) / number of disks
Raid 1 -- I/Os per disk = [reads + (2 * writes)] / 2
Raid 5 -- I/Os per disk = [reads + (4 * writes)] / number of disks
Raid 10 -- I/Os per disk = [reads + (2 * writes)] / number of disks
我们得到的结果是:(320+400)/4=180,这时你可以根据公式①来得到磁盘的正常I/O值。假设现在正常I/O计数为125,为了达到这个结果:720/125=5.76。就是说要用6块磁盘才能达到这样的要求。
但是上面的Disk Reads/sec和Disk Writes/sec是个很难正确估算的值。因此只能在系统比较忙时,大概估算一个平均值,作为计算公式的依据。另一个是你很难从客户那里得到Seek time、 Rotational latency参数的值,这也只能用理论值125进行计算。