皇上,还记得我吗?我就是1999年那个Linux伊甸园啊-----24小时滚动更新开源资讯,全年无休!

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

作者 杨旸

从应用上来讲,GPU数据库带来了三大方面的进步:加载速度、实时处理和宽表多条件查询。它最大的革新点之一在于,提供了一种不依靠索引,并大幅提升速度的手段。 所以,要搞清楚GPU数据库,先让我们聊聊数据库,尤其是数据存储。

索引、分区和组合主键

传统数据库的存储是在磁盘旋转的碟片上。读数据时碟片先旋转到一定位置,磁头再伸到相应的扇区,称之为寻道,并读取一个或多个数据块(Block)。旋转到位的时间和转速有关,以7200转/秒的磁盘为例,旋转延迟为4.16ms。普通台式PC磁盘的寻道时间为10ms, 数据传输时间可忽略不计,因此,光是从扇区上读取数据,就需要14毫秒左右。这是什么概念呢? 大家后面可以看到,GPU数据库的响应时间常常也就几十毫秒。

数据库如何找到想要的记录?最糟的办法是扫描整个表,这就意味着要一个个的扇区地读,直到读到目标记录。每读一个扇区用14毫秒的话,就洗洗睡了吧。 每个记录都有一个所属的扇区和该记录在该数据块里的位置。不同的操作系统和数据库对这两个概念有不同的名称,让我们姑且称为PageID和SlotID。如果知道每条记录的PageID和SlotID,无论运气好不好,读取时间都是一个常数——直接到磁盘上的目标块,整块读出,并按SlotID找到该记录在本块里的所在位置,读出即可。这也称为时间复杂度为O(1)。

索引可以看作一张表,最重要的功能就是记录每条记录的PageID和SlotID, 并通过一系列指针,让人们尽可能快地找到或更新它们。

以数据库最基本的查询之一: SELECT…WHERE ID=123456为例, 最有效的是哈希索引。它本质上是一个Key-Value表,Key是ID的哈希值,对应该Key-Value表里的第几行,Value包括一个指针,指向存储该条记录的PageID和SlotID。对于ID=123456,先用哈希函数算出哈希值,比如是9231,那么直接去索引表的第9231行即可找到PageID和SlotID,读出对应扇区的数据块里的数据。因为索引通常放在内存里,因此访问速度比一块块地从磁盘读快得多。

真实的索引远比这个复杂,并分为哈希、B树,B+树等不同技术,来处理等值、范围扫描、非等值查询等。基本原理都类似,将扫描磁盘的多个扇区变为扫描一个多层次的地图, 以便逐层找到目标记录所在的PageID和SlotID。

索引的最大坏处是多了一张或多张索引表。每增加一条记录,不仅要将该记录写到磁盘里,而且要计算哈希值、编入索引表、并调整索引里受影响的指针位置等等。将一个写操作变成了多个操作,更容易出错甚至损坏,而且延长了写入时间,大大降低了数据加载入库的速度。因此,大家可以看到,基于磁盘的数据库,无论是传统关系型还是现代的分布式Hadoop数据库,都会提供多种加载方式,其中一种一定是直接写文件,而不写索引,不考虑事务,以便加快加载。 在这点上,GPU数据库很不一样,也是其最重要的优势之一,后面再讲。

用户们不会那么乖,只按ID查,如果还需要按时间、店铺ID、产品ID之类查怎么办?最简单的办法是建多个索引。用哪个字段查,就为哪个字段建索引。如果字段数少还行,但是如果有10个常用字段怎么办? 这10个字段的组合就可能产生1024种索引,如果所有记录都需要编入索引,数据量将膨胀到何种程度?

用户行为分析的巨头Heap Analytics就用这个办法:将Web访问事件的所有属性记录进一张大表,对常用字段分别建索引。其使用的PostgreSQL支持部分索引(partial Index),允许按Where条件筛选,仅将符合Where条件的记录建入索引,以便大大地减小建索引的开销和索引表的大小。据称,他们需要维护几百甚至上千个这样的索引。 好在这张大Fact表是张稀疏表,每种属性的数据都不多,大量空白值,因此通过Where条件筛选后的部分索引会大大缩小。

Hive、SQL-On-Hadoop之类的产品还会增加其他手段,比如分区。在建表时增加一个“分区”字段,通常用基数低,而用户经常查询的字段,比如年月、店铺ID或产品ID。往数据库里增加记录时,同一分区的记录尽量连续存放在磁盘的同一个或相邻的数据块、或分布式集群的同一个Region/Partition/Bucket/Division里(不同的技术对这个概念的称谓不同)。如果用户经常用这些字段查询,或者Group By,那么只要先找到分区,一个读操作就可以读出同一个年月、店铺ID或产品ID的大量记录,大大节省旋转、寻道或分布式存储系统寻址的开销。

