分布式存储性能调优 - sysbench内存带宽测试详解

注:本文内容引用自张洋老师的知乎文章 https://zhuanlan.zhihu.com/p/689586190,他是一位存储研发专家。

测试目的

numa架构下,在固定数量的CPU核(10物理核,20逻辑核)的情况下,访问本地、远程以及混合内存的内存带宽表现。以及观察在不同的测试模式:顺序/随机、读/写情况下的内存带宽差异情况。从而由这些测试数据指导性能调优以及编写性能友好的代码。(如果不了解numa架构的基本知识,可以先查阅大致了解一下。)

image.png

测试工具介绍

sysbench

本文的实验均采用sysbench memory子命令用于内存带宽测试。下面是一段介绍sysbench内存测试的资料:

image.png

sysbench memory子命令用于测试内存性能,包括时延和带宽数据,本文只关注带宽数据。sysbench memory有6个可以配置的参数:

--memory-block-size=SIZE, 指定分配的buffer大小,不要分配得太小,否则会出现数据全从CPU缓存命中,达不到测试内存带宽的目的。本文测试用例中每个sysbench进程都设置为1GB。

--memory-total-size=SIZE,指定总共要测试多少数据量,例如100GB,那么便会循环操作--memory-block-size(例如1G)100次。每次操作以8字节对1GB buffer进行读写,直到1GB读写完毕。

--memory-scope=STRING,指定访问本地内存还是全局内存。本文的测试中使用numactl控制了内存访问范围,所以这个参数可以直接忽略。

--memory-hugetlb[=on|off],是否从分配大页内存。本文的测试中设置为on。

--memory-oper=STRING,指定read/wirte操作,默认是write。

--memory-access-mode=STRING,指定seq/rnd,即顺序或随机,默认是seq。

pcm

pcm是intel提供的分析intel cpu性能指标数据的工具,本文主要用于监控内存带宽和UPI带宽数据。

硬件配置

CPU

Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz 32逻辑核。

有两个这样的CPU,numa0上一个,numa1上一个。

内存

16GB 3200MT/s DDR4,numa0上6根,numa1上6根。

标称速率:Speed: 3200 MT/s 实际速率:Configured Memory Speed: 2666 MT/s

单根内存带宽理论上达到 3200MT/s(25GB/s),而实际的传输速度上限为2666 MT/s(20.8GB/s)。

UPI(NUMA间通信连接)

Socket 0

Max UPI link 0 speed: 23.3 GBytes/second (10.4 GT/second)

Max UPI link 1 speed: 23.3 GBytes/second (10.4 GT/second)

Socket 1

Max UPI link 0 speed: 23.3 GBytes/second (10.4 GT/second)

Max UPI link 1 speed: 23.3 GBytes/second (10.4 GT/second)

从这个配置来看,numa间有两条通信连接,每条提供23.3GB/s的带宽,两条连接合计46.6GB/s带宽。相比每个numa node上6根内存条的带宽,跨numa访问内存的带宽明显是瓶颈。

测试方法介绍

本文分为3个部分进行测试,包括本地内存带宽测试、远程内存带宽测试和混合内存带宽测试。其中每个部分分别测试4个测试用例:顺序写、随机写、顺序读、随机读。记录测试时的sysbench带宽结果和pcm显示的实际内存带宽结果,以及远程内存访问产生的UPI带宽信息。

本地内存带宽测试。在numa node0上同时启动20个sysbench进程,将这20个进程限定到numa node0上的20个逻辑核上(归属于10个物理核)。由操作系统调度每个sysbench在这20个逻辑核中的哪个上面运行。然后每个sysbench进程从numa node0上分配1GB大页内存用于测试,使用大页内存是因为可以排除TLB miss对测试结果的影响。

远程内存带宽测试。与“本地内存带宽测试”测试不同的是,sysbench进程从numa node1上分配1GB内存,而不是从本地numa mode0上分配。

混合内存带宽测试。将20个进程,其中10个的内存从本地numa node0上分配,另外10个从远程numa node1上分配,其余配置保持不变。

测试结果总览

image.png

测试结果解读

