使用 Socket Direct Protocol 实现 DB2 的 RDMA 功能

诸如主机适配器和 Ethernet 交换机之类的 LAN 网络设备在过去几年中得到了较大的发展,使得实现高达 40Gbps 的吞吐量以及低于 1 微秒的网络延迟成为可能。计算能力和 LAN 设备不再是一个瓶颈。相反,在这个高性能硬件的新时代里,TCP 之类的协议变成了真正的瓶颈。为了克服 TCP 局限性,人们开发了诸如 Remote Direct Memory Access (RDMA) 之类的新协议。本文将介绍一种经济高效的方法,可使用该方法在 DB2 客户端服务器环境中实现 RDMA 功能,而不需要重新编码和重新编译现有应用程序。

Sorin Iszlai, 系统工程师, IBM

作者的照片Sorin Iszlai 是一名系统和网络工程师,拥有超过 17 年的 IT 行业从业经验。Sorin 目前在 IBM Software Lab 工作,主要研究硬件加速和设备优化领域的新技术。



2012 年 10 月 08 日

免费下载:IBM® DB2® Express-C 10.1 免费版 或者 DB2® 10.1 for Linux®, UNIX®, and Windows® 试用版
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

简介

RDMA 是一种支持计算机绕过操作系统(内核和 TCP 堆栈)访问其他计算机上内存位置的机制。与传统的基于 TCP 的软硬件架构相比较,RDMA 有几个优势。内核旁路 (Kernel bypass) 意味着缩短了两个应用程序之间的路径,并减少了 CPU 利用率。通过直接在网络适配器和应用程序内存(用户空间)之间传输数据减少了特定于 TCP 的协议开销,无需将数据复制到内核空间并进行缓存。

为了充分利用 RDMA 提供的所有优势,需要使用 RDMA 语义或上层协议,比如 User-Level Direct Access Transport (uDAPL) 或 Message Passing Interface (MPI) 来编写应用程序。然而,对于 RDMA 来说,重写一个 TCP 应用程序可能非常昂贵,因此,针对这种情况开发了一个替代解决方案。该方法称之为 Direct Socket Protocol (SDP),无需重新编码任何应用程序。

SDP 是一个连线协议,在 RDMA 能力的适配器和套接字之间使用。鉴于这个原因,SDP 对应用程序是透明的,而标准流套接字的实现不需要使用另一个 API 替换。DB2 应用程序和 DB2 服务器无需修改就可在 SDP 或 TCP 上运行。用户只需要在执行应用程序之前通过预加载 SDP 共享库来选择要使用的协议即可。所有关于 TCP 的设置,比如主机名、IP 地址和端口,均无需修改。

例如,一个使用 TCP 连接到数据库服务器的 Java 应用程序也可以使用相同 JDBC URL 在 SDP 上运行。该 SDP 库,一旦预加载之后,将根据一组在 /etc/libsdp.conf 中定义的规则,以及服务器接受的协议来决定必需启动哪个协议。默认规则指定 SDP 作为第一个选项,如果连接失败,SDP 库将退回到 TCP。

一个应用程序可以只使用 SDP,或者只使用 TCP,或者同时使用二者。例如,可以将一个应用程序配置为使用 SDP 实现 DB2 数据库连接以及使用 TCP 实现 LDAP 连接。数据库和 LDAP 服务器可以在不同的物理机器上运行,或者运行在相同的机器上但侦听不同的接口。本文稍后将讨论各种场景以及如何应用规则。

硬件和软件基础架构

RDMA 需要专用的硬件和软件基础架构。本文将讨论 Linux x86 平台上的 SDP。

  • 主机适配器

    两类主机适配器支持 RDMA:Infiniband 适配器和 RoCE 适配器。前者需要 Infiniband 交换机,而后者需要 Ethernet 交换机。

    本例使用 Mellanox RoCE 适配器。本文提供的所有指令均适用于 Infiniband 适配器,只需稍作修改或无需修改。RoCE (RDMA over Converged Ethernet) 是 Infiniband over Ethernet 协议的一个实现。Converged Ethernet 网络允许不同类型的协议共享同一个媒介。定期封装 IP 数据包、Infiniband over Ethernet 和 Fiber Channel over Ethernet 的 LAN Ethernet 框架都可在一个 Ethernet 线路中共存。

  • 设备驱动程序

    这里有几个关于操作 Mellanox 适配器所需要的设备驱动程序和工具。所有可用的设备驱动程序和工具都是以 OpenFabrics Alliance 维护的 OFED 堆栈为基础。参阅 参考资料 部分,获取 OFED 网站链接。

  • 操作系统

    Red Hat Linux 6.2,内核版本 2.6.32-220.4.1.el6.x86_64。

  • Ethernet 交换机

    10Gbps RackSwitch G8264,操作系统版本 6.8.1.0。


