我有一个运行在RHEL7.4上的JavaOSGi(ApacheFelix)应用程序,它以大约975包/秒(1038个八位字节的长度)读取多播UDP。然后,它将数据转换为XML,模拟穿越边界设备,并将其转换回UDP多播数据包。涉及到多个线程,它的编写方式是,如果模拟边界设备处理一个负载需要一段时间,它会缓冲它,并在下次通过时发送更大的负载。
当通过这个集成测试场景查看数据包延迟时,两个不同的桌面级机器明显快于我们期望部署的相当高端的服务器。
-
服务器延迟5秒。硬件:双Xeon E5-2667v4@3.2GHz,128G内存,16个物理核,21个逻辑核,RAID 1 SAS固态硬盘。
-
桌面A<1秒。HW Xeon E5-1620v4@3.5Ghz,64G内存,4个物理核,8个逻辑核,500G固态硬盘
-
桌面B<1秒。HW i7-3770@3.4Ghz,16G内存,4个物理核,8个逻辑核,1TB 7200RPM驱动器。
为了完整起见,我只提到硬盘驱动器,因为这个应用程序不会写入磁盘。在纸面上,服务器的运行速度至少应该和两台台式机一样快。
我已经消除的东西:
-
网卡。我已经用物理网卡和虚拟设备进行了测试,以防网卡之间存在显著差异。
-
逻辑核心数。为了排除变量,我尝试禁用16个和24个服务器逻辑核心。
-
Java版本。这三个版本都已经在OpenJDK和Oracle的Java中试用过,它们都有相同的版本(Java
1.8.0
)产生相同的结果。
-
Java标志是相同的,并且都与felix(install directory,configuration properties,and jar to execute)相关。
-
塞莱努克斯。我尝试过三种模式(禁用、强制、允许)。我没想到这里会有什么不同,但我在这一点上有所把握。
-
内核版本。我试过测试
3.10.0
,
4.13.0
,和
4.15.0
结果相似。
ark.intel.com processor comparison
这里有两个示例图来说明这个问题。此测试通过4分10秒将260960个UDP数据包发送到多播地址A,并在通过应用程序处理后,将这些数据包发送到多播地址B。
tcpdump
记录两者的时间戳,然后减法产生延迟。所有三个应用程序(发件人、应用程序、,
命令
在同一台机器上)。
首先是针对虚拟接口的服务器硬件
i7针对虚拟接口的桌面硬件
注意Y轴的尺度差。服务器为0-4秒,i7桌面为0-1秒。出现难以读取的X轴是包号。
下一次尝试
我正在运行应用程序的本地集成验证。然后,我消除了几乎100%由应用程序开始的工作,并看到服务器硬件上的延迟不断增加。我试过了
-Xmx100G -Xms100G
基本上是为了防止垃圾回收器运行并看到以下结果(<1秒一致延迟)。
这让我
Java 8's Available Garbage Collectors
.
服务器硬件上的默认垃圾收集器选择是New:parallelsecruke,Old:ParallelOld。这是没有XML转换的结果延迟图,尽可能简单的一个测试来复制问题。
显式选择垃圾第一垃圾收集器
-XX:+UseG1GC
选定的新:G1New,旧:G1Old,其结果延迟图不太好:
显式选择并发标记扫描垃圾收集器
-XX:+UseConcMarkSweepGC
选定的New:ParNew,Old:concurrentmarkswipe及其生成的延迟图看起来非常出色:
看来问题解决了。一旦我把所有的组件都添加回原处,我仍然会有不可接受的延迟。我还在做测试,看能不能把问题隔离开来。
Strace结果
尝试
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
现在是服务器的
斯特拉斯
报告:
% 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
系统调用。我仍然不明白为什么应用程序在更快的硬件上更隐蔽。
剖析
我已经分析了两个硬件上的软件,显示了热点的相似位置,这似乎排除了这一点。