多节点通信配置实录

场景:测远端RDMA读SSD的带宽,使用InfiniBand网卡

RDMA prepare

RDMA在CPU-DRAM层面的连接是比较常规的,但是对于新手来说容易忽略一些事情,而且这种代码比较繁琐,也没什么所谓的逻辑性,通常是哪里细节之类的没处理好导致寄了

  1. 在RDMA连接之前,需要先TCP连接,交换彼此的GID/LID/QP等一众元数据,而且是需要双方都互相交换的
  2. 交换完元数据之后,两侧的RDMA程序都需要将自己的状态转为RTS(Ready to Send),顺序一般是INIT->RTR->RTS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
read(tcp_fd, &meta, sizeof(meta)); // meta is metadata.
write(tcp_fd, &client_meta, sizeof(client_meta));
...
memset(&attr, 0, sizeof(attr));
  attr.qp_state = IBV_QPS_RTS;
  attr.sq_psn = 0;
  attr.timeout = 14;
  attr.retry_cnt = 7;
  attr.rnr_retry = 7;
  attr.max_rd_atomic = 1;
  ret = ibv_modify_qp(qp, &attr,
                      IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT |
                          IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN |
                          IBV_QP_MAX_QP_RD_ATOMIC);

然后就能连成功了

连成功之后,需要将mmap的地址传给server.c的准备给client.c读的远端地址,这样就可以实现远端通过RDMA网卡读SSD了

双节点自动化脚本

由于RDMA实验需要两台服务器,所以自动化测试脚本需要能够让两个服务器一起启动起来

  1. 需要先将两台机器的public_key互相转给对面的authorized_key文件中,这样他们就可以通过公私钥配对的方式进行连接
  2. pythonparamiko库可以用来创建登录远端的ssh连接,注意和普通的ssh连接一样,会默认登录的时候处于/home/user这个目录中!所以建议通过这个自动化脚本执行的其他脚本写绝对路径
1
2
3
4
5
6
7
# create ssh_client object
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(remote_host, port=remote_port, username=remote_user, key_filename="/path/to/your/private/key")
# consult the command
command = "your command"
ssh_client.exec_command(command)
  1. server端脚本,主要是对脚本语言不熟每次都要查循环的语法
1
2
3
4
5
6
7
8
9
10
11
12
block_size=$((16 * 1024 * 1024))
file_size=$((4 * 1024 * 1024 * 1024))
min_block_size=$((4 * 1024))

while [ $block_size -ge $min_block_size ]; do
    echo "Testing with block size: $block_size"
    ./server &
    ./rdma_test.py -b $block_size -s $file_size
    sleep 22
    block_size=$((block_size / 2))
    file_size=$((file_size / 2))
done
  1. client端脚本,之前一直用什么awk指令,但是估计不太会用所以也没搞出来,后面用正则表达式,$1为脚本参数
1
2
3
4
5
6
output=$(/home/weiquan/RDMA-Tutorial/client $1 $2)

bandwidth=$(echo "$output" | sed -n 's/.*Bandwidth: \([0-9.]*\) MB\/s.*/\1/p')
latency=$(echo "$output" | sed -n 's/.*latency per block: \([0-9.]*\) us.*/\1/p')
iops=$(echo "$output" | sed -n 's/.*iops: \([0-9.]*\).*/\1/p')
echo "$2,$bandwidth,$latency,$iops" >> /path/to/your/csv
  1. python脚本传参的方式:argparse,具体使用方式见下:
1
2
3
4
5
6
7
8
9
def main():
    parser = argparse.ArgumentParser(description="SSH Key Management and Remote Program Execution")

    parser.add_argument("-b", "--block_size", type=int, default=2048, help="block size for RDMA")
    parser.add_argument("-s", "--size", type=int, default=1024, help="file size for RDMA")
    args = parser.parse_args()

    block_size = args.block_size
    size = args.size

然后就大功告成了,磨刀不误砍柴工~