安装 Mellanox 驱动程序和工具

  1. Mellanox 软件被打包为一个 ISO 映像。从 参考资料 部分提供的链接下载适合您操作系统的映像,对于 Red Hat 6.2,映像名为 MLNX_OFED_LINUX-1.5.3-3.0.0-rhel6.2-x86_64.iso。

    除非另有规定,以下所有命令都作为 root 来执行。

    在每个计算机上挂载 ISO 映像并启动安装程序,如清单 1 所示。

    清单 1. ISO 映像和安装程序
    bash# mount -o loop MLNX_OFED_LINUX-1.5.3-3.0.0-rhel6.2-x86_64.iso /mnt/iso
                            
    bash# cd /mnt/iso
                            
    bash# ./mlnxofedinstall
    This program will install the MLNX_OFED_LINUX package on your machine.
    Note that all other Mellanox, OEM, OFED, or Distribution IB packages will be removed.

    安装程序将安装所有驱动程序和工具,并将尝试升级每个 Mellanox 卡中的固件,只要它们的版本比 ISO 映像包含的版本低即可。

  2. 重启计算机以加载所有内核模块。
  3. SDP 需要 Ethernet 接口配置一个 IP 地址。对于 Infiniband 接口,IPoIB 必须启用,这基本意味着在 ib* 接口上配置 IP 地址以及在 /etc/infiniband/openib.conf 上启用 IPOIB_LOAD=yes

    首先,需要识别新设备。这一命令将列出所有 Mellanox 网络适配器和适配器的当前设置,包括 Link Layer 类型(本例中是 Ethernet)、固件版本和链接状态,如清单 2 所示。

    清单 2. Mellanox 网络适配器
    bash# ibv_devinfo
    hca_id: mlx4_0
            transport:                      InfiniBand (0)
            fw_ver:                         2.10.300
            node_guid:                      0002:c903:0005:6aa8
            sys_image_guid:                 0002:c903:0005:6aab
            vendor_id:                      0x02c9
            vendor_part_id:                 4099
            hw_ver:                         0x0
            board_id:                       IBM1020110023
            phys_port_cnt:                  2
                    port:   1
                            state:                  PORT_ACTIVE (4)
                            max_mtu:                2048 (4)
                            active_mtu:             1024 (3)
                            sm_lid:                 0
                            port_lid:               0
                            port_lmc:               0x00
                            link_layer:             Ethernet
                            
                    port:   2
                            state:                  PORT_DOWN (1)
                            max_mtu:                2048 (4)
                            active_mtu:             1024 (3)
                            sm_lid:                 0
                            port_lid:               0
                            port_lmc:               0x00
                            link_layer:             Ethernet
  4. 要识别出哪个端口与 eth* 接口相关联,执行以下命令,并将 IP 地址分配给相应接口,如清单 3 所示。
    清单 3. 识别端口
    bash# ibdev2netdev 
    mlx4_0 port 1 ==> eth8 (Up)
    mlx4_0 port 2 ==> eth9 (Down)
                            
    bash# ifconfig eth8 10.7.7.1 netmask 255.255.255.0

在内核和用户空间启用 SDP