S0: 表示socket0(numa node0)通过两条UPI连接发送出去的带宽,这里包括数据和非数据。即除了传输数据需要占用UPI带宽,CPU还有其他一些额外的带宽占用。另外表格中没有记录接收到的数据量,是因为接收带宽小于发送带宽,不是瓶颈。另外需要注意的是UPI连接是双工的,每条UPI连接发送和接收分别有23.3GB/s的带宽。

S1:表示socket1(即numa node1)通过两条UPI连接发送出去的带宽,这里包括数据和非数据。

W: 表示写带宽。

R: 表示读带宽。

SYSBENCH带宽:指的是20个sysbench测试进程显示的带宽结果求和。

PCM NODE0带宽:指得是pcm工具监控到的numa node0的多个通道的内存带宽汇总结果。

PCM NODE1带宽:指得是pcm工具监控到的numa node1的多个通道的内存带宽汇总结果。

PCM UPI利用率:指的是pcm工具监控到的numa节点之间的通信带宽利用率。

混合模式下,SYSBENCH带宽由本地带宽+远程带宽组成。

随机读写测试用例,SYSBENCH带宽和PCM带宽差距较大,是因为sysbench访问大小为8字节,而CPU缓存加载的内存大小至少是cache line(64B)大小,所以有较大的带宽浪费现象。

经验和总结

以下为本次测试得到的一些经验,仅供参考,可能换个硬件环境就不适用了。

1、写内存时,需要先将内存按照cache line读取到CPU缓存,所以写内存会伴随着读内存。

2、PCM带宽来讲,随机写比顺序写性能差,大概差个20%左右。

3、顺序读带宽明显利用率更高,带宽浪费也更少,约%6。

4、PCM带宽来讲,随机读相比顺序读要差50%左右。

5、远程写带宽利用率较低,且内存带宽写入的数据量有2倍的放大。

6、远程顺序读,达到了UPI的瓶颈。

7、混合顺序写和随机写,sysbench总的带宽表现更佳,特别是顺序写带宽提升20%。

8、混合顺序读sysbench带宽表现还不如本地,原因是UPI带宽限制。

9、混合随机读sysbench带宽表现也不如本地,原因未知,也许是因为测试进程数不够多。

10、随机读写情况下,由于未对齐到cache line操作内存,导致非常大的内存带宽浪费。

以下为详细测试数据

本地内存带宽测试

顺序写

从测试结果来看,对内存进行写操作测试,会有一半带宽用于读。这是因为在写内存的时候,会先对应读取数据到CPU缓存。20个进程同时压测,达到了内存带宽的66%。

#!/bin/bash

# 启动20个后台进程

for i in {1..20}

do numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_write_local.sh | grep transferred

image.png

./pcm-memory 10

image.png

随机写

随机写的带宽表现明显比顺序写要更差,只达到了内存带宽的56%。且由于未对齐到cache line的写操作,带宽利用率很低,sysbench带宽结果为4.2GB/s, PCM写带宽为34.9GB/s,仅为12%。

#!/bin/bash

# 启动20个后台进程

for i in {1..20}

do

numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_randwrite_local.sh | grep transferred

image.png

./pcm-memory 10

image.png

顺序读

顺序读的带宽利用效率明显要高很多,达到了76%。不过对比sysbench的带宽和PCM的带宽,仍然有6%左右的浪费。

#!/bin/bash

#启动20个后台进程

for i in {1..20}

do

numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_read_local.sh | grep transferred

image.png

./pcm-memory 10

image.png

随机读

随机读的内存带宽利用率仅为34%,相比顺序读为76%,差距很大。同样的因为未对齐到cache line来读取,所以带宽浪费也非常严重。PCM带宽42.1GB/s,然而sysbench仅为5.0GB/s。

#!/bin/bash

# 启动20个后台进程

for i in {1..20}

do

numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_randread_local.sh | grep transferred

image.png

./pcm-memory 10

image.png

远程内存带宽测试

顺序写

相比于本地顺序写sysbench带宽为42.2GB/s,远程顺序写仅为26.5GB/s,可见有明显的差距。另外远程顺序写还表现在PCM写带宽占用比例增加,本地顺序写和读的比例关系为1.17, 而远程写和读的比例达到2.0。所以远程顺序写不仅仅体现在延迟增加,而且会浪费更多的内存写带宽,这是需要注意的。最后UPI带宽占用达到87%,接近达到瓶颈。

#!/bin/bash

