常见 JSOR 问题(仅限 Linux)

使用基于远程直接内存访问 (JSOR) 的 Java™ 套接字来利用高性能网络基础结构,例如 InfiniBand。 要使用 JSOR,必须设置、配置和调优各种资源。 如果操作不正确,可能会发生问题。

注意: SR8 FP30 更改开始IBM®SDK,Java 技术版,版本 8.服务更新 8 修复包 30 的更改结束中移除了之前被弃用的 RDMA 实现

RDMA 套接字或线程创建失败

在无法创建线程或远程直接存储器存取 (RDMA) 套接字的情况下,可能发生 JSOR 问题。 导致此问题的原因可能是通过 RDMA 传输来运行并发连接。

可能的原因

  • RDMA 套接字缓冲区在缺省情况下是固定或内存锁定的。 环境中受限的 memlock 设置可能导致无法创建或注册新的 RDMA 套接字。
  • 运行并行连接时,各 RDMA 套接字隐式使用文件描述符进行事件跟踪。 如果最大用户打开文件数限制过低,那么套接字创建可能会失败。
  • 运行并行连接时,最大用户进程数限制过低可能会导致线程创建失败。 有关详细信息,请参阅以下技术说明:java.lang.OutOfMemoryError 同时创建新线程

缓解

  • 为避免套接字创建失败,请检查 ulimit -l 设置,并根据套接字缓冲区的使用情况将 memlock 设置更改为适合的值。
  • 为避免在运行并发连接时套接字创建失败,请检查 ulimit -n 设置,并根据应用程序的可扩展需求将 nofile 设置更改为适合的值。
  • 为避免在运行并发连接时线程创建失败,请检查 ulimit -u 设置,并根据应用程序的可扩展需求将 nproc 设置更改为适合的值。

RDMA 网络提供商初始化失败

在运行 32 位 JVM 时,如果 64 位 Linux 操作系统上的远程直接存储器存取 (RDMA) 网络提供商初始化失败,那么可能发生 JSOR 问题。

在 RDMA 网络初始化阶段,JSOR 运行时环境会检查兼容 OFED 运行时库的可用性。 如果运行时环境无法找到和装入 librdmacm.solibibverbs.so 32 位库,那么您可能会看到此问题。 要避免此问题,请在 64 位 Linux® 机器上安装 32 位 OFED 运行时库以及通常的 64 位库。

RDMA 连接失败

在远程直接存储器存取 (RDMA) 客户机未能连接到 RDMA 服务器的情况下,可能发生 JSOR 问题。

客户机和服务器在同一主机上

如果客户机和服务器位于同一主机上,那么预期会出现此行为,因为当前不支持 RDMA 回送。 为成功进行连接,客户机和服务器应位于由 InfiniBand 交换机通过 RDMA 网络接口适配器连接的不同主机上。

如果 RDMA NIC 有两个物理端口并且带有两个 InfiniBand 接口地址,那么可以使用外部硬件回送插头(单独购买)对端口进行连接。 然后可以将来自一个端口的数据回送到同一主机上的另一个端口。 通过此安排,RDMA 客户机和服务器可在同一主机上运行,各自选取不同的 InfiniBand 地址。
注: 此配置尚未在 Java 环境中进行测试。

客户机和服务器在不同子网上

RDMA 客户机和服务器应位于由公共 InfiniBand 交换机连接并由单个子网管理器管理的同一网络上。 如果 RDMA 客户机和服务器位于不同子网上,请确保在硬件和软件级别启用网络间交换和包转发。

客户机和服务器在同一子网上

如果客户机和服务器位于同一子网上,那么连接失败可能是由于客户机或服务器配置文件不正确或者一台或两台主机上的 InfiniBand 设置不正确所导致。

确保配置文件中的规则条目定义正确,如 -Dcom.ibm.net.rdma.conf (Linux 仅适用) 中所述。

