Curve是网易数帆开源的新一代分布式存储系统,具有高性能、高可用、高可靠的特点,可作为多种存储场景的底层存储,包括块存储、对象存储、云原生数据库、EC等。
对于分布式块存储系统来说,IOPS是最重要的一个性能指标。从Curve目前的性能测试情况看,读IOPS瓶颈在Client端——对于6个存储节点的集群,单个Client节点读IOPS接近30万,两个Client节点读IOPS接近60万。而Curve的写IOPS还有一定提升空间——对于6个存储节点的集群,IOPS只能达到26万~28万,而ChunkServer节点CPU使用率接近100%,而底层SSD的使用率则不到90%。因此,随机写IOPS场景是Curve的一个优化重点。
在测试环境A 中部署Curve(具体配置见附录1),在Client节点创建10个卷,进行4KB随机写测试。结果显示,写IOPS约为13.5万,而此时ChunkServer节点的CPU使用率接近100%,而所有SSD的使用率平均不到85%。
这表明,ChunkServer端CPU成为性能瓶颈。考虑到目前测试环境的SSD配置较低,若使用高性能NVME SSD,其IOPS可能比现有SSD高一个数量级,届时CPU性能瓶颈将更为严重。因此,优化CPU性能,释放SSD的I/O能力,是Curve性能优化的一个重要方向。本文围绕Curve的CPU性能优化进行了一些探索和实践。
在进行CPU性能优化之前,我们必须进行性能测量,对CPU性能进行量化分析,从而有的放矢,针对性优化。
先回顾下CPU的基本工作原理:现代CPU都是多核心架构,软件需要以进程或线程的方式在CPU核心上运行。操作系统会将每个CPU核心的运行时间划分为毫秒级的时间片,然后通过调度算法为每个时间片选择一个就绪的线程执行。时间片结束或者运行的线程需要等待资源(I/O, 锁,条件变量等),操作系统就会进行上下文切换,将对应的CPU核心分配给另一个就绪的线程。
因此,我们可以从线程和CPU两种视角去测量CPU性能。
下文将从这两个角度,分别对Curve的CPU性能进行测量和优化。
线程级CPU性能分析可以从三个方面进行:
下面在测试环境B(见附录2)进行4KB随机写测试,然后分别从这三个方面对curve进行CPU性能分析实践。
软件配置如下:
代码版本:d29c4991 (略新于v1.1-beta)
chunkserver数量:每节点20个chunkserver
copyset数量:4000个(测试前已确保leader均衡,range <= 2)
用户卷数量:10个
用户卷大小:30GB
4k随机写IOPS:234k
使用vtune采集ChunkServer进程的threading数据:
vtune -c threading -target-pid=pidof curve-chunkserver | awk '{print $1}' -duration 50
结果显示:
小结:
对上述测试数据,使用vtune进行自下而上的CPU分析,其测量结果如下所示:
可以得到以下信息:
对于bthread CPU开销较大的问题,Curve团队从其它方面进行了测试优化,写IOPS最多可提升约20%,具体情况就不在这里展开讨论了。
对于bvar模块CPU开销过大的问题,我们进行了测试分析。在代码中去除braft、brpc模块中几个耗时较长的bvar操作语句后,IOPS从236k提升到246k,提升了4%。
可见bvar确实对性能产生了影响,但我们对bvar监控指标的预期是性能下降低于5%,这样的影响可以接受。因此,我们暂不对bvar部分进行优化改动,但会对bvar指标的使用进行规范,包括增加监控开关,去除多余的监控指标,及控制新指标的增加等。
因vtune多次测试未采集到线程wait time相关数据,我们使用brpc内置的contention profiler组件,分析花在等待锁上的时间及发生等待的函数[1]。
在测试环境A中(见附录1)进行随机写测试,同时打开brpc服务的web页面,点击contention选项卡,触发contention profiler。(为确保测试结果稳定,总测试时间被修改为30s)
测量结果如下所示:
在30秒的采集时间内,ChunkServer等待锁的总时间为0.442秒,比例很小。
其中,curve::common::TaskQueue::Push等待锁的时间占比**86.8%,**这也符合并发控制层的逻辑。
因此,ChunkServer进程在等待锁方面很正常,不需要关注。
本节主要介绍CPU微指令运行效率的测量方法。首先,简单介绍下CPU的微指令和流水线的概念。操作系统提交给CPU的指令,会被CPU分解为若干条微指令(uOp),并在内部以流水线的方式调度执行。一般来说,CPU 流水线在概念上分为两部分,即前端(Front-end)和后端(Back-end)。Front-end 负责获取程序代码指令,并将其解码为一个或多个称为微操作(uOps)的底层硬件指令,并发送到后端。Back-end 负责监控 uOp 的数据何时可用,并在可用的执行单元中执行 uOp。 uOp 执行的完成称为退役(Retirement),uOp 的执行结果提交并反馈到架构状态(CPU 寄存器或写回内存)。
我们可以用流水线槽(pipeline slot)代表处理一个 uOp 所需的硬件资源。在最近的英特尔微体系结构上,流水线的 Front-end 每个 CPU 周期可以分配4个 uOps ,而 Back-end 可以在每个周期中退役4个 uOps。在每个 CPU 周期中,pipeline slot 可以是空的或者被 uOp 填充。 如果在一个 CPU 周期内某个 pipeline slot 是空的,称之为一次停顿(stall)。如果 CPU 经常停顿,系统性能肯定是受到影响的,如下图所示(绿色圆圈表示该流水线槽有微指令运行,灰色圆圈表示没有):
由此可见,我们可以统计流水线槽的运行状态,以此衡量CPU微指令运行效率。
现代 CPU 大多具有性能监控单元(Performance Monitoring Unit, PMU),用于统计系统中发生的特定硬件事件,例如缓存未命中(Cache Miss)或者分支预测错误(Branch Misprediction)等。同时,多个事件可以结合计算出一些高级指标,例如每指令周期数(CPI),缓存命中率等。一个特定的微体系架构可以通过 PMU 提供数百个事件。对于发现和解决特定的性能问题,我们很难从这数百个事件中挑选出那些真正有用的事件。 这需要我们深入了解微体系架构的设计和 PMU 规范,才能从原始事件数据中获取有用的信息。
Intel公司提出了自顶向下的微体系架构分析方法(Top-Down Microarchitecture Analysis Method, TMAM),可以在乱序执行的内核中识别性能瓶颈。TMAM方法通过CPU内置的PMU数据,测量这些流水线槽的运行状态,从而确定cpu微指令运行效率的瓶颈,显示运行应用程序时 CPU 流水线的使用情况。(CPU微指令与TMAM相关背景内容主要摘自[2]和[3])
TMAM方法将CPU性能问题划分为4大类——FrontEnd Bound, BackEnd Bound,Retiring, Bad Speculation。每大类又可划分为1-3个层级的若干子类,我们只需利用相关工具按图索骥,即可一层层区分、细化cpu性能问题,直至最终确定影响最大的问题所在。最终目标是,将Retiring比例提升至最大。
这种自顶向下的分析框架的优点是一种结构化的方法,有选择地探索可能的性能瓶颈区域。 带有权重的层次化节点,使得我们能够将分析的重点放在确实重要的问题上,同时无视那些不重要的问题。例如,如果应用程序性能受到指令提取问题的严重影响, TMAM 将它分类为 Front-end Bound 这个大类。 用户或者工具可以向下探索并仅聚焦在 Front-end Bound 这个分类上,直到找到导致应用程序性能瓶颈的直接原因或一类原因。TMAM方法的具体问题分类及对应的优化方法可查询intel各cpu的优化指南(如Xeon E5 v3系列cpu的优化文档为[4])
Intel VTune Profiler是一款全面的性能测量分析软件[5],它可以从系统、线程、CPU微架构等多个角度测量和分析性能数据,其中CPU微架构部分就应用了TMAM方法。
在测试环境中,对curve进行4KB随机写,软件配置如下:
代码版本:d29c4991 (略新于v1.1-beta)
chunkserver数量:3个节点,每节点20个chunkserver
copyset数量:500个(测试前已确保leader均衡,range <= 2)
用户卷数量:10个
用户卷大小:30GB
4k随机写IOPS:129k
同时使用Intel VTune Profiler采集CPU微架构相关性能数据,结果如下图所示:
从上图中vtune的cpu微架构性能数据看,主要的cpu瓶颈在Frond-End Latency, 占比50.3%。参考intel的优化指南,可以实施的优化方法主要是编译优化,包括:
其中,PGO优化是指基于性能反馈的编译优化,它需要进行两轮编译[6]。第一轮编译完成后,会生成带profiler功能的可执行文件,将它部署到测试环境,按最常用的负载进行运行后,它会自动采集性能数据;然后将性能数据复制到编译环境中进行第二轮编译,即可得到优化后的可执行文件。
对curve分别应用这些优化方法,实测方法3相比默认的-O2优化,性能明显下降;而方法4的优化会导致编译失败,未能解决。因此,curve无法应用这两种优化。
实测单独进行-O3优化或PGO优化时,性能提升在-5%和5%之间,无提升。
最终结合-O3和PGO优化,及cpu指令集优化时,性能提升了7.7%(IOPS从129k提高到了139k)。
具体的编译优化选项为:
第一遍编译时gcc优化选项:
-O3 -march=core2 -mtune=haswell -fprofile-generate=/tmp/pgo
链接优化选项为-fprofile-generate=/tmp/pgo
第二遍编译时gcc优化选项:
-O3 -march=core2 -mtune=haswell -fprofile-use=/tmp/pgo -fprofile-correction
链接优化选项为-fprofile-use=/tmp/pgo
从vtune的微架构性能数据看,编译优化后cpu的pipeline slots的retiring比例从19.1%提升到了22.3%。
而Front-End Bound从58.7%降至47.3%,这证明编译优化确实缓解了Front-End Bound,提升了CPU执行效率。
本文从线程的CPU运行时间与锁等待时间,以及CPU微指令运行效率等多个角度,对Curve ChunkServer的CPU瓶颈问题进行了测量分析和优化实践,结果如下:
另外,Curve近期还有其它优化工作在进行,欢迎关注下一个版本v1.2,其性能会进一步显著提升。
client节点(1台)
双路Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz
256GB内存
双10Gb网卡bond
mds和chunkserver节点(3台)
双路Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz
256GB内存
双10Gb网卡bond
20个 SSD用于chunkserver服务(SATA3接口,型号分别为INTEL DC S3610和三星PM863a,标称写IOPS分别为27000和24000)
copyset总数量为500个
client节点(1台)
双路Intel(R) Xeon(R) CPU E5-2660 v4 @ 2.00GHz
256GB内存
双10Gb网卡bond
chunkserver节点(6台,其中3台部署了mds)
双路Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz
384GB内存
双10Gb网卡bond
20个 SSD用于chunkserver服务(SATA3接口,型号是INTEL DC S3610标称写IOPS为27000)
copyset总数量为500个
作者简介
秦亦,网易数帆资深服务端开发工程师,计算机系统结构博士,专注于分布式存储领域;曾参与华为FusionStorage分支项目,独立攻关天玑数据PhegData X数据存储云平台的后端存储引擎,现为Curve团队核心开发。
相关视频
Curve监控、运维与质量体系
[1] https://github.com/apache/incubator-brpc/blob/master/docs/cn/contention_profiler.md
[2] https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
[3] https://kernel.taobao.org/2019/03/Top-down-Microarchitecture-Analysis-Method/
[4] https://software.intel.com/sites/default/files/managed/48/7d/Using_Intel_VTune_Amplifier_XE_on_Xeon_E5v3_Family_1.0.pdf
[5] https://software.intel.com/content/www/cn/zh/develop/tools/vtune-profiler.html?elq_cid=6919108_ts1603694716651
[6] https://en.wikipedia.org/wiki/Profile-guided_optimization
Curve Roadmap:opencurve/curve
2020年12月16-17日,来自CNCF、VMware、PingCAP、网易数帆、阿里云等17位重磅演讲嘉宾,带来2天主题分享,立体化解析云原生前沿技术与实践。活动详情如图,名额有限,欢迎点击这里,或识别下图二维码报名。