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 条评论
登录 后参与评论

相关文章

来自专栏我是业余自学C/C++的

汇编语言-第一章 基础知识

1662
来自专栏Ceph对象存储方案

对象存储基础概念

对象存储诞生之初 谈到为什么要有对象存储,必须聊聊对象存储诞生之前的两大存储模型:块存储和文件存储。 块存储主要是将存储介质的空间整个映射给主机使用的,主机如果...

3614
来自专栏java一日一条

Java中不同的并发实现的性能比较

正如即将上映的星球大战那样,Java 8的并行流也是毁誉参半。并行流(Parallel Stream)的语法糖就像预告片里的新型光剑一样令人兴奋不已。现在Jav...

371
来自专栏程序员与猫

MongoDB 存储引擎和数据模型设计

标签: MongoDB NoSQL 1. 存储引擎 1.1 存储引擎是什么 存储引擎是位于持久化数据(通常是放在磁盘或者内存中)和数据库之间的一个操作接口,它负...

19910
来自专栏架构师小秘圈

你所不知道的库存超限做法

作者:程序诗人,来自:cnblogs.com/scy251147 零,题记 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达...

3176
来自专栏Java面试笔试题

Error和Exception有什么区别?(还在总结)

Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Except...

632
来自专栏芋道源码1024

从一次 Snowflake 异常说起

1. 异常概述 2018年1月26日下午,业务方信贷小组的同学反馈服务执行数据库插入操作出现异常,异常信息显示数据库主键出现重复: ? 在仔细分析了用户的重复主...

1.2K5
来自专栏牛客网

C++后台腾讯WXG实习面经(已拿offer)

时间:2018年4月16日 岗位:C/C++后台开发(Linux) BG:WXG 关于我:本科大三 预计2019年毕业 一面(普通技术面) 过程:递交简历 ->...

47810
来自专栏个人分享

海量数据处理技术学习

  外排序:因为海量数据无法全部装入内存,所以数据的大部分存入磁盘中,小部分在排序需要时存入内存。

492
来自专栏about云

Apache Spark 2.2中基于成本的优化器(CBO)

问题导读 1.什么是CBO,RBO? 2.什么是执行计划? 3.什么是join,filter? 4.事实表和维度表的区别? Apache Spark 2.2最近...

3567

扫描关注云+社区