Doris开发手记4:倍速性能提升,向量化导入的性能调优实践
最近居家中,对自己之前做的一些工作进行总结。正好有Doris社区的小伙伴吐槽向量化的导入性能表现并不是很理想,就借这个机会对之前开发的向量化导入的工作进行了性能调优,取得了不错的优化效果。借用本篇手记记录下一些性能优化的思路,抛砖引玉,希望大家多多参与到性能优化的工作总来。
1.看起来很慢的向量化导入
问题的发现
来自社区用户的吐槽:向量化导入太慢了啊,我测试了xx数据库,比Doris快不少啊。有招吗?
啊哈?慢这么多吗? 那我肯定得瞅一瞅了。
于是对用户case进行了复现,发现用户测试的是代码库里ClickBench的stream load,80个G左右的数据,向量化导入耗时得接近1200s,而非向量化导入耗时为1400s。
向量化 | 非向量化 |
---|---|
1230s | 1450s |
ClickBench是典型的大宽表的场景,并且为Duplicate Key的模型,原则上能充分发挥向量化导入的优势。所以看起来一定是有些问题的,需要按图索骥的来定位热点:
定位热点的技巧
笔者通常定位Doris代码的热点有这么几种方式,通过这些方式共同组合,能帮助我们快速定位到代码真正的瓶颈点:
Profile: Doris自身记录的耗时,利用Profile就能分析出大致代码部分的瓶颈点。缺点是不够灵活,很多时候需要手动编写代码,重新编译才能添加我们需要进行热点观察的代码。
FlameGraph: 一旦通过Profile分析到大概的热点位置,笔者通常会快速通读一遍代码,然后结合火焰图来定位到函数热点的位置,这样进行的优化通常就有的放矢了。关于火焰图的使用可以简要参考Doris的官方文档的开发者手册。
Perf: 火焰图只能大致定位到聚合函数的热点,而且编译器经过内联,汇编优化之后,单纯通过火焰图的函数级别就不一定够用了。通常需要进一步分析汇编代码的问题,这时则可以用开发手记2中提到的perf来定位汇编语言的热点。当然,perf并不是万能的,很多时候需要我们基于代码本身的熟稔和一些优化经验来进一步进行调优。
接下来我们就基于上述的调优思路,来一起分析一下这个问题。
2.优化与代码解析
基于火焰图,笔者梳理出在向量化导入时的几部分核心的热点。针对性的进行了问题分析与解决:
缓慢的Cast与字符串处理
在CSV导入到Doris的过程之中,需要经历一个文本数据解析,表达式CAST计算的过程。显然,这个工作从火焰图中观察出来,是CPU的耗损大户
上面的火焰图可以观察出来,这里有个很反常的函数调用耗时FunctionCast::prepare_remove_prepare,这里需要根据源码来进一步分析。
在进行cast过程之中需要完成null值拆分的工作,比如这里需要完成String Cast Int的操作流程如下图所示:
这里会利用原始的block,和待cast的列建立一个新的临时block来进行cast函数的计算。
上面标红的代码会对std::set进行大量的CPU计算工作,影响的向量化导入的性能。在导入表本身是大宽表的场景下,这个问题的严重性会进一步放大。
进行了问题定位之后,优化工作就显得很简单了。显然进行cast的时候,我们仅仅只需要进行cast计算的相关列,而并不需要整个block中所有的列都参与进来。所以笔者这里实现了一个新的函数 create_block_with_nested_columns_only_args
来替换create_block_with_nested_columns_impl
,原本对100列以上的计数问题,减少为对一个列进行处理,问题得到了显著的改善。
优化前 | 优化后 |
---|---|
1230s | 980s |
缺页中断的优化
解决了上面问题之后,继续来对火焰图进行分析,发现了在数据写入memtable
时,产生了下面的热点:缺页中断。
这里得先简单了解一下什么是缺页中断
:
如上图所示:CPU对数据进行计算时,会请求获取内存中的数据。而CPU层级看的内存地址是:Virtual Address
,需要经过特别的CPU结构MMU进行虚拟地址到物理地址的映射。而MMU会到TLB(Translation lookaside buffer,记住这个是个缓存),查找对应的虚拟地址到物理地址的映射。由于操作系统中,内存都是通过页进行管理的,地址都是基于页内存地址的偏移量,所以这个过程变成了查找起始页地址的一个工作。如果目标虚存空间中的内存页,在物理内存中没有对应的页映射,那么这种情况下,就产生了缺页中断(Page Fault)。
缺页中断显然会带来一些额外的开销:
- 用户态到内核态的切换
- 内核处理缺页错误
所以,频繁的出现缺页中断,对导入的性能产生了不利的影响,需要尝试解决它。
内存复用
这里大量的内存使用,取址都是对于Column进行操作导致的,所以得尝试从内存分配的源头来解决这个问题。
解决思路也很简单,既然缺页中断是内存没有映射引起的,那这里就尽量复用之前已经使用过的内存,这样,自然也不会引起缺页中断的问题了,对于TLB的缓存访问也有了更高的亲和度。
Doris内部本身支持了ChunkAlloctor
的类来进行内存分配,复用,绑核的逻辑,通过ChunkAlloctor
能大大提升内存申请的效率,对于当前case的缺页中断也能起到规避的效果:
通过替换podarray的内存分配的逻辑之后,效果也很符合预期,通过火焰图进行观察,缺页中断的占比大量的减少,性能上也获得了可观的收益。
优化前 | 优化后 |
---|---|
980s | 776s |
3.一些相关的优化的TODO:
CSV的数据格式解析:通过4kb的cache 来预取多行数据,利用并SIMD指令集来进一步性能优化
缺页中断的优化:部分内存分配拷贝过程之中的page fault的问题, 可以考虑引入大页内存机制来进一步进行缺页中断,页内存cache的优化
4.小结
当然,笔者进行的向量化导入工作只是Doris向量化导入中的一部分工作。很多社区的同学也深入参与了相关工作,在当前的基础上又有得到了更为理想的性能表现。总之,性能优化的工作是永无止境的.
这里也特别鸣谢社区的两位同学的code review和分析帮助:@xinyiZzz, @Gabriel
Bingo!请大家期待下一个1.2版本全面向量化的Doris,相信在性能和稳定性上,一定会带给各位惊喜。
最后,也希望大家多多支持Apache Doris,多多给Doris贡献代码,感恩~~
Doris开发手记4:倍速性能提升,向量化导入的性能调优实践的更多相关文章
- [转载]Java 应用性能调优实践
Java 应用性能调优实践 Java 应用性能优化是一个老生常谈的话题,笔者根据个人经验,将 Java 性能优化分为 4 个层级:应用层.数据库层.框架层.JVM 层.通过介绍 Java 性能诊断工具 ...
- 软件性能测试分析与调优实践之路-Web中间件的性能分析与调优总结
本文主要阐述软件性能测试中的一些调优思想和技术,节选自作者新书<软件性能测试分析与调优实践之路>部分章节归纳. 在国内互联网公司中,Web中间件用的最多的就是Apache和Nginx这两款 ...
- 软件性能测试分析与调优实践之路-Java应用程序的性能分析与调优-手稿节选
Java编程语言自从诞生起,就成为了一门非常流行的编程语言,覆盖了互联网.安卓应用.后端应用.大数据等很多技术领域,因此Java应用程序的性能分析和调优也是一门非常重要的课题.Java应用程序的性能直 ...
- elasticsearch5.3.0 bulk index 性能调优实践
elasticsearch5.3.0 bulk index 性能调优实践 通俗易懂
- JVM性能调优实践——JVM篇
前言 在遇到实际性能问题时,除了关注系统性能指标.还要结合应用程序的系统的日志.堆栈信息.GClog.threaddump等数据进行问题分析和定位.关于性能指标分析可以参考前一篇JVM性能调优实践-- ...
- 软件性能测试分析与调优实践之路-JMeter对RPC服务的性能压测分析与调优-手稿节选
一.JMeter 如何通过自定义Sample来压测RPC服务 RPC(Remote Procedure Call)俗称远程过程调用,是常用的一种高效的服务调用方式,也是性能压测时经常遇到的一种服务调用 ...
- MySQL数据库的性能分析 ---图书《软件性能测试分析与调优实践之路》-手稿节选
1 .MySQL数据库的性能监控 1.1.如何查看MySQL数据库的连接数 连接数是指用户已经创建多少个连接,也就是MySQL中通过执行 SHOW PROCESSLIST命令输出结果中运行着的线程 ...
- Doris开发手记2:用SIMD指令优化存储层的热点代码
最近一直在进行Doris的向量化计算引擎的开发工作,在进行CPU热点排查时,发现了存储层上出现的CPU热点问题.于是尝试通过SIMD的指令优化了这部分的CPU热点代码,取得了较好的性能优化效果.借用本 ...
- Java 应用性能调优实践
Java 应用性能优化是一个老生常谈的话题,笔者根据个人经验,将 Java 性能优化分为 4 个层级:应用层.数据库层.框架层.JVM 层.通过介绍 Java 性能诊断工具和思路,给出搜狗商业平台的性 ...
随机推荐
- 点击>>>解锁Apache Hadoop Meetup 2021!
" 10月16日,属于开源发烧友的狂欢日来啦! Apache Hadoop Meetup 2021 开源大数据行业交流盛会盛大开启!让我们相约北京,一起嗨翻初秋~ 在当今信息化时代,逐渐成熟 ...
- 【深入学习.Net】.泛型集合【体检管理系统】
基于泛型List的体检管理系统(蜗牛爬坡) 第五章[体检管理系统] 一.项目展示图(基于.net core6.0) 二.首先准备两个Model类 HealthCheckItem(项目类):Name(项 ...
- 多环境配置 - SpringBoot 2.7.2 实战基础
优雅哥 SpringBoot 2.7.2 实战基础 - 06 -多环境配置 在一个项目的开发过程中,通常伴随着多套环境:本地环境 local.开发环境 dev.集成测试环境 test.用户接受测试环境 ...
- 巨细靡遗流程控制,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang流程结构详解EP09
流程结构就是指程序逻辑到底怎么执行,进而言之,程序执行逻辑的顺序.众所周知,程序整体都是自上由下执行的,但有的时候,又不仅仅是从上往下执行那么简单,大体上,Go lang程序的流程控制结构一共有三种: ...
- vue项目打包后使用reverse-sourcemap反编译到源码(详解版)
首先得说一下,vue项目中productionSourceMap这个属性.该属性对应的值为true|false. 当productionSourceMap: true,时: 1.打包后能看到xxx ...
- LeetCode 593. 有效的正方形(向量做法)
题目 题目链接:593. 有效的正方形 题意:给出二维平面上四个点的坐标,判断这四个点是否能构成一个正方形,四个点的输入顺序不做任何保证. 思路 通过向量运算可以很轻松地解决这道题.任取一点向其他三点 ...
- Dreamweaver8 网站制作软件使用教程
Dreamweaver是我喜欢做网站的软件.之所以喜欢Dreamweaver 8 是因为这个版本有折叠功能. 下面说说它的使用方法. 1.创建站点文件.注意看截图的顺序,如下图 2.选择你喜欢的编辑模 ...
- ARC122D XOR Game(博弈论?字典树,贪心)
题面 ARC122D XOR Game 黑板上有 2 N 2N 2N 个数,第 i i i 个数为 A i A_i Ai. O I D \rm OID OID(OneInDark) 和 H I D ...
- 【Java】学习路径48-线程锁ReentrantLock
与上一章学习的线程锁synchronized类似,都是为了解决线程安全的问题. 使用方法: 新建一个ReentrantLock对象.(如果使用Thread多线程,则需要声明static静态) 然后在需 ...
- Python 爬取网站数据
一.使用request库实现批量下载HTML 二.使用BeautifulSoup库实现html解析 官网:https://beautifulsoup.readthedocs.io/zh_CN/v4.4 ...