更多精彩内容参见云栖社区大数据频道https://yq.aliyun.com/big-data;此外,通过Maxcompute及其配套产品,低廉的大数据分析仅需几步,详情访问https://www.aliyun.com/product/odps。
摘要:回顾大数据技术领域大事件,最早可追溯到06年Hadoop的正式启动,而环顾四下,围绕着数据库及数据处理引擎,业内充斥着各种各样的大数据技术。这是个技术人的好时代,仅数据库领域热门DB就有300+,围绕着Hadoop生态圈的大数据处理技术更是繁花似锦。在云栖社区2017在线技术峰会大数据技术峰会上,阿里云大数据计算平台架构师钱正平做了题为《大规模流式增量计算及应用》的分享,钱正平结合阿里巴巴真实的业务场景为大家分享了流式增量计算编程方面的挑战和当前的解决方案。
首先从理解什么是数据流开始今天的分享,其实在真实的世界中,大部分的数据都是连续产生的数据流,比如手机上产生的GPS信号、用户在互联网上的行为、在线搜索、用户的点击、社交网络分享、即时通信以及一些传感器和物联网设备采集的日志信息等,这些数据都是连续产生的,自然就形成了数据流,在这些数据流产生以后,在很多场景下对于数据流的实时分析就会产生很大的价值。
接下来从大家比较熟悉的数据场景切入,比如大家经常会关注的股市情况,股价的波动其实就是实时数据的分析和聚合,除此之外大家在日常生活中还可能比较关心天气预报,可能会根据实时的信息来看比如当前的台风的情况,这些都是大家习以为常的,也已经深入大家生活的实时数据分析。
而随着实时数据源的越来越多,实时数据的规模也越来越大,可以应用的场景也越来越多,实时数据的应用也正在往更多的领域深入。比如像每年的天猫双11全球狂欢节,阿里巴巴就有一个实时大屏,左图上是2015年的情况,当时在第35分钟的时候就已经有了200亿的销售额,同样的2016年也是一样,所有的交易数据都会在秒级之内反映在数据大屏之上,再比如在2015年还有模拟的一个地球,可以看到从卖家到买家的订单都会被实时地刻画出来,这在商业领域将会给大家一个非常直观的印象,也可以用于辅助商业决策。
特别是在安全以及监控这些领域,数据有时候除了用于看以外还可以预先设定很多规则,基于流计算的“规则引擎”提供了传统的安全监控系统无法提供的海量数据处理能力,根据这些规则就可以省去很多的人力劳动,可以自动化地进行报警,利用大规模分布式集群实时计算和分析监控数据,避免人肉数据检查的低效,有效扩大监控范围,提升监控时效。这方面目前有很多的应用,比如像监控电网的运作等。
除了判断简单规则以外,还可以通过实时分析数据去发现一些规律,去实现更多的机器智能。这里举的是阿里巴巴帮助协鑫光伏的一个案例,协鑫光伏是一个专门加工太阳能电池的企业,它的设备都非常复杂,上面的每个设备都有几百个传感器,加起来就有成千上万路信号输入,如果通过人去理解传感器的行为,去检测或者预测哪一个设备将会发生故障再去更换,这中间的延迟就会造成很大的浪费,也就会导致次品率上升的问题。而通过实时的数据分析加上人工智能的算法最终实现了机器自动预警和判断,这样不仅提高了工作效率,甚至还能够预先自动提示操作人员对于设备的某些部件进行更换,最终实现对于良品率的提高,进而提高企业的收益。
更进一步除了对于简单结构化的数据的分析,实时分析还可以运用到更广泛的场景,阿里巴巴目前正在进行的一个项目就是城市大脑,就是将杭州所有城区的道路摄像头的视频信息做实时分析,用不同路口的视频信息来检测人和车的行为,以此来帮助城市更好地管理和优化交通,为解决城市拥堵问题带来很大的价值。
未来,实时数据分析将会越来越多地从我们所熟知的领域进入我们未知的领域,基于实时数据分析的应用的创新也会给我们的生活带来越来越多的变化,这将是激动人心的大趋势。
那么从流式数据处理背后的系统架构去看这个问题,实际上实时的数据处理对于大规模大数据的处理系统带来了大规模的高要求的挑战。因为数据是实时产生的,但是由于成本原因或者处理能力的问题,数据一般采取“先存后算”的架构,传统的架构上数据会在分布式文件系统中存储下来,然后再经过批量的计算,比如每天产生一个数据报表,这就是传统的数据处理的一套工具链。
而在新的要求更加实时的流式数据处理中,原来的“先存后算”的架构显然是无法满足要求的。对应的对于实时数据流的处理则希望能够随着数据的产生实时地进行加工处理,能够实现很高的时效性以及很低的计算延迟,并且实时地帮助各种各样的场景对于大数据的价值进行挖掘。
如果将流式数据处理系统架构进一步细化,从原来先存后算的架构过渡到这样一个不依赖于一开始的批量数据存储而每时每刻都要计算的架构,这中间存在着很多的问题和挑战。下图就是将系统架构稍微细化一点的示意图,对于数据源而言,首先数据是实时产生的,需要通过数据总线将实时产生的数据很低延迟地存储下来,并且需要传输给流计算。但是因为数据量的规模以及数据源端的各种复杂性,这样的数据总线是要求保证数据的持久化的,而且需要保持很低的延时,同时需要保证规模化,所以需要进行数据切片还需要保证数据的顺序。因为产生的数据本身是存在顺序的,很多应用对于数据的顺序也是非常关心的,所以整体而言对于数据总线部分是存在新的要求的,这些就是关于输入和数据采集的问题。
在之后会详细地分析计算这一部分,在这里先不考虑计算。那么假设数据通过计算之后能够产生某种价值和知识,在系统架构的消费端也需要经过改造。这里举个例子如果需要将应用改造为实时化的,可能在十几年之前会需要打印出一个纸质的报表,但是这个纸质的报表在实时处理的今天就无法展示出实时的形态了,所以首先需要进行报表电子化。其次要想实现低延迟的展现,就是从数据计算出结果到能够让用户看到计算结果需要很低的延时,否则在实时决策中的效果就无法达到预期。除此之外,整个实时计算系统是由很多服务构建的,所以计算出来的结果可能需要通过消息队列连接更多的服务,比如触发了某个规则引擎中规则,就可能需要调用某一个报警机制,比如发短信来通知用户,这就需要上下游更多系统之间的配合。第三个场景就是有时实时计算除了使得之前提到的应用成为可能还有一种场景下就需要数据采集手段的提高,因为存在大量的实时数据不得不以流式地进行预处理做一些筛选,将真正重要的信息存储下来再去进行离线的更加深入的分析。所以无论是数据的上游还是下游都需要大量的改造功能才能使得实时计算成为可能。
后面将会主要分享一下计算这部分,对于实时计算而言,需要面对很多的挑战。
首先实时计算需要很高的性能,需要保持延时和吞吐的平衡,需要很好的扩展性,能够支持超大集群规模的线性扩展。还需要考虑容错问题,大家知道在进行批处理的时候产生一个错误就需要重新计算,而且容错这部分还需要考虑低延时。还有因为很多任务可能同时在进行计算,所以也需要保证资源的有效利用。实时任务会一直占用资源,而有一些不同的数据流的输入速度不同,如何调配资源的共享和隔离也是一个挑战,除此之外还需要考虑流计算的易用性等等问题。
因为今天分享的主题是增量流式处理,所以在这这些流式计算所面对的挑战中选择一个话题展开来讲,今天就主要分享关于实时计算如何编程的问题。那么什么是实时计算的编程呢?其实就是去写一个程序来表达实时处理逻辑,数据是以流的形式进来然后存储在某个消息队列中,之后应用再去消息队列中获取数据并进行计算,并将数据产生的价值传输到下游的系统中。但是与离线计算不同,实时流式计算需要考虑很大的规模,需要同时并行地运行在很多的CPU上面,所以流式计算的编程实际上就是对于分布式程序的编程,这其实将会一个比较困难的问题。
而对于实时计算编程的一个简单的解决方式就是目前大数据方面非常通用的模型——数据流计算。这里举的例子就是2011开源的流计算系统Storm,Storm实现的就是如图的这样一个数据流的模型,这里有输入流和输出流,中间存在多阶段的计算。
当然知识这里示例性地分为了三个阶段,而真实情况下可能有多个阶段,在每个阶段上数据并行会有多个计算节点。与批处理不同,数据流模型上面的数据是流动的,所以每个事件在每个阶段都是流水式地执行和触发的,这就是基本的数据流模型,也是被很多系统所采用的模型。下图中只画出了6个节点,如果在成千上万的节点上去写这个程序,如何表达计算逻辑就是比较困难的了。刚才提到过数据并行,所以只需要为每一个阶段编写一个程序就可以了。图中包含了三个阶段,如果根据Storm的概念来看,其实每个阶段的编程接口实际上是非常简单的,这里是一个示例,比如X节点实现了这样的一个interface,实现的函数就是当数据灌给你的时候需要该怎么做,这是一个非常简单的接口,如果以这样一个非常底层的接口去描述实时逻辑,下图中列举了一个非常简单的例子,就是WordCount将输入的数据切成Word分词,并根据一些窗口去计算词频然后进行统计。一个简单的WordCount会占用很多的代码行,图中是从网上找的一个例子,所以大家可以想象如果一个非常复杂的业务使用基本的接口去写在某些场景下会是非常困难的。
面对上述这样的问题,一个想法就是与离线计算的处理一样去寻找更高层的语言,所以大家会尝试着去使用SQL。接下来列举两个具体的例子,就是如何使用SQL将比较复杂的拓扑通过简单的几行代码描述出来。
这里的例子就是前些年一个学术界的系统,可以看到上图中左边是使用C#高级语言写的一个MapReduce的程序,实际上就把每个记录调用Mapper()函数变成多个队,之后进行GroupBy()并按照不同的组进行Select并做一个Reducer。这个程序就比刚才一行行去写要简单很多,系统也可以自动从类似于SQL的描述性语言去生成右侧的DataFlow,右侧的数据图从输入到MapReduce实际上是两个阶段。另外一个更复杂的例子是分布式排序,可以看到一个非常复杂的问题也可以通过写非常简单的语言对于每个Mapper()出来的结果给一个Key进行OrderBy(),右边在生成计划的时候可以做非常多的工作。这个例子就是想告诉大家不仅可以用高层语言来简化对于复杂拓扑的描述,还可以让拓扑在生成的时候进行很多的优化。这里稍微解释一下右边这个图,这个图就是对于数据进行排序,大家可能想象简单的MapReduce就能够进行排序,但是在实际的执行情况下为了达到高效,数据的负载均衡是非常重要的,那么如何保证数据在排序这件事情上是分段均衡的呢?这里的解决思路就是对于每一份数据都进行采样,这样就能对于数据分布进行大致地了解,根据数据分布可以确定数据应该按照什么的range进行重新划分,这样就可以将数据分的比较均匀。如果采样足够高效,这部分的时间是值得的,因为这会使得后面的计算更加高效,计算的并行度和加速比也会变得非常高。以上就是SQL的例子,可以看出,在离线的情况下SQL可以帮助我们简化编程。
接下来我们再回到在线计算,今天的问题就是如何帮助大家用各种简单的方式编写一个流计算的程序,这里举的例子是一个离线的SQL语句,那么如果直接将这个SQL用于流计算会产生什么样的问题呢?假设输入的数据是连续的无穷的数据流,在这样的情况下大家可以看到有什么样的困哪呢,因为Group By需要对于例子中所有的Customer Name进行聚合,也就是需要知道某一个“Mike”购买的全部东西才能进行聚合,但是对于实时连续不断输入的流,如何才能知道“Mike”有没有购买更多的东西呢,怎么知道什么时候该输出呢?其实这里例子就是想要告诉大家如果简单地将SQL语句用于描述数据流处理实际上在语义上是无法匹配的,所以这样例子中的Group By是不会有输出的,但是如果等所有的数据都输入之后再进行处理就无法达到低延时的效果了,这就是困难所在。
为了解决上述的问题,大家也都想了各种各样的方法,但是到目前为止并没有一个最佳的解法。其中一种方式是使用类似SQL的语言去写这个问题,但是对其中的一些算子进行修改或者引入一些必要的算子。这里举个例子就是join操作,如果在SQL里面使用join其实就是将两个表连接在一起,但是在流式计算中将两个流join如何才能知道已经流过的数据能不能与当前流中的数据连接上呢,就需要保留太多的数据,所以一种做法就是在join上加一个范围限定实现时序的join。另外Group By操作的问题就是永远都无法产生输出,所以可以弱化它的语意,让Group只做分流,不同的用户进来将会丢到不同的Group中,但是并不在其上做聚合。那么什么时候做聚合呢?就是需要在流上引入Window的概念,Window有各种各样的定义,可以按照几分钟或者几小时进行一次聚合等。总之这一系列算法都是引入类似SQL的语言实现,这个方法是微软最早出SQL Server的时候就有的流数据库的语言,目前包括亚马逊、Storm也在提这种语言,但是这部分还没有统一的标准,各家都有各家的东西。最近Apache Calcite标准试图将不同的语言进行统一,形成一套大家公认的流式语言,其实标准化非常重要,不然的话学习成本将会非常高。
上述的方法引入了新的语言,虽然形似SQL,其实流式的SQL与传统的SQL并不一样,也需要一定的学习成本。
而实际上今天在真实场景下碰到的流计算SQL并不是全新的逻辑,往往在原来有对应的非流式的处理逻辑存在。下图中传统的SQL的背后可能是这样的一个非常复杂的报表系统,老板给你的要求实际上可能是这样的,实时流式计算能不能帮助降低延时,实时地产生数据,让老板时时刻刻看到报表的变化,这样就是一个非常自然的从原来离线的报表实时化的场景。如果现有一个离线的SQL,如何使其实时化呢?其实一种做法是学习新的SQL进行改写,这种方法是有可能实现的,而且在很多时候也是一个比较好的做法,那么有没有更好的做法呢?
其实再分析一下这个问题就是今天已经有一个离线的SQL,而数据表的数据是有穷的并不是无限的数据,就知道如何在数据集上进行计算。如果数据是一点点流式增加的,想要实现老板的需求其实是非常简单的,在每次数据增加完就运行一次SQL就可以了,这样就能够将中间结果以报表的形式让老板实时地看到了。这样看上去就是一个流式计算的过程,但实际上在背后其实在不断地运行离线的SQL,每次前面和后面的数据出现差异也就是增加了一些新的数据时就再运行一次离线SQL。这一页其实想要讲的做法就是从离线的计算变到实时计算是可以通过递进式的增量计算实现的。
那么这样做有什么好处呢?首先大家不必再学习新的SQL语言了,可以直接使用离线的SQL表达处理逻辑。只是需要将报表随着数据的到达不断地变化就可以了,这就是实时计算,不需要继续再写程序。其实这样做就像下图中的漫画一样,流式增量计算可以产生中间的每一幅画,但是因为数据是递增到达的,如果每到一个数据就执行SQL就可以将漫画中的过程生动地展现出来,这对于很多的商业决策是非常有帮助的。但是这其中存在着很大的技术挑战,就是如果真的这样去做,虽然不用写程序,但是计算量却是非常高的,因为每到一个数据就需要进行重新计算,就好像漫画中的每一幅都是需要人工画出来,工作量就比原来只画一幅画多了很多倍,所以今天面对的技术挑战就是如果允许自动增量化地计算SQL,怎样让计算机尽可能避免冗余地实现增量计算,如何将此过程的代价降到最低也就是我们需要面对的技术问题。以上就是解决流计算编程问题的一个新的思路,即可以用离线计算的思维去描述流计算,将复杂的任务交给系统进行处理。
对于这里提到的系统,其实阿里云有一个正处于公测期间的阿里云流计算系统,它提供了SQL描述程序,并提供了非常易用的IDE可以供开发者编写SQL并使其以流式形式运行起来,开发者还可以在IDE中进行调试和监控运维等工作,计算的结果会根据数据的流式输入不断更新结果,并且阿里云流计算系统在背后也做的许多的优化,所以消耗的资源比较少,而且不再需要学习新的语言。
阿里云流计算系统在阿里内部被证明是非常有用的,因为阿里原来在包括电商和离线的数据分析中积累的大量的离线SQL,所以可以回到双11大屏上显示的数据实际上就是采用这样的增量计算的方式产生的,实际上是将最终的报表的SQL分析变成实时的数据报表。而其实系统面临着许多的挑战,虽然大家看到的只是几个数据加起来,但是其实在背后可能使用了成百上千台机器,峰值的时候需要面对达到每秒1亿次事件的处理,然后进行各种聚合所带来的挑战。
接下来分享一下除了流式编程问题以及目前能够看到的问题以外的一些展望。未来,实时化是一个大趋势,以后会有越来越多的实时流数据计算的场景。实际上语言和编程是最难的课题,虽然系统已经很难了,但是语言和编程是比系统还难的课题,需要有足够的经验和场景才能够总结某一方面的东西。今天分享的时序和流式SQL以及增量计算可能适应某一类场景,但是随着对于应用理解的深入会产生进一步的改进。流式计算之后会更多地使用到包括实时语音、图像和视频监测、在线机器学习、智能分析以及物联网的很多场景中,很多时候大家接触的大规模的实时计算可能需要处理的是海量的数据流,数据总量是海量的,而且用户的查询逻辑也可能是海量的,特别是物联网和用户使用的手机可以自定义想要关心的结果,每个人其实都可以放一个流查询在云端运行,处理成千百万的查询,而如何把这些查询尽可能做的高效还存在着很多系统的挑战。
在最后总结部分就是想和大家分享大规模流式计算可能是大数据应用的一个突破点,这里面可能是机会与挑战并存的。机会就是这其中存在着很多的场景,实际上随着对于场景理解的深入,从系统的设计以及底层的语言上面可能有很多的机会和需求要进行重新考虑,当然阿里巴巴会将很多东西不断地放在云上作为云服务,让大家不断尝试,也希望能够得到大家的反馈更好地指导下一步该怎样走。另外就是需要深入领域,和领域相关的专家进行合作,结合真实的场景解决真实的问题。最后还想谈一谈,在阿里云,我们始终拥抱技术的发展趋势,也期待在这个领域中和大家一起通过技术和应用创新向大数据要更多的红利。