按照以下步骤检查 InfiniBand 设置:
  1. 确保通信中涉及的各主机具有相应的 InfiniBand 主机通道适配器或带有有效 InfiniBand 地址的 RDMA 网络接口卡(以前缀 ib 开头的接口)。
  2. 确保各 InfiniBand 端口处于活动状态且正确设置了最大传输单元。 要检查最大传输单元,请运行以下某个 OFED 运行时命令:ibstatibv_devinfo
  3. 确保 ifconfig 命令列出所有 InfiniBand 接口,并且各接口具有有效的 IP 地址。
  4. 选择向子网管理器注册的用于制定 JSOR 配置规则的两个有效 InfiniBand 地址,然后通过对所选的 InfiniBand 地址运行 rping 命令来验证主机和客户端机器之间是否可以进行基本 RDMA 通信。
  5. 类似地,运行 ibv_rc_pingpong 命令。
  6. 类似地,运行 ib_read_bwib_write_bw 命令。
如果所有这些步骤都成功,那么表明机器之间的基本 RDMA 通信没有问题。 要进一步确定问题所在,请阅读作为 OFED 源代码发行版一部分的 README.txt 文件的配置部分:https://www.openfabrics.org/ofed-for-linux/.

RDMA 连接重置异常

尝试数百万次地将小数据区块发送到单个 RDMA 服务器的并发远程直接存储器存取 (RDMA) 客户机可能会抛出连接重置异常。

Java Sockets over Remote Direct Memory Access (JSOR) 采用 R-Sockets 协议作为在 RDMA 基础上实现套接字级 API 的基础。 R-Sockets 协议使用发送和接收队列大小作为在发送方和接收方之间实施数据流和事件控制的基础。 当若干并行客户机尝试百万次地发送少量数据时,它们可能会由于队列大小不足而遇到连接重置异常。 发生此行为是因为队列大小规定了任一端可以排队的工作量。

由于默认队列大小很大(请参阅 JSOR 环境设置(Linux 仅适用)),只有在极少数情况下才需要调整队列大小。 您应根据应用程序的工作负载特征来确定队列大小。 发送和接收操作的最大数量和频率尤其重要。 没有可用于确定最佳队列大小的一般公式。

RDMA 通信似乎挂起

在运行消息大小不可预测的基于 RPC 的工作负载时,客户机和服务器之间的远程直接存储器存取 (RDMA) 通信似乎挂起。

Java Sockets over Remote Direct Memory Access (JSOR) 采用 R-Sockets 协议作为在 RDMA 基础上实现套接字级 API 的基础。 要正确传输数据,R-Sockets 协议需要协调发送方和接收方。 接收方必须准备好一个接收缓冲区,以供发送方放置数据。 该行为与按需自动分配缓冲区的 TCP/IP 不同。 如果事先未提供足够的接收缓冲区,RDMA 接收操作将失败。 有关详细信息,请参阅 Remote Direct Memory Access Transport for Remote Procedure Call 的 IETF 草案中的流量控制部分。

缺省情况下,JSOR 实现提供了大小小于 50 KB 的较小发送和接收缓冲区。 如果 RDMA 客户机或服务器尝试以 1 KB 这样的区块为单位,单向发送较大有效内容(例如 2 MB 或 4 MB),而不包含端点之间的同步数据流,那么接收缓冲区可能会被耗尽,从而导致挂起的情况。 R-Socket 协议尝试回收接收缓冲区,但如果补给速度小于数据发送速度,那么将无法继续运行。 当有上百个并行客户机尝试在同一 RDMA 传输上执行相同操作时,这些影响更加明显,因为这些客户机争用同一组物理网络资源。 R-Sockets 协议从此情况恢复需要较长的时间,因为它依赖于重试和“接收方未就绪”否定确认才能继续运行。 最糟糕的情况是该行为可能会导致端点之间发生死锁情况。

类似地,发送缓冲区的大小应该足够大,以将数据传输到对应的接收缓冲区。

缓解

对于 Java RPC 应用程序,请先调整缓冲区大小,然后再在生产环境中部署该应用程序。 根据应用程序的工作负载特征和最大有效内容大小,设置缓冲区大小。 没有可用于确定最佳缓冲区大小的一般公式。 有关更多信息,请参阅 JSOR 环境设置(Linux 仅适用)

