X-Man:本文是阿里巴巴数据库事业部X-DB团队在今年云栖大会上的分享。作者王剑英是阿里巴巴高级技术专家,主要从事存储引擎的开发及性能优化,同时负责X-DB异构计算加速方向的一些工作。本文将介绍X-DB数据库在FPGA异构计算加速方向上的探索。主要内容包括:X-DB的整体架构,在这个架构中异构计算加速处于什么位置,为什么X-DB会使用异构计算加速,异构计算加速又能解决实际业务的什么问题。
X-DB整体架构
![bb](http://img.blog.itpub.net/blog/2018/11/08/bf82af950d03f908.jpeg?x-oss-process=style/bb)
上图展示了X-DB整体架构, 它分为几个组成部分:
分布式SQL-Engine层。
存储引擎X-Engine,是一个针对阿里巴巴业务需求自研的存储引擎,具有自动冷热分离功能。目前X-DB异构计算加速就在存储引擎层起作用。
X-Paxos,高性能paxos库,主要解决跨AZ,跨region的多副本数据同步, 实现高可用。
此外,X-DB整体是构建在存储计算分离架构上的,它可以运行在本地盘,也可以运行在分布式存储系统之上(比如阿里巴巴的盘古)。存储计算分离架构给X-DB部署带来极大的灵活性,我们可以非常方便的增加计算节点和存储节点。
为什么要采用存储计算分离架构呢? 阿里巴巴是全球最大的电商之一,经常举办各类促销活动,比如大家耳熟能详的双11大促,618大促等等。大促状态和日常状态,数据库的负载很不一样。双11当天,我们的数据库负载可能是日常负载的100倍。因此在大促期间,需要扩容,而大促过后,就得缩容。一般情况下,数据库扩容和缩容都意味着数据搬迁,操作非常不便。 而使用存储计算分离架构之后,我们的扩容和缩容变得简单很多:只需要分别增加计算节点和存储节点就可以了。
X-Engine架构
X-Engine在设计之初,我们就期待它能解决两个问题:一个是性能问题,比如钉钉的万人大红包,或者双11促销,这些业务对DB有极大的性能诉求。 另一个是成本问题,阿里每天会产生大量订单,需要非常多的服务器来响应这些请求。 解决成本问题的本质是如何用更少的钱,完成更多的工作,反映到数据库上,就是用最少的服务器来承载更多的TPS。
![bb](http://img.blog.itpub.net/blog/2018/11/08/9f4683e34117bac8.jpeg?x-oss-process=style/bb)
这张X-Engine架构图分为两大部分,分别解决上述两个问题。内存部分解决高性能问题,磁盘部分解决成本问题。 X-Engine在内存中维护了一个高性能无锁索引结构, 能够达到百万级别的TPS,可以解决双11零点业务对性能的极致诉求。 整体上,X-Engine是一个LSM-tree结构,磁盘上的数据是分层存储的,可以方便的对数据进行冷热分离。冷数据可以压缩存储,从而达到省成本的目的。
为什么可以这么做呢?这是阿里巴巴的业务特点决定的,比如钉钉业务的消息存储,今天发送的消息,昨天发送的消息和上周、上个月发送的消息,被读取的概率是不一样的。我们很可能会查看今天或者昨天的聊天记录,但是翻看上个月甚至去年的聊天记录非常罕见。阿里的交易订单存储也具有类似的特征, 用户一般更可能浏览最近购物的订单,但很少会去查看时间久远的订单。这样就让分层存储变得可行,经常被访问的数据存储在内存中,提供最高的性能。历史数据存储在磁盘上,更久远的数据可以进一步做一些压缩处理,甚至是使用列存方式存储在机械盘上,进一步降低成本。
![bb](http://img.blog.itpub.net/blog/2018/11/08/463b1a0f2f9744f4.jpeg?x-oss-process=style/bb)
上图是X-Engine引擎对比InnoDB的性能数据。在我们的线上服务器上,对比官方MySQL 5.7 11WTPS的性能,我们有接近6倍的性能提升。但是,这里却有个隐藏的问题,X-Engine是LSM-tree的架构,而LSM-tree存储引擎有一个共性的问题:Compaction这样的后台任务会消耗CPU,而且分层存储底层数据压缩操作又会带来另一部分CPU消耗。X-Engine在单进程时,可以完全消耗完一个服务器的CPU资源。当后台任务运行时,不可避免的会带来性能的下跌。
![bb](http://img.blog.itpub.net/blog/2018/11/08/247c31a58e13676d.jpeg?x-oss-process=style/bb)
由上图可知,在X-Engine初始满载运行时性能非常高,但是当后台任务运行时,比如compaction或者压缩开始运行,对CPU资源的争抢会带来40%以上的性能下跌。 当然,在日常任务中,由于我们有很高的性能余量,跑一些后台任务是没有影响的。但是在双11零点那一刻,我们对性能和时延有着非常苛刻的要求,这时就不能容忍数据库的性能和时延有任何抖动了。
如何解决CPU耗尽的难题
因为性能抖动的原因是CPU被消耗了,那我们分析一下,数据库里面哪些任务会消耗CPU资源。经过profiling,我们发现消耗CPU资源的任务分类两种 :1)前台请求,典型的像SQL解析,请求处理,打开表,关闭表,加锁解锁这些操作。 2)后台操作,比如checkpoint,刷脏页,compaction,压缩解压等等。对于CPU资源不足的问题,其实有几个解法,第一个是继续提供更多的CPU资源,但这个方案受intel的限制,毕竟intel号称牙膏厂,每年CPU性能提升有限。第二个方向是提升代码对计算资源的使用效率。这个我们一直在做,但是优化的越多,性能表现越好,后台任务导致的性能抖动就更明显。 第三个方向就是考虑引入异构计算硬件比如GPU,FPGA,甚至是ASIC芯片。
那么为什么我们会把目光投到异构计算加速上来呢?我们最开始接触到的异构计算设备是intel出的一款ASIC芯片,叫做QAT。它是一个专门做压缩解压缩的芯片。经测试发现,它对性能有一定提升,起码可以节省压缩解压缩的CPU消耗。其实压缩解压只是Compaction操作中顺便完成一个任务,我们就想能不能把整个compaction任务都放到异构计算设备上来解决。毕竟后台任务中,compaction消耗的CPU资源是最多的。
X-Engine Compaction CPU 实现
要用异构计算设备来解决compaction问题,首先要分析compaction是做什么的。X-Engine新写入的数据会写到内存表,当内存表达到一定大小(比如256MB)之后会冻结,并转储到磁盘上形成文件,这些文件内部记录是有序的,不同的文件之间记录是无序的,存在范围重叠。对于读操作来讲,首先会读内存表,如果没读到就会去磁盘上读,从上到下依次读取转储形成的文件。如果写入的记录很多,转储的文件会越来越多,导致读操作需要读的文件也越来越多,速度越来越慢。此时别无选择,只能调度出一部分CPU资源,合并转储文件,形成一个全局有序的大文件,这样读的层数少了,响应时间会减少。但是如果我们调度了更多的CPU资源给Comapction,则留给前台线程的CPU资源会减少,这样能够处理的读写请求也就变少了。所以这是一个悖论:不做compaction,读操作越来越慢,做compaction导致的CPU消耗也会导致性能降低。
![bb](http://img.blog.itpub.net/blog/2018/11/08/8cb44dd073533a42.jpeg?x-oss-process=style/bb)
现在我们考虑用新硬件来解决compaction问题了,首先介绍一下CPU是怎么处理compaction任务的。compaction任务本质是一个多路归并操作,CPU会使用多个迭代器分别打开需要合并的文件,然后依次从这些迭代器集合中输出最小的KV记录,编码形成block(16KB大小)。block再编码形成extent(2MB),extent再组成文件。整体是一个流式操作,扫描多个输入文件,形成一个全局有序的输出文件。上图是CPU实现的基本逻辑图。
异构计算设备的选择
在众多异构计算设备,究竟该作何选择呢?我们首先把眼光投向了ASIC,它的成本是最低的,效率也是最高的。遗憾的是,市场上没有一款能实现compacton任务的ASIC芯片在售。此时可选的就只有GPU或者FPGA了。近几年借机器学习的火热东风,GPU加速能力被更多人熟识。GPU一般包含数千个小core,每个小core能完成一些简单的任务,如数字相加或相乘。人们通常用SIMD描述GPU,意指单指令多数据。就是说它能让数千个小core同时完成一个相同的指令。但是,GPU的缺点也很明显,众多小core之间的数据交互是通过板上RAM来实现的,效率比较低,所以不适合一些需要各个core互相交互的任务。虽然FPGA的计算核心没有GPU那么多,但是它有个优点是小计算单元之间通过片上高速缓存交互的(类似CPU的L1Cache),因而特别适合各个计算单元之间,需要前后接力完成的任务。对于一些深度流水类型的计算任务,FPGA可在一个时钟节拍的时间周期内,输出一次复杂操作的运行结果。这是FPGA的优势所在。
![bb](http://img.blog.itpub.net/blog/2018/11/08/a07b8d5f966cb814.jpeg?x-oss-process=style/bb)
Compaction恰好是一种任务之间有前后依赖关系的复杂操作,它涉及到数据block解码,key比较,以及最终输出编码等。我们可以在FPGA构建多个小计算单元,他们同时完成一个compaction任务的每一个计算步骤,然后各个core之间互相配合,达到在一个时钟周期内输出一个已排序key的目标。
X-Engine: 软硬件结合的数据库引擎
![bb](http://img.blog.itpub.net/blog/2018/11/08/13b5f0b3e36ddc4e.jpeg?x-oss-process=style/bb)
上图右边展示了结合FPGA后X-Engine的架构图。CPU资源用于完成前台用户请求,消耗资源的后台计算任务交付给FPGA。每种设备各司其职,互不影响,这样可以获得最高的性能,同时也有最为稳定的性能表现。
在分布式数据库系统使用FPGA,面临很多挑战。FPGA虽然计算能力很强,但不是插到服务器上就完事儿了,X-DB数据库需要做一系列改造。
第一,compaction是流式操作过程,它需要同时打开多个数据文件,输出一个数据文件。但FPGA设备是一个外设,通过PCIE接口和主机总线交互的。因此不能一下把好几个文件一起丢给FPGA,然后让排序后再输出,这样的任务FPGA设备无法处理。我们需要改造compaction接口。
第二,也是最核心的挑战。我们要设计出一个高效的FPGA IP,它必须能够以比CPU快的多的速度,来完成数据记录的排序操作,否则在成本上就是不划算的。
第三,容错设计,因为异构计算设备有一些与CPU不同的错误特点,同时由于它是一种外设,出错不可避免,数据库尤其对数据正确性要求非常高的所以我们必须要能cover这些错误。
关于第一点,CPU能比较好的适应流式compaction接口,它只需要不断和主机内存交互即可。为了适配FPGA计算能力特点和PCIE的接口特点,我们对compaction进行的两个大的改造。(1)原来较大的compaciton任务,被拆成一个个2MB大小的小任务。这些任务之间互不重叠,可以并行运行。这些任务可以通过PCIE接口发送给FPGA,同时我们把任务的分发和结果的收割做成异步模式,以适应PCIE接口的延迟。这样CPU端不断生成compaction任务,并推到compaction任务队列中,在内核空间有一个执行线程,不断将待执行的compaction任务扔给FPGA执行。而FPGA执行完compaction任务之后,会执行一个回调函数将完成的任务push到一个完成队列。数据库中的compaction收割线程会处理这些已完成的compacton任务,并做进一步的调度或者合并。异步队列解决了PCIE接口的延迟问题,可以避免IO操作阻塞太多的compaction调度线程。
![bb](http://img.blog.itpub.net/blog/2018/11/08/5f5939c6be23be8e.jpeg?x-oss-process=style/bb)
第二个核心的问题是如何设计一个高效的FPGA IP。FPGA运行频率相对GPU较低。但它的好处是各个小单元之间可以高效的相互配合,形成流水线来完成任务。想像一下富士康生产iphone的流水线,iphone本身的结构是非常复杂的,但是富士康的生产线却能每个几秒就下线一台iphone。我们设计的FPGA compaction IP就类似富士康的生产线,但我们的任务是对数据进行全局排序。如下图,整个compaction任务所需要的操作,被切分成了一个个小的工序。首先是解码器,它复杂从数据block中解码出一条记录放置到cache中。然后是比较器,用来比较多路compaction任务输出的key,选择当前最小的key输出。最后是编码器,编码器负责将输出的key再组织成一个以16KB为单元的block,根据需再接下来还可能有压缩单元等。这只是一个粗略的描述,事实上内部的细分步骤更多,而每一个计算步骤都可以同步并行执行。
![bb](http://img.blog.itpub.net/blog/2018/11/08/2962bac62fd74fde.jpeg?x-oss-process=style/bb)
最终的效果是在每一个时钟节拍之内,一条FPGA compaction就可以输出一条排好序的记录。可以想象这个速度是非常快的。我们需要合理设计FPGA的每一个计算步骤,保证它们的都以相同的速度运行,不能有的快,有的慢,互相干扰。每一个步骤都必须要在一个时钟节拍之内完成一次任务。
当然实际情况没这么理想化,不同步骤的任务复杂度是不一样的。比如排序相比解码来讲就复杂很多,它们可能难以保证在同频率运行。为了避免这种频率不同步导致的互相干扰,我们引入协调器,来同步不同速度的各个处理单元。比如,若解码速度过快,我们会发送一个通知,让解码任务暂停,在后续任务完成之后,再开始解码。
最后要解决的是容错问题。我讲一个大家可能觉得匪夷所思的问题:FPGA这种计算设备,可能受太阳黑子影响,计算任务出错。对于这类问题,我们通过双路check的方式来解决。另一方面,因为FPGA是一种外设,通过PCIE设备传输的时候,也可能发生一些意外错误,这种任务也需要探测到,我们在每一个阶段都引入crc32校验。此外,为了最大化FPGA的计算速度,FPGA compaction IP能够实现的功能并不和CPU对等,有些compaciton任务,FPGA可能无法实现,它会报错返回,再由CPU执行。
我还想分享一个异构计算加速的开发经验。在一开始就设计一个测试友好的系统。我们设计了三种compaciton模式,分别是CPU/FPGA/Check模式,其中Check模式的实现是同时把compaction任务下发给CPU和FPGA执行,然后对比二者的结果,这样可以检测出FPGA执行compaction任务的结果是否符合预期。这样的设计在前期帮我们探测到了很多的问题。
实验结果
该图展示了FPGA IP对比CPU的compaction性能,可以看到,FPGA最高可以超过3GB/S的compaction吞吐,在记录长度为2K的时候。此时FPGA相对于CPU的加速比超过了30倍。
![bb](http://img.blog.itpub.net/blog/2018/11/08/e7f0277d23500592.jpeg?x-oss-process=style/bb)
下图展示了X-Engine KV接口的测试,可以看到它几乎消除了我们最开始贴出的那个图里面的性能下跌的陡坑。
![bb](http://img.blog.itpub.net/blog/2018/11/08/5e170a7e3a621417.jpeg?x-oss-process=style/bb)
下面是YCSB测试结果,它和X-Engine KV接口的测试结果是类似的。
![bb](http://img.blog.itpub.net/blog/2018/11/08/3e458830d6a5851a.jpeg?x-oss-process=style/bb)
最后展示了SQL接口下X-Engine的CPU compaction和FPGA compaction的性能曲线,以及这两者和Innodb的的性能曲线的对比。可以很明显的看出,X-Engine(FPGA compaction)性能远远高于Innodb,同时它的运行稳定性也远好于X-Engine(CPU compaction).
![bb](http://img.blog.itpub.net/blog/2018/11/08/4ef63e8f041e9a4c.jpeg?x-oss-process=style/bb)
- end -
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31556436/viewspace-2219239/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31556436/viewspace-2219239/