【问题标题】:Protocol Buffer first usage high latencyProtocol Buffer 首次使用高延迟
【发布时间】:2019-12-18 19:02:46
【问题描述】:

在我们的一个 java 应用程序中,我们有很多协议缓冲区类,并且 jar 本质上公开了一个接口,其中一个方法由另一个应用程序使用。我们注意到,第一次调用此方法时,调用时间相当长(>500ms),而随后的调用要快得多(

这在另一个应用程序中得到了进一步证实,该应用程序的工作方式完全不同 - 但也使用协议缓冲区 - 表现出相同的行为。此外,我们尝试在启动时为所有 proto 缓冲区类创建一个虚拟实例 (XY.newBuilder().build()),我们添加的每个类都可以注意到第一次调用下降的开销。

在 .NET 中,我可以找到另一个显示类似问题的问题 (Why is ProtoBuf so slow on the 1st call but very fast inside loops?),但是那里的解决方案似乎特定于带有预编译序列化程序的 C#。到目前为止,我在 Java 中找不到相同的问题。是否有类似上述问题中所示的适用于 java 的解决方法?

【问题讨论】:

  • 我想延迟发生是因为 JVM 需要加载新类。你可以开启类加载日志看看是不是真的。
  • 这是个好主意,我会尽快启用详细类加载,看看这是否证实了我的怀疑。

标签: java protocol-buffers


【解决方案1】:

JVM 附带即时 (JIT) 编译器,可对您的代码进行大量优化。如果您想进一步了解它,可以深入研究 JVM 内部。会有类加载和卸载、性能配置文件、代码编译和反编译、偏向锁定等。

举个例子,这会变得多么复杂,根据this article,在 OpenJDK 中有两个编译器(C1 和 C2),有五个可能的代码编译层:

分层编译有五层优化。它从第 0 层(解释器层)开始,其中插桩提供有关性能关键方法的信息。很快,第 1 层,简单的 C1(客户端)编译器,优化了代码。在第 1 层,没有分析信息。接下来是第 2 层,其中只编译了几个方法(再次由客户端编译器)。在第 2 层,对于这几个方法,为入口计数器和环回分支收集分析信息。然后,第 3 层将看到客户端编译器使用完整的分析信息编译所有方法,最后第 4 层将利用服务器编译器 C2。

这里的要点是,如果您需要可预测的性能,您应该始终通过在每次部署后运行一些虚拟请求来预热您的代码。

您使用创建所有使用的 protobuff 对象的虚拟代码做了正确的事情,但您应该更进一步并预热您正在使用的实际方法。

【讨论】:

  • 我可以通过详细的类加载确认所有时间都花在了第一条消息的类加载上。解决方案是通过 Reflections 包从具有许多 protobuffer 文件的位置获取所有类,现在差异可以忽略不计。
猜你喜欢
  • 2013-06-23
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2018-07-08
  • 2013-04-10
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多