分布式存储性能调优 - sysbench内存带宽测试详解
注:本文内容引用自张洋老师的知乎文章 https://zhuanlan.zhihu.com/p/689586190,他是一位存储研发专家。
测试目的
numa架构下,在固定数量的CPU核(10物理核,20逻辑核)的情况下,访问本地、远程以及混合内存的内存带宽表现。以及观察在不同的测试模式:顺序/随机、读/写情况下的内存带宽差异情况。从而由这些测试数据指导性能调优以及编写性能友好的代码。(如果不了解numa架构的基本知识,可以先查阅大致了解一下。)
测试工具介绍
sysbench
本文的实验均采用sysbench memory子命令用于内存带宽测试。下面是一段介绍sysbench内存测试的资料:
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上分配,其余配置保持不变。
测试结果总览
测试结果解读
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
./pcm-memory 10
随机写
随机写的带宽表现明显比顺序写要更差,只达到了内存带宽的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
./pcm-memory 10
顺序读
顺序读的带宽利用效率明显要高很多,达到了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
./pcm-memory 10
随机读
随机读的内存带宽利用率仅为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
./pcm-memory 10
远程内存带宽测试
顺序写
相比于本地顺序写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
./pcm-memory 10
随机写
远程随机写,除了有远程顺序写的问题以及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
./pcm-memory 10
顺序读
远程顺序读,相比本地读差距很大。主要原因是因为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
./pcm-memory 10
随机读
与远程顺序读相比,远程随机读的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
./pcm-memory 10
混合内存带宽测试
顺序写
混合顺序写模式下,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
./pcm-memory 10
随机写
随机写和顺序写有类似的现象,可以参考。
#!/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
./pcm-memory 10
顺序读
混合顺序读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
./pcm-memory 10
随机读
混合随机读同样的,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
./pcm-memory 10
作者
云和恩墨 zStorage分布式存储系统 性能架构师 张洋
扩展阅读:《企业存储技术》文章分类索引(微信公众号专辑)》
注:本文只代表作者个人观点,与任何组织机构无关,如有错误和不足之处欢迎在留言中批评指正。进一步交流可加微信:490834312。如果您想在这个公众号上分享自己的技术干货,也欢迎联系我:)
感谢您的阅读和支持!《企业存储技术》微信公众号:HL_Storage
长按二维码可直接识别关注
历史文章汇总:http://www.toutiao.com/c/user/5821930387/
http://www.zhihu.com/column/huangliang