Protocol Buffer 首次使用高延迟
Protocol Buffer first usage high latency
在我们的一个 java 应用程序中,我们有相当多的协议缓冲区 类 并且 jar 本质上公开了一个接口和一个方法,供另一个应用程序使用。我们注意到,第一次调用此方法的调用时间非常长(>500 毫秒),而后续调用要快得多(<10 毫秒)。起初我们假设这与我们的代码有关,但是在分析之后我们无法证实这一点。通过排除的过程,很明显它与协议缓冲区有关。
这在另一个应用程序中得到了进一步证实,该应用程序的工作方式完全不同 - 但也使用协议缓冲区 - 显示出相同的行为。此外,我们尝试在启动时为所有原型缓冲区 类 创建一个虚拟实例 (XY.newBuilder().build()
),对于我们添加的每一个,我们都可以注意到第一次调用的开销下降。
在 .NET 中,我可以找到另一个显示类似问题的问题 (Why is ProtoBuf so slow on the 1st call but very fast inside loops?),但是那里的解决方案似乎特定于带有预编译序列化程序的 C#。到目前为止,我在 Java 中找不到相同的问题。是否有适用于 java?
的解决方法,如上述问题中所示的解决方法
JVM 附带即时 (JIT) 编译器,它可以对您的代码进行大量优化。如果您想进一步了解,可以深入了解 JVM 内部结构。会有class加载卸载、性能配置文件、代码编译反编译、偏向锁等
举个例子,根据 this article,OpenJDK 中有两个编译器(C1 和 C2),有五个可能的代码编译层:
Tiered compilation has five tiers of optimization. It starts in tier-0, the interpreter tier, where instrumentation provides information on the performance critical methods. Soon enough the tier 1 level, the simple C1 (client) compiler, optimizes the code. At tier 1, there is no profiling information. Next comes tier 2, where only a few methods are compiled (again by the client compiler). At tier 2, for those few methods, profiling information is gathered for entry-counters and loop-back branches. Tier 3 would then see all the methods getting compiled by the client compiler with full profiling information, and finally tier 4 would avail itself of C2, the server compiler.
这里的要点是,如果您需要可预测的性能,您应该始终在每次部署后通过 运行 一些虚拟请求来预热您的代码。
你用虚拟代码创建了所有使用过的 protobuff 对象是正确的,但你应该更进一步,预热你正在使用的实际方法。
在我们的一个 java 应用程序中,我们有相当多的协议缓冲区 类 并且 jar 本质上公开了一个接口和一个方法,供另一个应用程序使用。我们注意到,第一次调用此方法的调用时间非常长(>500 毫秒),而后续调用要快得多(<10 毫秒)。起初我们假设这与我们的代码有关,但是在分析之后我们无法证实这一点。通过排除的过程,很明显它与协议缓冲区有关。
这在另一个应用程序中得到了进一步证实,该应用程序的工作方式完全不同 - 但也使用协议缓冲区 - 显示出相同的行为。此外,我们尝试在启动时为所有原型缓冲区 类 创建一个虚拟实例 (XY.newBuilder().build()
),对于我们添加的每一个,我们都可以注意到第一次调用的开销下降。
在 .NET 中,我可以找到另一个显示类似问题的问题 (Why is ProtoBuf so slow on the 1st call but very fast inside loops?),但是那里的解决方案似乎特定于带有预编译序列化程序的 C#。到目前为止,我在 Java 中找不到相同的问题。是否有适用于 java?
的解决方法,如上述问题中所示的解决方法JVM 附带即时 (JIT) 编译器,它可以对您的代码进行大量优化。如果您想进一步了解,可以深入了解 JVM 内部结构。会有class加载卸载、性能配置文件、代码编译反编译、偏向锁等
举个例子,根据 this article,OpenJDK 中有两个编译器(C1 和 C2),有五个可能的代码编译层:
Tiered compilation has five tiers of optimization. It starts in tier-0, the interpreter tier, where instrumentation provides information on the performance critical methods. Soon enough the tier 1 level, the simple C1 (client) compiler, optimizes the code. At tier 1, there is no profiling information. Next comes tier 2, where only a few methods are compiled (again by the client compiler). At tier 2, for those few methods, profiling information is gathered for entry-counters and loop-back branches. Tier 3 would then see all the methods getting compiled by the client compiler with full profiling information, and finally tier 4 would avail itself of C2, the server compiler.
这里的要点是,如果您需要可预测的性能,您应该始终在每次部署后通过 运行 一些虚拟请求来预热您的代码。
你用虚拟代码创建了所有使用过的 protobuff 对象是正确的,但你应该更进一步,预热你正在使用的实际方法。