# 启动20个后台进程

for i in {1..20}

do

numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_write_remote.sh | grep transferred

image.png

./pcm-memory 10

image.png
image.png

随机写

远程随机写,除了有远程顺序写的问题以及cache line对齐的问题之外,PCM内存带宽的利用率相比顺序写也要更低一些,约为86%。

#!/bin/bash

# 启动20个后台进程

for i in {1..20}

do

numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_randwrite_remote.sh | grep transferred

image.png

./pcm-memory 10

image.png

image.png

顺序读

远程顺序读,相比本地读差距很大。主要原因是因为UPI带宽达到91%,基本到达了瓶颈。所以远程顺序读带宽的瓶颈在于UPI带宽。

#!/bin/bash

# 启动20个后台进程

for i in {1..20}

do

numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_read_remote.sh | grep transferred

image.png

./pcm-memory 10

image.png

image.png

随机读

与远程顺序读相比,远程随机读的UPI带宽利用率达到78%,还未达到瓶颈。但是PCM带宽相比顺序读也更低,说明随机读内存的性能确实会更差,本地顺序读也有类似随机比顺序PCM带宽更差的表现。

#!/bin/bash

# 启动20个后台进程

for i in {1..20}

do

numactl -C 0,32,4,36,8,40,12,44,16,48,20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_randread_remote.sh | grep transferred

image.png

./pcm-memory 10

image.png

image.png

混合内存带宽测试

顺序写

混合顺序写模式下,sysbench本地得到31.1GB/s的带宽,远程得到20.3GB/s的带宽,而本地顺序写只有42.2GB/s的带宽。整体上来讲,从sysbench角度来看,获得了更大的带宽。本地部分的测试与前面讲的本地测试一致,同样远程测试部分与前面讲的远程测试情况一致。

#!/bin/bash

# 启动10个后台进程, 访问本地内存。

for i in {1..10}

do

numactl -C 0,32,4,36,8,40,12,44,16,48 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 启动10个后台进程, 访问远程内存。

for i in {1..10}

do

numactl -C 20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_write_mix.sh | grep transferred

image.png

./pcm-memory 10

image.png

image.png

随机写

随机写和顺序写有类似的现象,可以参考。

#!/bin/bash

# 启动10个后台进程, 访问本地内存。

for i in {1..10}

do

numactl -C 0,32,4,36,8,40,12,44,16,48 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 启动10个后台进程, 访问远程内存。

for i in {1..10}

do

numactl -C 20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_randwrite_mix.sh | grep transferred

image.png

./pcm-memory 10

image.png

image.png

顺序读

混合顺序读sysbench带宽为88.2GB/s,还不如直接本地顺序读的带宽89.8GB/s,是因为达到了UPI的利用率达到了89%,接近瓶颈导致。

#!/bin/bash

# 启动10个后台进程, 访问本地内存。

for i in {1..10}

do

numactl -C 0,32,4,36,8,40,12,44,16,48 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 启动10个后台进程, 访问远程内存。

for i in {1..10}

do

numactl -C 20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_read_mix.sh | grep transferred

image.png

./pcm-memory 10

image.png

随机读

混合随机读同样的,sysbench带宽表现还不如本地顺序读。这里有两个因素,随机读性能本来就更差,另外还可能是测试使用的进程数(20个)不足以利用内存带宽。(待验证)

#!/bin/bash

# 启动10个后台进程, 访问本地内存。

for i in {1..10}

do

numactl -C 0,32,4,36,8,40,12,44,16,48 --membind=0 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 启动10个后台进程, 访问远程内存。

for i in {1..10}

do

numactl -C 20,52,24,56,28,60,2,34,6,38 --membind=1 \

sysbench memory --time=30 --threads=1 \

--memory-oper=read \

--memory-access-mode=rnd \

--memory-hugetlb=on \

--memory-block-size=1G \

--memory-total-size=4000G run &

done

# 等待所有后台进程结束

wait

./run_sysbench_randread_mix.sh | grep transferred

image.png

./pcm-memory 10

image.png

image.png

作者:张洋
原文:企业存储技术

推荐阅读

欢迎关注企业存储技术极术专栏,欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
5557
内容数
237
关注存储、服务器、图形工作站、AI硬件等方面技术。WeChat:490834312
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息