SDP 不是默认启用的。除了前面提到的 libsdp.so 用户库,部分 SDP 实现为一个需要加载的内核模块。

  1. 加载 SDP 内核模块 ib_sdp,并编辑 /etc/infiniband/openib.conf 来将该参数设置为 yes,如清单 4 所示。
    清单 4. 参数设置为 yes
    SDP_LOAD=yes
  2. 重新启动系统,或手动加载该模块。然后验证内核模块是否加载,如清单 5 所示。
    清单 5. 加载模块
    bash# modprobe ib_sdp
                            
    bash# lsmod | grep ib_sdp
    ib_sdp 130827 0
    rdma_cm 35175 2 ib_sdp,rdma_ucm
    ipv6 322029 89 ib_sdp,ib_addr,ib_ipoib
    ib_core 69947 14
  3. 配置应用程序以便加载动态库 /usr/lib64/libsdp.so。有两种方法可用于加载 SDP 库。您可以对创建的每个进程预加载该 SDP 库,或者对整个系统预加载该 SDP 库。这些方法适用于任何使用 glibc 套接字调用的应用程序,包括使用 JDBC 连接到数据库服务器的 Java 应用程序。
    1. 为您创建的每个进程预加载此库,如清单 6 所示。
      清单 6. 预加载库
      bash# LD_PRELOAD=/usr/lib64/libsdp.so myapplication
    2. 为整个系统预加载此库。系统中的每个进程将预加载该库。在 /etc/ld.so.preload 中添加下面一行,如清单 7 所示。
      清单 7. 使用 /etc/ld.so.preload 预加载 SDP
      /usr/lib64/libsdp.so
    3. 检查一个应用程序是否将在运行时加载 SDP 库,如清单 8 所示。
      清单 8. 运行时的 SDP 库
      bash# ldd my_app | grep sdp
      /usr/lib64/libsdp.so (0x00007f217170d000)
  4. 启动 DB2 服务器和客户端之前,可使用 echo servertelnet 来测试 SDP 是否正常运行。通过设置 disable = no 启用 /etc/xinetd.d/echo-stream 中的 echo 服务器。

    1. 重启 xinetd 守护进程,如清单 9 所示。
      清单 9. xinetd 守护进程
      bash# service xinetd restart
      Stopping xinetd:                                           [  OK  ]
      Starting xinetd:                                           [  OK  ]
    2. 验证 xinetd 进程是否链接到 SDP 库。如清单 10 所示。
      清单 10. xinetd 进程
      bash# lsof -p `pidof xinetd` | grep sdp
      xinetd  10090 root  mem  REG    8,5    69128 9339172  /usr/lib64/libsdp.so.1.0.0
    3. 现在,您可以从另一个配置了 SDP 的计算机连接到端口 7 上的 echo server,如清单 11 所示。
      清单 11. Echo 服务器连接
       bash# LD_PRELOAD=/usr/lib64/libsdp.so telnet 10.7.7.1 7
       Trying 10.7.7.1...
       Connected to 10.7.7.1.
       Escape character is '^]'.
       test sdp
       test sdp
    4. 此时,telnet 客户端被连接到 echo server,输入到 telnet 的任何行都将由 echo server 返回。活动的 SDP 连接可使用 sdpnetstat 命令列出,该命令类似于标准的 Linux netstat。如清单 12 所示。
      清单 12. 活动的 SDP 连接命令
       bash# sdpnetstat -Sn
       Active Internet connections (w/o servers)
       Proto Recv-Q Send-Q Local Address           Foreign Address        State      
       sdp        0      0 10.7.7.2:41771          10.7.7.1:7             ESTABLISHED

      注意,SDP 连接不能通过标准的 netstat 命令显示。


SDP 上的 DB2 客户端-服务器

