【问题标题】:What Could Cause Software to Run Slower on Better Hardware?什么可能导致软件在更好的硬件上运行更慢?
【发布时间】:2023-04-08 14:00:01
【问题描述】:

我有一个在 RHEL 7.4 上运行的 Java OSGi (Apache Felix) 应用程序,它以大约 975 个数据包/秒(长度为 1038 个八位字节)的速度读取多播 UDP。然后,它将数据转换为 XML,模拟通过边界设备,并将其转换回 UDP 多播数据包。涉及多个线程,并且它的编写方式是,如果模拟边界设备需要一段时间来处理一个负载,它会缓冲它并在下一次发送更大的负载。

通过此集成测试方案查看数据包延迟时,两台不同的桌面级机器比我们预期部署的相当高端的服务器要快得多。

  • 服务器延迟 5 秒。硬件:双 Xeon E5-2667v4@3.2GHz、128G RAM、16 个物理内核、32 个逻辑内核、RAID 1 SAS SSD。
  • 桌面 A
  • 桌面 B

为了完整起见,我只提到硬盘驱动器,因为此应用程序不会写入磁盘。在理论上,服务器的运行速度至少应该与两个桌面一样快。

我已经消除的东西:

  • 网卡。我已经对物理 NIC 和虚拟设备进行了测试,以防万一 NIC 之间存在显着差异。
  • 逻辑核心数。我已尝试禁用 16 和 24 个服务器逻辑核心以排除变量。
  • Java 版本。所有这三个都已在 OpenJDK 和 Oracle 的 Java 上使用相同版本 (Java 1.8.0) 进行了尝试,产生了相同的结果。
  • Java 标志是相同的,并且都与 felix 相关(安装目录、配置属性和要执行的 jar)。
  • SELinux。我已经在所有三种模式下都试过了(禁用、强制、许可)。我没想到这里会有什么不同,但我现在正在抓住任何东西。
  • 内核版本。我已经对3.10.04.13.04.15.0 进行了测试,结果相似。

ark.intel.com processor comparison

这里有两个示例图表来说明问题。该测试在 4 分 10 秒内向多播地址 A 发送 260,960 个 UDP 数据包,并在通过应用程序处理后,将数据包发送到多播地址 B。tcpdump 记录两者的时间戳,减法产生延迟。所有三个应用程序(Sender、Application、tcpdump 都在同一台机器上)。

首先针对虚拟接口的服务器硬件

i7 桌面硬件对抗虚拟接口

注意 Y 轴比例差异。服务器是 0-4 秒,i7 桌面是 0-1 秒。看起来难以阅读的 X 轴是 Packet Number。

下一次尝试

