启动时间、加速时间和吞吐量

您或许听说过那些以“如果我的汽车的行为像软件一样”开头的笑话 – 包括比尔盖茨与通用汽车公司在 20 年前的那次臭名昭著的争论。当然,这只是一个都市传说,但确实很有趣 [1]:

盖茨:“如果通用汽车公司能像计算机行业一样跟上技术发展,我们早就可以驾驶每加仑油跑 1,000 英里、售价只有 25 美元的汽车了。”

通用汽车公司:“如果通用汽车公司像微软公司一样开发技术,我们开的车每天都会撞车两次。”

紧随这次反驳之后,这辆完全现代化的汽车的一系列其他不幸“特征”被列举出来,其中包括在按下启动按钮后它才会提醒您按下它来关闭发动机!

或许,应该避免计算机与汽车之间的对比。

或者我们可以再做一次对比,帮助我们思考 Java 的性能:具体来讲,让我们思考运行 Java 程序所用的 OpenJ9 Java 虚拟机 (JVM) 技术。

当然,“性能”对于不同的人有着不同的含义,采用的度量方式也会有所不同。有趣的是,同样的复杂情形既适用于汽车,也适用于软件。

Jack's taxis

请容许我介绍一下我的朋友杰克,他决定开始自己跑出租车。我们最好不做太深入的类比,但是,通过以不太严谨的方式分析杰克在寻找合适的车和设置他的业务操作时需要考虑的因素,可以帮助我们更好地理解我们尝试优化的一些 OpenJ9 性能“指标”。

1. 应用程序启动时间

首先:从杰克按下点火装置的那一刻起,他的新车需要多长时间才能准备好上路?我们假设需要 5 秒。如果需要 10 秒,杰克是否会在意?考虑到我在一天中发动我的汽车的次数,我或许不会在意。但是请记住,杰克开的是出租车,需要经常停车和启动。所以他在意这一点!

启动半拖挂车的卡车司机也在意这一点。(可以称呼该车为半拖挂、18 轮、运输车、双拖斗卡车、拖挂车……随你怎么称呼!)或许启动车辆会花半分钟的时间。但是,如果仅在早上启动一次,那么实际启动时间无论是 20 秒还是 30 秒都无关紧要。但是对于需要维修这辆卡车、频繁地启停发动机来检查进度的机修工,这些额外的 10 秒会积少成多。

作为极端情况的示例,可以考虑汤姆·克鲁斯在危情谍战中驾驶的杜卡迪。对他而言,10 秒的延迟(哪怕只有一次)决定着生死!

软件应用程序也是如此。启动延迟重要吗?“视情况而定……”启动时间的重要性取决于具体的用例和业务模型。

当然,我们可以将一些不重要的系统留在汽车准备好行驶后再启动,以缩短启动时间。例如,过一会儿再启动音频系统不会出现什么问题。

类似地,在 Java 应用服务器软件中,对于某些初始化任务,我们可以在服务器报告它已准备好接受客户端请求后,在后台同步执行这些任务。

OpenJ9 非常重视启动时间,并通过使用共享类技术在这一领域开拓创新。通过使用共享缓存,并让通用类可用于其他 JVM,客户可以在每次后续 JVM 启动时节省大量时间。

要进一步了解类共享,请参阅以下文章:类共享 和使用类共享提高性能。

2.应用程序加速时间

但是,即使在启动车辆并驶上高速公路后,杰克也需要花一段时间才能达到最大速度。没有人喜欢一辆反应迟缓的车,尤其在我们必须快速驶入车流中时,或者在我们需要频繁地停止和启动车辆时。作为一条经验规则,“加速时间”随马力(和成本)增加而缩短。但是,杰克需要平衡这两个方面。

类似地,在某些情况下,尽快达到峰值吞吐量对应用程序至关重要。例如,您需要处理您网站上的流量高峰,以避免业务流失。或者如果您在使用一个框架,比如 Apache Hadoop 或 Apache Spark,它们可能会频繁地启动某个应用程序的多个短暂实例。

在 Eclipse OpenJ9 中,我们大力投资开发了复杂的 JIT 编译启发式算法和类加载功能,可以优化这些功能来提高应用程序加速的速度。

要进一步了解 JIT 编译,请参阅以下这篇文章:Java 性能优化。

3. 吞吐量

我们已通过度量启动和加速时间,并进行适当调整,整理出了杰克的汽车的行驶特征。但他的职业是提供出租车服务;他主要关注的是尽快送达尽可能多的客户 – 用计算术语讲,这就是他的“吞吐量”。

如果杰克能够始终按极限速度驾驶,始终载满客户,而且始终行驶最短距离到达目的地,那么他就会获得最大绝对吞吐量。如果所有这些因素都没有经过优化,那么他的效率(吞吐量)就会降低。

软件应用程序具有类似的问题。要实现最大吞吐量,必须尽快完成大量任务,而且 JVM 和应用程序代码必须采用一些技术,在尽可能短的时间内满足尽可能多的请求,比如平衡 JIT 编译、垃圾收集或线程池管理的成本与运行这些任务的最终收益。

这可能就像杰克停下车,花点时间在他的卫星导航中优化路线,他知道这样做会让他的行驶总时间得到改善。或者在一趟行程中搭载多个客户,尽管一位客户的路线可能稍微长一点,但将每个人送到目的地所花的总时间得到了最小化。

我们愿意这样想:OpenJ9 在不同的性能指标间实现了很好的平衡,做了一些明智的妥协,在获得最大化吞吐量的同时并没有牺牲其他度量指标。但是如果您想进行调优,OpenJ9 提供了多个调优选项,使您可以针对不同工作负载来优化它。

继续阅读:

在下一篇文章中, 杰克需要在确保客户满意度(响应时间)的同时保持较低的成本(最小化内存占用)。如果他的业务取得成功,他还需要考虑如何容纳更多的客户(可扩展性)。

 

Footnote:
[1] www.snopes.com/humor/jokes/autos.asp

在developerWorks上的相关资源:


本文翻译自:Measuring Java performance (or Jack starts a taxi business): Part 1(2017-10-25)

加入讨论