Java 胖客户端连接本地主机时速度慢,远程连接时速度快

Java 胖客户端连接本地主机时速度慢,远程连接时速度快

我在使用(通常)受延迟限制的桌面 Java 应用程序连接自定义数据库服务器时遇到了问题。

当它在远程主机(Windows XP)上工作时,它的速度很快(大表单在 2 秒内打开)。当它在数据库所在的同一主机上运行时(使用 X11vnc 和 NX),它的速度非常慢(相同的表单在大约 20 秒内打开)。服务器正在运行 SuSE Linux Enterprise Server 10。

我检查了:

  • iptablesfilter是干净的(在、rawmangle中没有规则nat,所有表格都接受)
  • 路由正常(仅默认路由和本地网络)
  • brtables 甚至没有安装
  • tc很干净
  • 对于 64 字节和 1500 字节数据包,到本地主机的 ping 延迟约为 0.007ms,到远程主机的延迟约为 0.8ms
  • 环回吞吐量约为 500MiB/s(经测试netcat
  • 不同的 Java VM(1.5 和 1.6)

看起来atop似乎没有任何瓶颈:

  • Java 和数据库进程的 CPU 利用率非常低(Java:~20%,数据库 <5%),远程访问时的 CPU 利用率适中(数据库约为 30%)服务器是四核 2.66Ghz,客户端是 Core 2 Duo 2.33Ghz,除此之外系统处于空闲状态
  • 长查询期间几乎没有任何磁盘读取/写入(总共约 5-10 次读取)

远程和本地运行之间唯一的区别是网络利用率,本地进程以大约 1200kbps 的速度提取数据,而远程以大约 15Mbps 的速度提取数据。

我目前正在用我的硬件复制该问题,因此也欢迎任何有关这方面的提示。

编辑:将lo接口 MTU 从默认的 16k 更改为 1500 可修复此问题。此问题在 Debain lenny 64bit 上也曾出现过。

答案1

我要给大家提供的只是一些没有特别顺序的调试想法......

  • 问题真的是环回吗?您是否尝试过连接到服务器的网络 IP 地址而不是 127.0.0.1?(这使用我系统上的环回接口,但它应该可以排除奇怪的 DNS 问题)
  • 是个系统这段时间内负载是否很高(io 问题可能导致系统负载高于所有单个进程加起来的负载)?
  • 检查每个进程的 netstat 信息,如果客户端的 Recv-Q 很高,则表示客户端进程没有定期从其套接字读取。
  • 尝试观察tcpdump -i lo,它可能有助于弄清楚传输的数据包是否有明显的模式。
  • “vmstat 1” 是否显示出远程访问与本地访问版本截然不同的行为(即,将数据集保存在数据库服务器和 Java 客户端的 RAM 中,迫使您进行交换)?
  • 尝试增加环回设备上的 MTU,我的默认为 16436。如果您处理大量小数据包,这不会有太大帮助。小数据包似乎有自己的问题。我不是 Java 程序员,所以我不知道该怎么做,但尝试在连接上设置 TCP_NODELAY(setsockopt 系统调用)。这个似乎有一个狂热的追随者,但据说如果通信是单向的,客户端将更频繁地响应 TCP ACK 并保持数据流动。
  • 另一件需要尝试调整的事情是:echo 1 > /proc/sys/net/ipv4/tcp_low_latency
  • 在使用 setsockopt 时,看看如果增加客户端的发送和接收缓冲区会发生什么?
  • 你使用的不是某种古老的 2.2 内核吧?根据 2.4 TODO,2.3.x 中显然修复了某种巨大的回环错误
  • 也许客户端(或 Java)中有一个错误,您是否在具有相同 Java 运行时的单独 Linux 系统上运行完全相同的客户端?

答案2

这听起来很奇怪,但对我来说,它以前是有效的。
检查 /etc/hosts 文件,确保主机名与 localhost 一致,或者添加指向 127.0.0.1 或监听的主机名。

答案3

为了消除 X11vnc 和 NX 作为延迟的可能原因,我将编写一个控制台模式非 GUI Java 测试程序,执行数据库查找或测试事务并计时该应用程序在 PC 和服务器上的运行时间(例如使用 SSH/Putty 来调用它)。

长远来看:如果 JDBC 驱动程序正在使用反向 DNS 解析(例如用于日志记录),我还会检查反向 DNS 解析,如果 DNS 配置不正确,软件可能会挂断,等待 DNS 解析超时。Java 应用程序中的 DBMS 位置是如何配置的?

答案4

我最喜欢的解决此类问题的工具是strace。您可能能够简单地 strace 客户端并看到它在执行某些操作(如 connect 或 read 等阻塞调用)后暂停。如果存在某种事件循环掩盖了暂停,您可以尝试过滤掉这些系统调用,或者您可以打开 strace 的计时选项并将整个输出保存在文件中。另一个技巧是等到它“完成”了阻碍它执行的操作并按下 ^C,这样您就可以查看发生了什么,从而将其从昏迷中唤醒。

相关内容