Codegen技术学习

Codegen在spark中的应用

除了前面查询优化中讲到逻辑优化器之外,Spark在1.5版本中引入了比较大的一个动作就是DataFrame执行后端的优化,引入了codegen技术。(Tungsten项目的一部分)

从上图中可以看除,spark通过Codegen在运行前将逻辑计划生成对应的机器执行代码,由Tungsten backend执行。

原理

从上图中可以看除,spark通过Codegen在运行前将逻辑计划生成对应的机器执行代码,由Tungsten backend执行。

以spark为代表的基于内存的计算引擎,使得I/O性能比传统基于硬盘有10倍左右的性能提升,但与之同时,CPU的瓶颈会更明显,以传统Postgres的引擎为例,操作数据都被缓存到内存的Page Cache上面,它做最简单的Count(*)统计都只能勉强达到每秒钟400万行左右,而真实所需要的操作其实是很少的,按照2010年的X86 CPU而言,其实处理这些计算是非常简单的,但实际性能还是很低,为什么呢?先看看现在X86 CPU性能特征,随着技术本身的发展,X86 CPU本身的处理能力非常强大,但是一切换Context就会出现性能方面的小滑坡。如果等待处理的命令和数据没有被预缓存在Cache上面,而是需要访问的内存的话,会有一个更大的性能滑坡。既然大家都了解CPU本身的瓶颈,下面来聊聊传统数据库处理引引擎的短板有哪些?主要有以下四点:

其一是条件逻辑冗余,数据处理引擎代码非常繁琐,因为SQL语句本身非常复杂,所以数据引擎为了支持那些复杂的SQL语句,使得数据处理引擎需要复杂的条件逻辑来处理,甚至一个Switch循环里面会有成百上千的case这样的选择逻辑,虽然Switch循环本身会被编译器进行一定程度的优化,但是最终机器码中的分支指令会一定程度上阻止指令的管道化(instruction pipelining)和并行执行(instruction-levelparallelism)。

其二是虚函数的调用,和第一个问题的原因类似,因为数据处理引擎要支持极为复杂的SQL语句,还有十几种的数据类型,比如,程序在处理add这个逻辑的时候,此时数据处理引擎需要根据来源数据是INT还是BIGINT来选择不同的函数来处理,所以在实际处理时,肯定只能用虚函数来转给具体的执行函数,这个对CPU的影响肯定是非常明显的,因为很多时候虚函数调用本身的运行成本,比这个函数本身执行成本更高。更因为如此,内联函数这个最常见的性能优化方式也无法被使用。

其三是需要不断地从内存中调用数据,而无法一次性将数据从内存加载至Cache上,比如,常见的For循环,虽然知道下一个数据就在下一个偏移地址,但还是要从内存上面读取,这样读取开销很大而且阻止整个CPU管道化的操作。

其四是因为不同x86CPU年代不同,所以支持不同扩展指令集,而这些新的指令集对很多操作都能提升100%以上的性能,比如,有些比较新的CPU支持SSE 4.2,而有些却不支持,为了保证数据引擎能跨不同的硬件平台,所以数据引擎很少支持一些扩展的指令集,这导致浪费了本来可以提升的性能没有得到支持。

为了接上述瓶颈,Google研发的Tenzing技术里面提出基于LLVM编译框架实现动态生成代码Codegen这个技术,并且通过这个技术基于MapReduce分布式框架下面的类SQL系统的性能也能接近商业收费并行数据库的水准。Codegen这种方式,就是在SQL执行前才编译具体的执行代码。那么使用Codegen的好处如下:

其一是简化了条件分支,因为在生成代码的时候,程序已经获知运行时的信息,通过展开for循环(因为我们已经知道循环次数)和解析数据类型,所以可以将if/switch这些分支指令这样的语句就能优化掉,这是非常简单有效的。

其二是内存加载,我们可以使用代码生成来替代数据加载,这样极大减少内存的读取,增加CPU Cache的利用率,这对CPU性能而言非常有帮助。

其三是内联虚函数的调用,因此当对象实例的类型在运行时可知,可以使用代码生成来取代虚函数的调用,并做内联化,这样表达式可以无需函数调用而直接求值。此外,内联后的函数使编译器做进一步的优化,例如子表达式消除等。

其四是能利用最新的指令集,在Codegen的时候,由于Codegen本身是在即将执行的那个节点执行,所以它很方便就能感知到其底层CPU到底支持那个版本最新的指令集,比如是SSE 4.2还是SSE4.1,所以Codegen完全会根据具体的指令集支持来编译具体的执行代码,使其能尽可能地利用最新的指令集。

应用场景

Codegen技术使解析语言的性能接近预编译语言,而且兼容多种语言。可以看出来服务器端编程未来语言会越来越不重要,表达力越强,越容易使用的语言越受欢迎。

原文发布于微信公众号 - 大数据和云计算技术(jiezhu2007)

原文发表时间:2016-07-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏魏琼东

DotNET企业架构应用实践-数据库表记录的唯一性设计的设计兼议主键设定原则

简要介绍          在我们进行数据库设计的时候,大家都会考虑到数据表主键的设计,而可能没有人去关注记录唯一性字段设计,或者说,很多开发人员把这两种混合在...

1735
来自专栏蓝天

linux的free命令详解-内存是拿来用的不是拿来看的

我告诉有朋友我一直用linux.他问我了一下我为什么linux使用的内存这么高.他讲他1G的内在free才232M.讲win xp才用200M的样子.

581
来自专栏小怪聊职场

MySQL(五)|《千万级大数据查询优化》第二篇:查询性能优化(1)

2558
来自专栏机器学习从入门到成神

2013百度校招笔试真题以及解析(内存管理及其优缺点总结)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

501
来自专栏杨建荣的学习笔记

数据库收缩数据文件的尝试(三)(r11笔记第22天)

不知道大家在数据库运维中是否会有这样的困扰,一个数据文件里没有多少数据,但是数据文件的大小却调不下来,尝试使用resize来调整屡屡失败。如果一个数据文件里...

33412
来自专栏Rgc

提高查询数据速度

在实际项目中,通过设计表架构时,设计系统结构时,查询数据时综合提高查询数据效率 1.适当冗余 数据库在设计时遵守三范式,同时业务数据(对数据的操作,比如资料...

3538
来自专栏沃趣科技

Oracle Real Time SQL Monitoring

术语说明 TableQueue,消息缓冲区,在并行操作中使用,用于PX进程之间的通信,或者PX进程与QC进程之间的通信,是内存中的一些page,每个消息缓冲区的...

4098
来自专栏Java架构师历程

数据库(表结构)设计技巧及注意事项

库设计: 1、数据库名称要明确,可以加前缀或后缀的方式,使其看起来有业务含义,比如数据库名称可以为Business_DB(业务数据库)。 2、在一个企业中,...

971
来自专栏SmartSql

SmartCode.ETL 这不是先有鸡还是蛋的问题!

相信不少同学都用过各种代码生成器,这里我就不做详细介绍了,如果想体验 SmartCode.Generator 请至 https://www.cnblogs.co...

1186
来自专栏cs

知识点找回2.0

Servlet(server Applet),全称Java Servlet, 是用java编写的服务器端程序。而这些Servlet都要实现Servlet的这个借...

501

扫码关注云+社区