对于索引问题,惠普等老牌数据库公司还推出了MDAM等技术,将分区字段放在主键之前,拼成多个字段的组合主键,建入同一个B树索引中,从而用一个索引达到两个甚至更多索引的效果。 查询时,先组合主键里的分区字段,对每个分区进行并行的范围扫描(Range Scan)。可以想象,如果按性别分区,一下子可以缩小一半的搜索范围。 有兴趣的同学可以读读HP Labs大牛Goetz Graefe的有关论文,此人对惠普大型数据库和Microsoft SQL Server都有神一般的影响。 这一机制在惠普的Nonstop SQL/MX和Apache Trafodion里仍能找到。

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

不过组合分区也有其他问题。如果存储系统是键-值(Key-Value)的分布式系统,如HBase,那么对于每对键-值都需要存Key。如果Key是组合主键,包括多个字段,那么Key就会很长,大大增加存储开销。所以还需要进行编码和压缩,来减小空间开销。代价是,在数据加载时,仍会有增加额外的编码开销。

GPU和SIMD

表和图像很类似,对象都是很有规律的一个个格子。 处理起来也很类似:可以并行地对每个格子里的数值执行一组单向步骤的指令——即通过SIMD(Single Instruction Multiple Data)用同一组指令处理多个数据单元。加上GPU有多核,因此可以并行大量线程。每个线程都有对应的核支撑,无需操作系统来回切换,将大大加快速度。对NVidiaK80这样的GPU设备来讲,硬件并行意味着可以用4992颗核来支持上万个线程并行处理,这比操作系统+CPU的超线程快多了。GPU上的内存也增加了不少,K80有24G显存,在RDMA等技术的支持下,可以通过PCI-E总线和网口实现GPU显存之间的高速数据交换。 K80显存的IO总吞吐量也达到480G/S。因此,将GPU用于并行计算和数据库是水到渠成的事。

用GPU进行几千万行的扫描通常仅需几十毫秒。如果网络速度够快,几十亿行的扫描,返回几亿行结果,也仅需几百毫秒。

GPU数据库

物联网的迅猛发展,让人们不得不调整数据平台的设计思路和处理方式。2017年Gartner发布的Top strategic predictions for 2017一文指出,到2020年,210亿只IoT设备对数据中心存储需求增长将不超过3%。 先入库再处理的方式不适合高速、巨量的物联网数据。

和银行或商业交易记录相比,这些物联网数据的存储价值不高,因为同样的传感器之间的个体差异很小,更接近于随机过程,我们更关心在某个时间段内,发生某个事件的概率,因此需要确保相应统计模型的可靠,和等,而不那么关心A区的传感器在二季度比去年同期多发了多少个警报,更无需考虑A区传感器半年以来的购物和存贷记录,是否适合我行180天期的金茉莉理财产品。

在数据加载的同时进行分析,显得前所未有地重要。第一个坎就是要摆脱对索引的依赖。在多个数据流高速加载的情况下,无需写索引表所换来的性能非常可观。据Kinetica的创立者称,2010年美国陆军情报和安全指挥中心(US Army Intelligence and Security Command)希望处理200个实时数据流,包括手机、无人机、社交网络和Web访问,每小时2千亿条记录,为分析师和开发者们提供接口,来结合时间和地理位置监控危险信号。 他们尝试了HBase,、Cassandra和MongoDB, 但一直未能解决同样的问题:能支持的查询极为有限,索引越来越多,越来越复杂,并一直需要增加硬件。得到结果的速度越来越慢,开始是1个小时,随着索引越来越复杂,逐渐需要1天,后来发展到一个星期。 用两年时间,他们开发了基于GPU的系统——用HBase作为永久存储,用GPU数据库提供实时加载、实时查询。多个实时流可以从多个Head节点,多线程加载,可处理每分钟14亿条。

该GPU数据库以列式存储,结合内存+显存,无需优化,无需建索引。内置可视化层、地理空间层、流处理层,并有Hadoop和 Spark等接口。常见的使用方法是从Kafka、Storm、Nifi上获取数据,高速处理,并输出到BI工具如Tableau、Qlikview里。

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

他们在2017年纽约举行的O’Reilly AI大会里有个演示: 8个GPU设备组成的集群,每台服务器256G内存,整个集群有244亿条记录,1.7TB,其中41亿条推特。

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

推特表的情况如下:

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