启用应用程序或运行时数据传输超时以允许客户机取消并重试数据传输,必要时增加缓冲区大小。 请参阅以下 APAR 示例:PM52124: OutOfMemoryError eXtreme Scale 客户端上的错误会导致网格失败。 在该示例中,内存不足导致服务器线程在 socketWrite() 方法中挂起。 建议的解决方法是设置 com.ibm.CORBA.SocketWriteTimeout 属性。

遇到的零拷贝功能的有关问题

启用零复制功能时 Java 应用程序挂起

由于在使用零拷贝功能时,需要在数据源和数据接收器之间进行内部同步,因此如果仅为一个端点启用零拷贝功能,客户机或服务器应用程序可能会挂起。

为避免此问题,请采取以下操作:

Java 应用程序未使用零复制函数

即使在指定 -Dcom.ibm.net.rdma.zeroCopy=true 参数之后, Java 应用程序也可能不使用零复制功能。

仅在以下两个语句均成立的情况下才会使用零拷贝功能:
  • 您已指定 -Dcom.ibm.net.rdma.zeroCopy=true 参数。
  • 在 Java 读写调用中传递的缓冲区大小超过 -Dcom.ibm.net.rdma.zeroCopyThreshold 参数指定的值。 有关此参数的更多信息,请参阅 -Dcom.ibm.net.rdma.zeroCopyThreshold (Linux only)
您可以使用标准的 JSOR 跟踪机制,通过在跟踪中查找以下函数来了解是否使用了零拷贝功能:
  • socketRead0Direct
  • socketWrite0Direct
  • RDMA_ReadDirect
  • RDMA_SendDirect

Java 应用程序不扩展

零拷贝功能是针对大量数据传输而设计的,一次传输一小部分数据。 由于内部同步和资源分配与管理开销,可伸缩性受到传输的数据大小的限制。

请确保使用方案接近于零拷贝方式下数据传输的文件传输 (FTP) 类型的方案。

遇到派生兼容性方式问题

在 Java 客户机与本机派生服务器之间以派生兼容性方式运行时,可能会发生一些问题。

本机服务器错误消息 librdmacm: Fatal: unable to open RDMA device

此消息与大约 100 个客户机线程重复打开连接并传输数据时发生的已知 Open Fabrics Enterprise Distribution (OFED) 问题相关。 在以下系统配置中会发生此问题:
  • 具有基于融合以太网的 Mellanox RDMA (RoCE) MT26448 适配器的 POWER ® PC 系统
  • Redhat Enterprise Linux (RHEL) v6.4
  • MLNX_OFED_LINUX-2.0-3.0.0
在具有更高版本的 Mellanox 适配器 MT4099(运行 RHEL V7 beta 和 OFED V3.5)的系统上未发生此问题。

如果遇到此问题,请升级到操作系统和 OFED 软件的最新版本。 如果问题仍然存在,请考虑升级到 Mellanox RoCE 适配器的最新版本。

Java 客户机挂起

在派生兼容性方式下,当系统连接到本机派生服务器时, Java 客户机可以挂起。 此问题与 RSocket 预装入库关联。 在内部,当处理 fork() 支持时,库会创建指定的信号量 /rsocket_fork。 但在完成时,R-Socket 库不会移除信标,该信标持久存储,直至系统重新引导为止。 先前调用中的此指定信标的任何旧链接或值会阻止本机服务器接受远程客户机连接。

要解决此问题,请使用 rm 命令在 fork() 预装入开始之前取消链接 /rsocket_fork 指定的信号量。 在 Red Hat Enterprise Linux (RHEL) 上,您可以在目录 /dev/shm 中查找指定的信标。 这些文件具有前缀 sem.

Java 客户机不扩展

RSockets 协议当前仅为理想条件下运行的简单应用程序提供派生预装入支持。 在预装入派生进程时, RSockets 库使用分块语义将连接迁移到 RDMA。

因此,RSocket 中 fork() 方法的当前支持固有地无法扩展。 尝试使用本机互操作性功能连接到本机派生服务器的 Java 多线程客户机可能会迂到大量失败连接。 要缓解此问题,请将客户机连接重试计数增大到 1 以上。