启用 SDP for DB2 所需的步骤类似于 echo 服务器示例。确保 SDP 库在 /etc/ld.so.preload 中列出,然后重启 DB2 实例。 DB2 服务器不能通过设置或导出环境变量 LD_PRELOAD 启动,因为 DB2 由许多被分叉的进程构成,而且其中一些进程是作为 root 或 setuid root 运行的。因此,变量将不能传递给所有子进程。

  1. 以实例所有者的身份登录并重启实例,如清单 13 所示。
    清单 13. 重启 DB2 实例
    db2inst1$ db2stop 
    db2inst1$ db2start
  2. 要测试正在使用 SDP 的 DB2,使用一个简单命令 db2batch,该命令包含在 DB2 中。在 DB2 客户端机器上,以客户端实例所有者身份登录,并创建一个包含将用于基准测试的 SQL 语句的文件。清单 14 提供了一个样例文件。
    清单 14. 样例 update.sql 文件
     --#SET PERF_DETAIL 0
     create table demo (c1 bigint, c2 double, c3 varchar(8));
                    
     --#BGBLK 4000
     insert into demo values (-9223372036854775808, -0.000000000000005, 'demo');
     --#EOBLK
                    
     --#SET ROWS_OUT 0
     select * from demo;
                    
     drop table demo;

    在该示例中有 4 个语句。第一个语句创建一个表,该表将在语句 4 测试结束后删除。第二个语句是 INSERT,将执行 4000 次。第 3 个语句将选择表中的所有行(4000 行),但是不会将它们显示到 stdout 中。
  3. 要启动测试,在客户端机器上以客户端实例所有者身份运行该命令,如清单 15 所示。
    清单 15. 客户端实例
     db2inst1$ LD_PRELOAD=/usr/lib64/libsdp.so db2batch -d sample -f update.sql \
                    -a db2inst1/password -r result.txt,summary.txt

    db2batch 命令生成 2 个结果文件。result.txt 包含每个语句的详细度量,summary.txt 包含每个块的总时间和平均时间。
    尽管这是一个非常简单的测试,但是您可以看到 SDP 对性能的影响。使用 SDP,插入平均耗时 230 微秒,而 TCP 平均耗时 300 微秒。使用 SDP,SELECT 语句返回 4000 条记录耗时 4 毫秒,而 TCP 耗时 6 毫秒。这些测试是使用默认 SDP 设置 sdp_zcopy_thresh (64K) 和 recv_poll (700) 执行的。参阅 性能调优 部分,了解如何调优这些参数的详细信息。
  4. db2batch over SDP 摘要如清单 16 所示。
    清单 16. db2batch over SDP 摘要
    Type      Number      Repetitions Total Time (s) Min Time (s)   Max Time (s)
    --------- ----------- ----------- -------------- -------------- --------------
    Statement           1           1       0.115556       0.115556       0.115556
    Block               1        4000       0.924646       0.000200       0.001328
    Statement           3           1       0.004281       0.004281       0.004281
    Statement           4           1       0.133243       0.133243       0.133243
                    
    Type      Number      Repetitions Arithmetic Mean Geometric Mean
    --------- ----------- ----------- --------------- --------------
    Statement           1           1        0.115556       0.115556
    Block               1        4000        0.000231       0.000229
    Statement           3           1        0.004281       0.004281
    Statement           4           1        0.133243       0.133243
  5. db2batch over TCP 摘要如清单 17 所示。
    清单 17. db2batch over TCP 摘要
    Type      Number      Repetitions Total Time (s) Min Time (s)   Max Time (s)   
    --------- ----------- ----------- -------------- -------------- --------------
    Statement           1           1       0.115521       0.115521       0.115521
    Block               1        4000       1.445863       0.000326       0.001034
    Statement           3           1       0.006005       0.006005       0.006005
    Statement           4           1       0.137436       0.137436       0.137436
                    
    Type      Number      Repetitions Arithmetic Mean Geometric Mean
    --------- ----------- ----------- --------------- --------------
    Statement           1           1        0.115521       0.115521
    Block               1        4000        0.000361       0.000360
    Statement           3           1        0.006005       0.006005
    Statement           4           1        0.137436       0.137436
  6. 图 1图 2 中以图形化方式显示了 SDP 和 TCP 之间的比较。
    图 1. 每个 INSERT 的平均时间
    INSERT 语句平均时间,SDP vs. TCP
    图 2. 4000 个 INSERT 块的总时间
    4000 个 INSERT 语句的测试时间,SDP vs. TCP

高级 SDP 配置

默认情况下,SDP 库被配置为首先使用 SDP,如果 SDP 连接失败,则尝试使用 TCP。附加规则可在 /etc/libsdp.conf 中定义。
该文件格式是 <address-family> <role> <program name> <address|*>:<port range|*>

默认值在清单 18 中定义。

清单 18. 默认值
use both server * *:* 
use both client * *:*
  • both 关键词意味着如果尝试 TCP 失败,尝试 SDP
  • server 规则适用于侦听一个套接字的应用程序。
  • client 规则适用于启动一个连接的应用程序。
  • <program name> 指定该规则采用的进程名。
  • <address:port> 与本地 IP 和服务器侦听 server 规则的端口相匹配。
  • <address:port> 与远程 IP 和客户端试图连接的端口相匹配。

与应用程序匹配的第一个规则将被应用,其余规则则忽略。

例如,当连接一个 DB2 服务器并使用 TCP 连接 LDAP 服务器时,这些规则将 Java 进程切换到 SDP,如清单 19 所示。

清单 19. DB2 的 SDP 连接、LDAP 的 TCP 连接
use sdp client java 192.168.100.10:50000
use tcp client java *:389

这些规则配置一个 DB2 服务器仅接受一个接口上的 SDP 连接,以及另一个服务器上的 TCP 连接,如清单 20 所示。

清单 20. 接受 SDP 和 TCP 连接的服务器
use sdp server db2* 192.168.100.10:50000
 use tcp server db2* 192.168.200.10:50000