用户可以在地图上任意圈定区域,结合邮编、名称等筛选、关联,一秒以内可以从41亿条里,返回5.13亿条结果。

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

这种城市级的区域选择,得到4300多万条结果,需几十毫秒。

同时,也可以复制区域形状,拉到其他地区放大缩小范围,用关键词搜索文本内容,也可以在几十毫秒得到几百条结果。

用SQL对这张40多亿条记录的大表,跑下面这条聚合查询,72毫秒就出结果。

SELECT count(*), sum(sentiment_vader_p),avg(sentiment_vader_p), min(sentiment_vader_p),stddev(sentiment_vader_p),var(sentiment_vader_p),sum(txtblob_p),avg(txtblob_p),stddev(txtblob_p)
FROM MASTER.Twitter

对两张2000万条记录的电影统计表关联、排序和模糊匹配,响应时间是53毫秒。既然是排序,那么limit 100对响应时间的帮助应该不大。

SELECT m.title, m.genres, avg(r.rating),count(r.rating) 
from movie m, rating r
where r.movieID=m.movieID
and (genres like'Action%' or genres like 'Thriller%')
group by m.title, m.genres
order by 4 desc
limit 100

总的来说,分析型应用涉及到的大多数数据库操作是读。在生产时间,将数据加载到显存和内存里,无需访问磁盘,因此无需依靠索引来降低访问扇区的开销。通过每个GPU的几千个核,并发上万个线程并行扫描全表,尤其适合几千万到几十亿行的JOIN、模糊匹配、Group By、全表扫描或聚合等等,比如七八千万条的大表在非主键字段上JOIN,性能提升很明显。单机处理几千万行的数据也能在几十毫秒内返回。这样的低成本查询,使用起来就比Hadoop和传统关系型数据库灵活、高效得多。人们不仅可以更自由地选择任意字段分析,按任意组合,一次查询的条件更多,而且能够对高速加载的数据流实时处理——先处理,再落地。

同时,GPU显存和内存之间的交换带宽很高,所以即使是TB级数据,或者有更新、数据注入时,可以用内存作为桥梁,实现磁盘–内存–显存缓存的三级缓存来解决。

多维交叉可视化查询

传统的BI只能每次看一个视图,比如先从销售,再碰碰运气加入库存,但实际上有价值的结论需要多个视图一起看,因此产生了多维度交互式可视化查询,让大家的尝试更高效。

Tableau无疑是这方面最成功的企业之一。这种做法的颠覆性意义在于,同一个仪表盘上同时展现多个视图,反映不同的角度,比如销售、库存、客户等等,点击任何一个视图都会对所有视图添加同样的筛选条件,展现所有角度的变化。

每次点击实际上是对所有视图加了Where条件。当数据超过1千万条,用普通数据库的响应时间就会很慢,不再是交互式。如果视图超过10个,每次互动产生的查询很多,数据库压力也会很大。Tableau等BI工具的解决方法是将查询结果缓存起来,和对大数据集先采样再计算。但这种缓存的设计比较考究,也增加了更多步骤——要先查缓存,缓存里的记录也可能未及时更新。而GPU数据库的响应速度快,每个查询的开销低,所以即使不用缓存、不采样,每次都发新的Query,同样可以达到实时的效果。

MapD曾有一个很棒的Demo,展示纽约市出租车的交互式分析,数据量超过10亿条。利用GPU数据库的性能,加上查询结果在显存里,能实现动画式的交互:用户可以在时间轴上拉一个窗口,并拉动该窗口,其他视图随之变化,请见下图底部时间轴的浅蓝色块,从左到右移动效果。这就超越了指标计算,可以更好地洞察趋势。

这种拉动窗口产生的查询更密集,因此仍可以借助查询缓存,利用之前的结果来加速响应,实现流畅的动画效果。不过这种缓存更加简单,比如将查询结果按Key-Value的形式放入缓存,Key是查询语句,Value是查询结果。

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

(点击放大图像)

崛起的GPU数据库大揭秘:多数据流实时分析,如何做到快如闪电?

举个例子,如果用X、Y轴分别展示航班的到达延误和满座率,通过拉动时间窗口,可以看出不同航空公司的这两个指标组成的点的移动。哪些公司的差距逐渐增大?哪些在减小?

小空间,大数据

大家都知道,GPU数据库的显存小,那么有没有处理TB级以上的例子呢?

