大数据系统的Lambda架构

在大数据处理系统中,如何有效地将real time与batch job结合起来,既发挥前者对响应的实时性,又能解决对海量数据的分析与处理?答案就是Lambda架构思想。

Mathan 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。

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

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

如果数据系统通过查找过去的数据去回答问题,则通常需要访问整个数据集。因此可以给data system的最通用的定义: Query = function(all data)

一个大数据系统必须具备的属性包括:

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

Lambda架构

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

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

一个解决方式是预运算查询函数(precomputed query funciton)。Mathan Marz将这种预运算查询函数称之为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架构,一旦数据通过batch layer进入到serving layer,在realtime view中的相应结果就不再需要了。

原文发布于微信公众号 - 逸言(YiYan_OneWord)

原文发表时间:2015-10-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT大咖说

容器化RDS|计算存储分离架构下的 IO 优化

摘要 在基于 Kubernetes 和 Docker 构建的私有 RDS 中,普遍采用了计算存储分离架构。该架构优势明显, 但对于数据库类 Latency Se...

3178
来自专栏Linyb极客之路

分布式系统基础理论之CAP理论

一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中...

772
来自专栏杨建荣的学习笔记

Oracle主备架构下的逻辑备份考虑

今天想到一个问题,如果有一个环境是一主一备架构,根据业务需要做逻辑备份,该怎么规划和考虑。数据库版本为10g,11g ? 这个问题如果在考虑性能的前提下,我...

3415
来自专栏无题

mongoDB运作原理与分片实现

觉得这一篇整理比较好,主要在于通俗易懂,逻辑清晰。但是网上转载的人太多了,我实在找不到原作者了。 关于MongoDB,我们能看到的资料,基本都是在指导大家如何使...

2944
来自专栏腾讯云数据库团队的专栏

Greenplum 简单性能测试与分析

通过TPC-H基准测试,可获得数据库单位时间内的性能处理能力,为评估数据库系统的现有性能服务水平提供有效依据。

72512
来自专栏CSDN技术头条

如何学习分布式系统?一文全Get!

image.png 本文来自作者在GitChat(ID:GitChat_Club)上分享「如何学习分布式系统?」,CSDN独家合作发布。 分布式系统在互联网公...

3319
来自专栏杨建荣的学习笔记

海量数据迁移之通过shell估算数据量 (r2笔记93天)

在数据迁移的时候,需要根据用户量来评估需要在表空间理添加的空间大小。比如迁移5百万的用户和迁移200万,两者需要添加的数据量差别很大,在资源有限的情况下,需要一...

2352
来自专栏ImportSource

NoSQL-Master-Slave Replication 主从复制

翻译内容: NoSQL Distilled 第四章 Distribution Models 作者简介: ? 本节摘要: 各位好,今天我们主要讨...

4436
来自专栏CSDN技术头条

容器化RDS|计算存储分离架构下的IO优化

在基于 Kubernetes 和 Docker 构建的私有 RDS 中,普遍采用了计算存储分离架构。该架构优势明显, 但对于数据库类 Latency Sensi...

2376
来自专栏鸿的学习笔记

聊聊分布式系统的时钟问题

诸如此类的问题,还能提出很多,因此需要一个靠谱的时钟来保证分布式系统里事件的处理不会出错。

571

扫描关注云+社区