清单 21 中的规则配置 SDP 库以同时接受 SDP 和 TCP 连接,SDP 作为首选。

清单 21. 配置 SDP 库的规则
 use both server * 192.168.100.10:50000

性能调优

sdp_zcopy_threshrecv_poll 参数对于 SDP 性能调优是非常重要的,必须根据每个特定工作负载和流量模式进行设置。

零拷贝阈值

SDP 可以通过两种模式拷贝数据包:使用零拷贝(绕过内核,用户缓存直接从用户内存传送),或者缓存拷贝(用户缓存首先拷贝到内核空间)。

ZCopy 对于较大的消息更为有效,而 Bcopy 只一些大小为 KBytes 的消息比较有效。

sdp_zcopy_thresh 参数指定将要使用哪种方法。默认情况下,小于 64 KB 的消息使用 Bcopy 传递,大于 64 KB 的消息使用 Zcopy 传递,如清单 22 所示。

清单 22. sdp_zcopy_thresh 参数
bash# cat /sys/module/ib_sdp/parameters/sdp_zcopy_thresh 
65536

要修改该阈值,在 sys 文件系统中写入一个不同值,如清单 23 所示。

清单 23. sys 文件系统
bash# echo 32768 > /sys/module/ib_sdp/parameters/sdp_zcopy_thresh

用一个 0 值来完全禁用 Zcopy,强制所有消息大小使用 Bcopy。

也可以在 modprobe.conf 中对该参数进行设置,如清单 24 所示。

清单 24. modprobe.conf
 options ib_sdp sdp_zcopy_thresh=32768

最小阈值等于内存页面大小。使用 getconf PAGE_SIZE 显示系统的页面大小。

接收轮询计时器

recv_poll 参数指定接收器轮询输入数据的时间,默认值是 700 微秒,如清单 25 所示。

清单 25. 接收轮询计时器
 bash# cat /sys/module/ib_sdp/parameters/recv_poll
 700

该轮询可以通过将 procfs 参数 recv_poll 设置为零来禁用,如清单 26 所示。与非零值相反,这的 CPU 密集程度更小。但是,使用 recv_poll=0 的消息延迟则比较高。

清单 26. 使用 recv_poll=0
 bash# echo 0 > /sys/module/ib_sdp/parameters/recv_poll

将其添加到 modprobe.conf 中,重启后将被持久化,如清单 27 所示。

清单 27. modprobe.conf
 options ib_sdp recv_poll=0

SDP 调试

  • 使用 sdpnetstat 列出 SDP 连接,类似于 netstat,但是 netstat 不能显示 SDP 连接,如清单 28 所示。
    清单 28. 使用 sdpnetstat
    bash# sdpnetstat -Sn
    Active Internet connections (w/o servers)
    Proto Recv-Q Send-Q Local Address        Foreign Address      State
    sdp     0       0   192.168.100.10:4432  192.168.100.11:7     ESTABLISHED
    sdp     0       0   192.168.100.11:7     192.168.100.10:4432  ESTABLISHED
  • SDP 有两个组件,称为内核模块和用户库。它们都可以在调试模式中进行设置,如清单 29 所示。
    • 用户空间调试模式由 libsdp.conf 控制。
      清单 29. 调试的等级在 libsdp.conf 中进行了描述
      log min-level 9 destination file libsdp.log
    • Kernel-mode 调试模式可在 procfs 中启用,如清单 30 所示。
      清单 30. Kernel-mode 调试
      bash# echo 1 > /sys/module/ib_sdp/debug_level

      Kernel-mode 调试模式也可在 modprobe.conf 中启用,如清单 31 所示。

      清单 31. modprob.conf 中的 Kernel-mode 调试
      options ib_sdp sdp_debug_level=1

结束语

本文介绍了如何使 Remote Direct Memory Access (RDMA) 协议比 TCP 更高效,并提供了一个经济高效的方法,使得可以在 DB2 客户端服务器环境启用 RDMA 功能,而不需要对现有应用程序进行重新编码或重新编译。本文也讨论了如何安装 Mellanox 驱动程序和工具、在内核和用户空间中启用 SDP,以及性能调优和 SDP 调试。

参考资料

学习

获得产品和技术

讨论

  • 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、讨论组和维基,并与其他 developerWorks 用户交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=839490
ArticleTitle=使用 Socket Direct Protocol 实现 DB2 的 RDMA 功能
publish-date=10082012