除了Kinetica宣称能处理100TB级的数据之外,Sqream也比较擅长大数据量的GPU应用:其最初客户来源于癌症研究中心,需要处理基因排序,比如对比癌症患者的缺陷基因序列和正常序列,需要大表之间JOIN。每对序列有200多GB,多对序列的比对就需要TB级的处理能力。用关系型数据库对比12对序列需要2个月,Sqream通过GPU比对几百对序列,仅用了2小时。

他们的另一个场景和Kinetica最初的安全监控很相似,反映了GPU数据库的另一个优势。

5个无人机加一个巡逻车进行边境巡逻,每小时无人机总共传输8TB给巡逻车,巡逻车要及时发现异常以便及时准备扔石头(好吧,后面这句是我编的,如有雷同,纯属巧合)。车里最多能放一两台服务器,GPU数据库当仁不让。

同样,无人机在人群集中的广场、景点巡逻时,可以将视频传输到坐在咖啡馆里的便衣工作人员的笔记本上,由人脸识别等视频软件产生结构化或半结构化的数据,并由GPU数据库实时处理,来识别可疑人物或异常移动的车辆。灵活转移的工作地点和隐秘性,使得一台带GPU的笔记本比几台服务器更适合。

机器学习和深度分析

GPU数据库在机器学习和深度分析上的应用也越来越多。对于机器学习来讲,在模型上跑机器学习算法,需要用多个数据集在多个模型上计算。越快算完,可验证的模型就越多。 这方面的应用有很多文章,就不再赘述。

越来越多的厂家开始用UDF将人工智能、回归、分类、预测等现成的代码集成到GPU上运算,以充分利用GPU加速线性回归、随机森林、灰度提升树(GBT)或蒙特卡罗仿真等。一般的实现方式是先将自己的Java/Python/C/C++的函数和library向GPU数据库注册成UDF函数,然后在自己的Python/Spark/Tensor Flow/Caffe里访问数据库,比如通过UDF向GPU数据库传入一个表,在GPU上执行UDF,返回数值结果或二进制的表结果。

GPU数据库的局限

GPU数据库擅长能够被转化成并行处理的任务,比如Group By, JOIN, Aggregates, Hash。但不擅长某些难以并行的,比如排序,或者先排序再处理。

同时,由于显存有限,在处理较大数据集时,需要内存、显存之间的交换。数据准备、分块、各个阶段IO访问和Kernel的同步协调等执行细节,对开发者的要求和代码质量比较高。考虑到数据的实际物理分布、并行度、对JOIN优化等情况,还可能涉及到数据重分配,广播等跨GPU、跨节点的交换。虽然NVidia的RDMA通过支持GPU和网卡、GPU同伴之间基于PCI-E总线的高速交换,能提高数据交换速度,但仍和开发水平关系很大。

一旦涉及到大量的写操作,GPU显存小的劣势更明显,需要频繁地和内存、磁盘之间交换。随着计算的比例下降,IO的比例上升,GPU在计算上的优势就被IO上的劣势逐渐掩盖。同时,分析型应用和显存的有限,导致GPU数据库常用列式存储。因此对于一致性要求较高的场景,需慎用。它们一般提供最终一致性。读写并行时,如果有20个线程访问,19个读,1个写,会让所有读都通过,无锁,无事务,有可能带来脏读等问题。

在并发处理上,更多的是依靠高速计算能力,十几毫秒的响应速度结合分布式、管道、队列、消息系统等来提升并发性能。而如果十几毫秒仍然不够快, 从GPU SIMD的实施方式上来讲,是独占和单向的,有的指令要等所有核都计算完,数据同步后才能进入下个指令。 因此,如果某个核所需的数据没准备好,有可能造成其他核空等。

实际上,GPU数据库这个称谓,和其发展现状来比,还有甚远的距离。“数据库”包括很多内容,性能仅仅是一个小部分。MySQL、PostgreSQL等开源数据库的成功远远不只是“性能”或“兼容”。窗口函数、CTE等带来的便捷、高可用、事务、ACID、元数据管理、冷热数据分离、混合工作流等等都是大型数据库集几十年、数代的开发和应用逐渐积累的,基于GPU的数据产品还不能全面和商业数据库媲美。

同时,站在数据湖的角度来看,GPU能解决某些实时流处理、查询和加工工作。而更多的报表、ETL、数据集市、关系型数据库迁移、混合云等工作,还是需要基于Hadoop等分布式数据平台,依靠全面的ETL、索引、分区、冷热数据分离、冷数据转移、清理、合并、复制等。数据治理、元数据管理、安全和权限、弹性计算等方面,几个Hadoop平台厂家也有成熟、全面,可靠、好用的方案。

任重而道远,且行且珍惜!

转自 http://www.infoq.com/cn/articles/the-rise-of-gpu-databases