我有一个在 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结果相似。
这里有两个示例图来说明这个问题。该测试在 4 分 10 秒内将 260,960 个 UDP 数据包发送到多播地址 A,并在通过应用程序处理后,将数据包发送到多播地址 B。tcpdump记录两者的时间戳并减去产生延迟。所有三个应用程序(Sender、Application,tcpdump都在同一台机器上)。
首先是针对虚拟接口的服务器硬件

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,它的延迟图不是很好:

显式选择 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
我不清楚我应该从中得出什么结论。futex桌面在系统调用和系统调用中都快很多倍poll。我仍然不明白为什么该应用程序在更快的硬件上更具有潜在性。
剖析
我已经在两个硬件上分析了软件,显示了热点的相似位置,这似乎排除了这一点。