我正在运行应用程序的本地集成版本。然后,我消除了应用程序开始完成的几乎 100% 的工作,并看到服务器硬件上的延迟越来越长。然后我尝试-Xmx100G -Xms100G 基本上是为了让垃圾收集器永远不会运行,并看到了以下结果(

这让我找到了Java 8's Available Garbage Collectors

服务器硬件上的默认垃圾收集器选择是新的:ParallelScavenge,旧的:ParallelOld。这是没有 XML 转换的结果延迟图,我可以通过简单的测试来复制问题。

明确选择 Garbage First Garbage Collector -XX:+UseG1GC 选择 New:G1New,Old:G1Old,结果延迟图不是很好:

明确选择 Concurrent Mark Sweep Garbage Collector -XX:+UseConcMarkSweepGC 选择 New:ParNew,Old:ConcurrentMarkSweep,其生成的延迟图看起来很棒:

看起来问题已经解决了。一旦我将所有组件添加回原位,我仍然会遇到不可接受的延迟。我仍在运行测试,看看是否可以隔离问题。

追踪结果

尝试strace -c -o /path/to/file -f 产生了以下顶级系统调用

首先是 i7 的桌面 strace 报告(截断前 10 项)

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 93.71 1418.604132         959   1479659    134352 futex
  1.74   26.294223      730395        36           poll
  1.74   26.288786         314     83645         4 read
  1.41   21.373672          73    293618           epoll_pwait
  1.19   17.952475         120    149854         2 recvfrom
  0.10    1.448453           2    909731           getrusage
  0.06    0.896903           3    281407           sendto
  0.03    0.394695           2    198041           write
  0.01    0.182809          10     18246           mmap
  0.01    0.120735           6     20582           sched_yield

现在查看服务器的strace 报告:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.46 2119.311196        2642    802183    131276 futex
  1.28   27.734136     6933534         4           poll
  0.59   12.840448          49    263597           epoll_wait
  0.41    8.885742         113     78387         2 recvfrom
  0.07    1.575401           6    263671           sendto
  0.07    1.515999           6    262256           epoll_ctl
  0.04    0.902788          54     16800           sched_yield
  0.03    0.743231          10     75455           write
  0.02    0.490052           6     84509         7 read
  0.01    0.170152           4     42732           lseek

我不清楚我应该从中得出什么结论。在futexpoll 系统调用中,桌面速度要快很多倍。我仍然不明白为什么应用程序在更快的硬件上具有如此多的潜伏性。

分析

我已经在两个硬件上分析了软件,显示了相似的热点位置,这似乎排除了这种可能性。

【问题讨论】:

  • 我假设环境标志在两者上是相同的。黑暗中的一枪:您是否尝试过研究 JIT 如何在其中一个上工作(即,无论出于何种原因它是否不在服务器上)?您是否尝试过使用 Flight Recorder 或类似的东西来查看延迟可能来自何处?
  • 我只使用了与 felix 相关的 java 选项,所以标志应该是相同的。我现在将查看 JIT / Flight Recorder,看看是否有什么惊人的地方。
  • 分配给JVM的内存是否超过了不再使用压缩指针的阈值?你实际上可以在这一点上受到显着的性能影响,因为更少的内容适合缓存。 (是的,您指定 JVM 标志是相同的,但您没有指定这些标志 是什么,因此我们不知道哪些配置是显式的,哪些是从硬件推断的) .
  • ...不过,这确实是我要退出(商业)JVM 分析工具(也许还有 sysdig,以查看操作系统级别的系统调用响应是否存在差异)的地方次)。
  • Java 标志是默认的,而不是告诉 felix 从哪里获取配置/属性。如何判断分配给 JVM 的内存是否超过了这个阈值?此外,服务器版本的缓存是桌面 A 的 2.5 倍,这使得它不太可能,但我现在想排除一切。我会研究一下 sysdig。

标签: java osgi performance-testing multicast latency


【解决方案1】:

我确认我正在使用 performance CPU 调节器和 RedHat:CPUfreq Coverners

我遇到了一个 VMWare ESXi 报告有问题的 BIOS 设置 Virtual Machine Application runs slower than expected on EXSi

这直接指向我的答案。此戴尔 R630 的默认设置是“每瓦性能 (DAPC)”(DAPC:戴尔有源电源控制器)。切换到“性能”完全解决了这个问题。机器在控制台上感觉更快,延迟比台式机能够实现的要低得多,考虑到 CPU 的差异,这是我所期望的。

在戴尔 R630(以及可能的其他设备)启动时更改 BIOS 的步骤:

  1. F2 进入系统设置
  2. 选择“系统 BIOS”
  3. 选择“系统配置文件设置”
  4. 确保第一个条目设置为“Performance”,默认为“Performance Per Watt”
  5. 选择“返回”
  6. 选择“完成”
  7. 选择“是”以通过系统重置保存更改
  8. 选择“确定”设置保存成功

这是生成的延迟图,它们使用相同的 1 秒刻度。

服务器上的默认 GC:

服务器上的并发标记扫描 GC:

服务器上的第一代 GC:

G1GC 和 CMSGC 之间没有太大区别,但两者的延迟明显优于默认值(这是预期的)。

逻辑核心时钟速度图表

符号很难看到,但这两张图上有 32 个不同的点。总体而言,您可以快速判断哪个是性能,哪个是每瓦性能 dapc。

每瓦性能 (DAPC):

性能

一起绘制。红色子弹的性能,蓝色空心圆圈的每瓦性能

这是在 BIOS 设置相应的 300 秒数据流期间捕获的。以下是我捕获数据的方式,以防有人想知道:

for i in `seq 300`; do
  paste /sys/devices/system/cpu/cpu[0-9]*/cpufreq/cpuinfo_cur_freq
  sleep 1
done > performance.log

【讨论】:

  • 伟大的工作,感谢分享这个(我不确定 SO 是理想的论坛,但无论如何它都是一些可靠的调查)。顺便说一句,我建议for ((i=0; i<300; i++)); do paste /sys/devices/system/cpu/cpu[0-9]*/cpufreq/cpuinfo_cur_freq; sleep 1; done >performance.log——这样你只打开输出文件一次,而不是 300 次。
  • 你是对的,重定向应该发生在循环的完成点,很好。
猜你喜欢
  • 1970-01-01
  • 2023-01-15
  • 2017-12-03
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多