3

我有一个在 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 < 1 秒。HW Xeon E5-1620v4@3.5Ghz,64G RAM,4个物理,8个逻辑核心,500G SSD
  • 桌面 B < 1 秒。硬件 i7-3770@3.4Ghz,16G RAM,4 个物理内核,8 个逻辑内核,1TB 7200RPM 驱动器。

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

我已经消除的东西:

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

ark.intel.com 处理器比较

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

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

i7 桌面硬件对抗虚拟接口 i7-桌面

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

下一次尝试

我正在运行应用程序的本地集成版本。然后,我消除了应用程序开始完成的几乎 100% 的工作,并看到服务器硬件上的延迟越来越长。然后我-Xmx100G -Xms100G基本上试图阻止垃圾收集器运行 EVER 并看到以下结果(< 1 秒的一致延迟)。

巨大的内存

这让我想到了Java 8 的可用垃圾收集器

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

默认垃圾回收

显式选择 Garbage First Garbage Collector-XX:+UseG1GC选择 New: G1New, Old: G1Old,它的延迟图不是很好:

G1 GC

显式选择 Concurrent Mark Sweep Garbage Collector-XX:+UseConcMarkSweepGC选择 New: ParNew, Old: ConcurrentMarkSweep,它的延迟图看起来很棒:

CMS GC

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

追踪结果

尝试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

我不清楚我应该从中得出什么结论。futex桌面在系统调用和系统调用中都快很多倍poll。我仍然不明白为什么该应用程序在更快的硬件上更具有潜在性。

剖析

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

4

1 回答 1

1

我确认我正在使用performance带有 RedHat 的 CPU 调控器:CPUfreq Coverners

我遇到了有问题的 BIOS 设置的 VMWare ESXi 报告虚拟机应用程序在 EXSi 上运行比预期慢

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

启动时更改戴尔 R630(可能还有其他)上的 BIOS 的步骤:

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

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

服务器上的默认 GC: 默认GC

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

服务器上的第一代 GC: G1GC

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

逻辑核心时钟速度图

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

每瓦性能 (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
于 2018-07-31T19:23:35.637 回答