大数据系统的Lambda架构

作者: _张逸_ | 来源:发表于2016-06-27 19:31 被阅读2248次

    Nathan Marz的大作Big Data: Principles and best practices of scalable real-time data systems介绍了Labmda Architecture的概念,用于在大数据架构中,如何让real-time与batch job更好地结合起来,以达成对大数据的实时处理。

    传统系统的问题

    在传统数据库的设计中,无法很好地支持系统的可伸缩性。当用户访问量增加时,数据库无法满足日益增长的用户请求负载,从而导致数据库服务器无法及时响应用户请求,出现超时错误。

    解决的办法是在Web服务器与数据库之间增加一个异步处理的队列。如下图所示:

    引入队列

    当Web Server收到页面请求时,会将消息添加到队列中。在DB端,创建一个Worker定期从队列中取出消息进行处理,例如每次读取100条消息。这相当于在两者之间建立了一个缓冲。

    但是,这一方案并没有从本质上解决数据库overload的问题,且当worker无法跟上writer的请求时,就需要增加多个worker并发执行,数据库又将再次成为响应请求的瓶颈。一个解决办法是对数据库进行分区(horizontal partitioning或者sharding)。分区的方式通常以Hash值作为key。这样就需要应用程序端知道如何去寻找每个key所在的分区。

    问题仍然会随着用户请求的增加接踵而来。当之前的分区无法满足负载时,就需要增加更多分区,这时就需要对数据库进行reshard。resharding的工作非常耗时而痛苦,因为需要协调很多工作,例如数据的迁移、更新客户端访问的分区地址,更新应用程序代码。如果系统本身还提供了在线访问服务,对运维的要求就更高。稍有不慎,就可能导致数据写到错误的分区,因此必须要编写脚本来自动完成,且需要充分的测试。

    即使分区能够解决数据库负载问题,却还存在容错性(Fault-Tolerance)的问题。解决办法:

    • 改变queue/worker的实现。当消息发送给不可用的分区时,将消息放到“pending”队列,然后每隔一段时间对pending队列中的消息进行处理。
    • 使用数据库的replication功能,为每个分区增加slave。

    问题并没有得到完美地解决。假设系统出现问题,例如在应用系统代码端不小心引入了一个bug,使得对页面的请求重复提交了一次,这就导致了重复的请求数据。糟糕的是,直到24小时之后才发现了该问题,此时对数据的破坏已经造成了。即使每周的数据备份也无法解决此问题,因为它不知道到底是哪些数据受到了破坏(corrupiton)。由于人为错误总是不可避免的,我们在架构时应该如何规避此问题?

    现在,架构变得越来越复杂,增加了队列、分区、复制、重分区脚本(resharding scripts)。应用程序还需要了解数据库的schema,并能访问到正确的分区。问题在于:数据库对于分区是不了解的,无法帮助你应对分区、复制与分布式查询。最糟糕的问题是系统并没有为人为错误进行工程设计,仅靠备份是不能治本的。归根结底,系统还需要限制因为人为错误导致的破坏。

    数据系统的概念

    大数据处理技术需要解决这种可伸缩性与复杂性。首先要认识到这种分布式的本质,要很好地处理分区与复制,不会导致错误分区引起查询失败,而是要将这些逻辑内化到数据库中。当需要扩展系统时,可以非常方便地增加节点,系统也能够针对新节点进行rebalance。

    其次是要让数据成为不可变的。原始数据永远都不能被修改,这样即使犯了错误,写了错误数据,原来好的数据并不会受到破坏。

    何谓“数据系统”?Nathan Marz认为:

    如果数据系统通过查找过去的数据去回答问题,则通常需要访问整个数据集。

    因此可以给data system的最通用的定义:

    Query = function(all data)
    

    接下来,本书作者介绍了Big Data System所需具备的属性:

    • 健壮性和容错性(Robustness和Fault Tolerance)
    • 低延迟的读与更新(Low Latency reads and updates)
    • 可伸缩性(Scalability)
    • 通用性(Generalization)
    • 可扩展性(Extensibility)
    • 内置查询(Ad hoc queries)
    • 维护最小(Minimal maintenance)
    • 可调试性(Debuggability)

    Lambda架构

    Lambda架构的主要思想就是将大数据系统构建为多个层次,如下图所示:

    lambda layer

    理想状态下,任何数据访问都可以从表达式Query = function(all data)开始,但是,若数据达到相当大的一个级别(例如PB),且还需要支持实时查询时,就需要耗费非常庞大的资源。

    一个解决方式是预运算查询函数(precomputed query funciton)。书中将这种预运算查询函数称之为Batch View,这样当需要执行查询时,可以从Batch View中读取结果。这样一个预先运算好的View是可以建立索引的,因而可以支持随机读取。于是系统就变成:

    batch view = function(all data)
    query = function(batch view)
    

    Batch Layer

    在Lambda架构中,实现batch view = function(all data)的部分被称之为batch layer。它承担了两个职责:

    • 存储Master Dataset,这是一个不变的持续增长的数据集
    • 针对这个Master Dataset进行预运算

    显然,Batch Layer执行的是批量处理,例如Hadoop或者Spark支持的Map-Reduce方式。 它的执行方式可以用一段伪代码来表示:

    function runBatchLayer():
      while (true):
        recomputeBatchViews()
    

    例如这样一段代码:

    Api.execute(Api.hfsSeqfile("/tmp/pageview-counts"),
         new Subquery("?url", "?count")
             .predicate(Api.hfsSeqfile("/data/pageviews"),
                 "?url", "?user", "?timestamp")
             .predicate(new Count(), "?count");
    

    代码并行地对hdfs文件夹下的page views进行统计(count),合并结果,并将最终结果保存在pageview-counts文件夹下。

    利用Batch Layer进行预运算的作用实际上就是将大数据变小,从而有效地利用资源,改善实时查询的性能。但这里有一个前提,就是我们需要预先知道查询需要的数据,如此才能在Batch Layer中安排执行计划,定期对数据进行批量处理。此外,还要求这些预运算的统计数据是支持合并(merge)的。

    Serving Layer

    Batch Layer通过对master dataset执行查询获得了batch view,而Serving Layer就要负责对batch view进行操作,从而为最终的实时查询提供支撑。因此Serving Layer的职责包含:

    • 对batch view的随机访问
    • 更新batch view

    Serving Layer应该是一个专用的分布式数据库,例如Elephant DB,以支持对batch view的加载、随机读取以及更新。注意,它并不支持对batch view的随机写,因为随机写会为数据库引来许多复杂性。简单的特性才能使系统变得更健壮、可预测、易配置,也易于运维。

    Speed Layer

    只要batch layer完成对batch view的预计算,serving layer就会对其进行更新。这意味着在运行预计算时进入的数据不会马上呈现到batch view中。这对于要求完全实时的数据系统而言是不能接受的。要解决这个问题,就要通过speed layer。从对数据的处理来看,speed layer与batch layer非常相似,它们之间最大的区别是前者只处理最近的数据,后者则要处理所有的数据。另一个区别是为了满足最小的延迟,speed layer并不会在同一时间读取所有的新数据,相反,它会在接收到新数据时,更新realtime view,而不会像batch layer那样重新运算整个view。speed layer是一种增量的计算,而非重新运算(recomputation)。

    因而,Speed Layer的作用包括:

    • 对更新到serving layer带来的高延迟的一种补充
    • 快速、增量的算法
    • 最终Batch Layer会覆盖speed layer

    Speed Layer的等式表达如下所示:

    realtime view = function(realtime view, new data)
    

    注意,realtime view是基于新数据和已有的realtime view。

    总结下来,Lambda架构就是如下的三个等式:

    batch view = function(all data)
    realtime view = function(realtime view, new data)
    query = function(batch view . realtime view)
    

    整个Lambda架构如下图所示:

    lambda architecture

    基于Lambda架构,一旦数据通过batch layer进入到serving layer,在realtime view中的相应结果就不再需要了。

    相关文章

      网友评论

      • 我在睡觉:没看出来如何解决大量并发写问题
        六爷1_1:总结得很干净,32个赞!同意对写的解读。基于Lambda的数据,默认是被清洗(并索引)过的。
        我在睡觉:@逸見 了解了
        _张逸_:@我在睡觉
        个人看法,大数据分析基本上不解决数据写问题,或者说写数据不是数据分析的范畴,而是属于数据采集的问题。数据采集同样可以分为batch与streaming两种方式,例如可以利用sqoop之类的工具将RDB中的数据同步到hdfs;至于streaming,就可以利用类似Kafka以接近实时的方式把数据以消息形式写到kafka中,然后用streaming去订阅,最后进行数据分析。

        labmda架构解决的是数据分析,分析行为主要集中在数据读,即查询、聚合运算等。

      本文标题:大数据系统的Lambda架构

      本文链接:https://www.haomeiwen.com/subject/nlozdttx.html