大家好,又见面了,我是你们的朋友全栈君。
很多人学习大数据都听说过以下发展进程,MySQL/Oracle/SQLServer → Hadoop/Hive/Spark。但还有一个时期,是大家容易忽略的——NoSQL。我们不能忽略掉它。
其实,NoSQL的发展和推广要比Hadoop更早,在没有Hadoop的大数据过渡期,随着数据量急剧膨胀,大家纷纷从传统的关系型数据库转变到NoSQL数据库,各种各样的NoSQL数据库应用而生。有了NoSQL数据库,可以轻易将机器的数量扩展到上千台。从RDB到NoSQL的转变,有一个重大的改变是数据模型的变化。
也是受限于数据模型,NoSQL有很大的限制,如果要做复杂的数据分析、处理,很难实现。NoQQL能够将数据存下来、取出来,但OLAP很难在NoSQL开展,至今依然是这样的。所以不会有人用HBase、Cassandra、ES去做数据仓库。而是会用它们来做一些OLTP的工作。
而Hadoop的诞生,让对海量数据进行分析变得可行。也就是大数据的OLAP是从Hadoop开始的。至今,很多的计算引擎,依然采用的是Hadoop生态的模型,只不过使用的技术更优越了,速度也变快了。所以,有一种大数据的看法,会认为后续的很多产品,都是Hadoop的衍生物。一些人把这称为这是广义上的Hadoop。
大数据领域有两个先驱,一个是Google,一个是亚马逊。Google开发了分布式文件系统、MapReduce。亚马逊开发了Dynamo分布式key-value存储系统。然后下来就是开源社区,包括:Hadoop、HBase、MongoDB、Cassandra、RabbitMQ以及其他项目。
数据越来越多,关系型数据库在「大数据」的压力下崩溃了。而除了传统数据库,还有其他的一些技术,例如:消息队列、数据库分片等。我们来看看,即使用了这些补救策略,依然解决不了根本问题。而对传统关系型数据库的扩展是大数据的起点。
为了说明问题,给大家举个例子:使用关系型数据库,统计某个网站的点击量。
看起来很美好,但数据库分片无法解决所有问题。如果可以的,就不会有后续的NoSQL、以及Hadoop技术的发展。
所以,每当数据量一达到阈值,就需要重新分片,这就非常难受了。
软件开发中出错是不可避免的,而大数据技术就是要来解决上述的这些问题。分片和副本带来了可扩展性和容错性,数据的不可变特性也很大程度避免了人为原因把好的数据搞乱。
所以,这些组件没有哪个组件是万能的。但如果搭配它们一起来使用,就可以取得不错的效果。绝大多数的大数据系统都是由多个组件组成。而Lambda架构就是将若干组件组合在一起。
提到Lambda架构,就不得不提Nathan Marz(后面我们称他为Marz)。嗯,下面是它的Twitter截图。
他是Red Plant LABS的创始人、Apache Storm项目的创始人。Marz在Backtype(后来Twitter把Backtype收购了)开发了Apache Storm。他也是「Big Data: Principles and best practices of scalable realtime data systems」这本书的作者。这本书没有划水,基本上都是干货。大家也可以看到他是Manning出版社的图书。这本书主要也是围绕Lambda架构来讲解了,建议大家去看英文版本。
Marz也是Lambda Architecture的创始人。他在2011年发布了一篇「如何打破CAP定理」热度非常高。大家有兴趣也可以去看看,下面是链接:http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html。
分布式数据库要保证数据的一致性、避免重复数据、并发等。同时,还要保证数据总是正确的,这会给系统设计带来较大挑战。我们应该尽量避免这种复杂。同时要具备人为容错能力。也就是说需要避免因为人为的失误,而导致数据丢失、数据错误。需要为系统提供重跑数据的能力,能够在人为导致数据错误情况,重新获得正确的数据。同时,保证数据的不可变性,外部程序无法修改数据。
系统能够不影响系统健壮性的同时实现低延迟读取和更新。大家看这些年的技术发展,相信有很多人都想将低延迟读取和更新融合到HDFS中。而其实十几年前就有这样的实践,例如:HBase。虽然,HBase是属于Hadoop生态,但就数据模型、存储引擎来说,HBase做了非常大的调整,只不过在底层,数据仍然是保存在HDFS中,其他的基本上跟HDFS差距非常大。所以,HBase也划入到了NoSQL的阵营。
要让数据系统能够支持各种各样的应用场景,我们是否能够依赖一个组件就能完成所有呢?如果真的可以,那Lambda架构让组件相互协作的方式将会被打破。但目前,其实我们并没有看到在大数据领域中有这样的一款万精油组件。其实,在OLTP系统中,也没有这样的组件。就像我们会用消息队列来进行流量削峰,我们会使用高速缓存在减轻数据库的负载,我们会使用全文检索引擎来加速模糊、关联查询等等。且看IT这么多年的发展,我根本不相信会有这样的组件出现。
说到这里,需要来聊一个比较另类的存储系统——Kudu。虽然Kudu也是一个LSM结构的存储引擎,但它的数据模型看起来像极了关系型模型。但如果用过Kudu就会知道,Kudu本身能够支持的操作非常少,只是它有表的概念、有主键、列的概念。但如果要进行一些类似于关系型的复杂操作,我们得借助于Impala或者是Spark这样的引擎。
Kudu官方也介绍,它是一款介于HDFS、NoSQL之间的存储系统。Kudu也确实实现了能够以低延迟写入、更新以及主键查询。而在OLAP上。但如果用Kudu存储海量的数据、以及进行复杂一点的分析,我们会发现,在OLAP上Kudu还是弱了很多,因为它的结构非常复杂,要兼顾事务、并发、低延迟读写、数据分析,所以,它确实也是一个中间型的产品。维护的成本比较高,资源消耗也会比较大。大规模的数据探索,Kudu有非常大的局限性。而且写放大问题很难解决。这些问题,当在海量数据面前,全部都会暴露出来。
在数据负载增加时,可以通过向系统增加资源来保证性能。可扩展性几乎是数据系统中的必备选项。当然,我们不能排除所有的公司都是这样的。例如:一个公司业务急剧下滑,数据突然急剧减少。这种情况是存在的,但我坚信,如果一个公司出现这样的情况,公司会想办法来降低数据系统的开发、维护成本。而将更多地资源投入到业务中,技术人员的价值也会逐渐衰落。我相信,没有哪个架构师愿意看到这样的局面,更没有哪个架构师会基于这样的场景来去设计系统。
Lambda架构能够保障每个层都可以进行水平扩展,也就是添加更多的机器来实现扩展。水平扩展,是系统扩展的常见方式。而我们基于大数据组件开发的应用,基本上也都是能够水平扩展的。没有人会将一个用于调试的单机系统部署到生产环境中。
当添加新功能或者对系统功能进行调整时,可以对系统进行扩展,并且能够以最小的成本来开发。例如:能够快速地进行数据迁移、格式转换等。统一是目前数据系统建设的重要原则。为减小开发成本,我们在设计之初尽可能地减少架构的复杂度、减少引入不同的存储体系、和计算体系。每当我们添加一个组件、每当我们添加一个模块,都会提升开发成本,开发成本提升了,维护成本也上来了。
要为挖掘数据提供即席查询的能力。即席查询对开发人员、分析人员或者是维护人员都很重要。不要指望在企业中能够让ETL开发工程师提供所有的数据、和计算结果。一个尊重数据的公司,一个谋求发展的公司,不会指望ETL开发工程师能够带来太多的业务创新,以及去发现、解决业务问题。我们需要给这些用户去探索数据的空间。那么AdHoc是必不可少的。
AdHoc的引擎有Presto、Impala等。但AdHoc也不一定就是MPP引擎的独家授权。为了能够更好的管控资源,稳定的性能。Spark、Flink也可以提供有一定延迟的AdHoc。这没有什么问题。毕竟,如果定位用户为分析人员、开发人员、或者维护人员,大多数的场景也都不是毫秒级、秒级的。
选择一个功能实现比较简单,复杂度不高的组件。系统越复杂,出现问题的概率也就越大。维护成本我们需要考虑下公司的运维人员,当我们研发完毕后,要将数据系统的维护移交给运维人员。让他们来完成一些操作。不要指望运维人员的技术能力有多强,我们设计的数据系统就应该能够降低运维门槛。维护成本越低,系统出现故障的概率、人为的错误操作带来的风险,也都会下降。
而Lambda架构可以将复杂性从核心组件推到系统的各个部分。
当出现问题时,能够提供更多的调试信息。能够跟踪系统中的每个值,确切地知道是什么导致问题。可调试性也是需要Lambda架构中保证的,而且能够使用数据重跑的方式重新计算数据。
可调试性在系统的设计中非常关键,但系统出现一些问题时,我们需要重新追数、重新跑数。或者我们想要查找到是在什么时间、什么数据、什么操作下出现的问题。并且能够追溯到每个细节。这就要求在我们设计应用程序(不限于ETL、实时应用等)时,我们需要考虑可调试。我们需要给系统做较多的配套工具,通过工具能够快速发现问题、解决问题。
下面这张图,是一个最简单、也是最高层次的架构抽象:应用基于数据库不断地进行读写操作。
不管是什么系统,应用都是在增量地维护数据库状态。我们日常开发的系统都是基于完全增量来开发的,与具体的实现技术无关,也不管数据模型如何,不管是关系型数据库,或者是非关系型数据库。几十年来,一直都是这样的模式。只不过,大部分人没有感知。还有一些童鞋,一直都觉得自己是在实现增删改查、抽数取数对数中,没有关注到这些。
举个例子,就是写放大问题。例如,缓存存满需要溢写到磁盘,而当溢写到磁盘中的文件达到一定数量时,需要合并这些文件,不然如果要检索这些文件,需要开启过多文件句柄,耗费磁盘IO。与此同时,还需要重建索引,我们无法将继续将数据写入到之前的文件中,直到Compaction完成。Compaction过程会增加磁盘IO、CPU负载。同时,一般为了节省出来一些空间,还需要进行压缩。常见的一般有Snappy、Gzip这样的压缩方式。Compaction过程,因为需要拷贝数据再进行合并,所以也要求磁盘有更多的空间。
如果是数据存储框架当然不想让写放大影响数据系统的可用性。所以,它们肯定会想办法将负载均摊到集群中,也是想尽量降低对节点数据操作的影响。这种操作是有运维工程师来完成的。我之前也听过一个上市公司在介绍他们的HBase一系列的运维活动,相当复杂。
Online Compaction是完全增量架构所固有的。而最近的,Hudi、IceBerg、DeltaLake这类组件。他们将Online Compaction放到了计算引擎中(Spark、Flink)。
CAP定理,在存在网络分区情况下,根本不可能同时实现高可用性和一致性。
所以,在增量、高可用系统要实现最终一致性是很容易出错的。
完全增量系统一旦出现人为失误操作导致的问题容忍度是很低的。既然增量系统,所以数据是不断变化的,所以数据库的状态需要不断保存。如果期间出现了错误,状态就会被改变成为错误的状态。从而导致,后续的所有数据都是错误的。毕竟,增量嘛!Lambda架构在数据准确性、延迟以及吞吐量上表现明显要比完全增量架构要好得多。
在大数据技术领域中,没有单一工具能够解决所有的数据问题。我们必须要使用一系列技术来构建大数据系统。Lambda架构的主要思想是将大数据系统分层。而每一层都能实现一定的功能。Lambda一共分为三层:
Marz提出来一系列的公式来演绎Lambda架构。Marz用一个公式来概括大数据系统:Query = function(all data)。但实现这个操作特别难,因为数据量达到PB级,每次查询需要处理如此大量的数据,几乎是难以完成的。而目前数仓跑批是如何实现的呢?答案是:预计算。提前将一些所需的查询计算好,然后快速查询结果。基于此,公式转变为:
这种查询方式比较典型的就是T+1的离线数仓查询方式。但它也存在问题:
Batch层 + Serving层基本上解决了所有问题,但我们之前提到了,它的延迟很高。因为Batch layer需要处理大规模数据,全部跑完有的需要若干个小时。
Speed层要解决的问题就是数据延迟高的问题。延迟主要在哪儿呢,就是在跑批开始到跑批结束这期间的数据。Lambda架构提到的是,通过一个低延迟的实时系统来补足这个时间段内的数据。它的意义也很明确,就是要尽快地将新的数据对外供数。
加速层和批处理层很大程度上,处理的数据规模不同。加速层只能看到的是最近的数据。每当数据有更新的时候,它仅更新实时视图。不会像批处理一样重新计算。所以,加速层做的是增量计算。
Marz用公式通俗易懂地解释了加速层:
意思是,加速层是基于已经存在的实时视图,和新数据进行增量计算。
Lambda架构还有一个重要特点,每当批处理层的数据进入到服务层后,不再需要实时视图中的数据了,也就是可以丢弃掉。Lambda这三层中,加速层是最复杂的。Lambda架构也旨在隔离复杂性。一旦出现问题,还可以放弃复杂的加速层。可以在几个小时内数据恢复正常。因为有Batch层兜底,所以加速层的数据可以得到修复。毕竟,如果要求加速层的数据100%正确,其实并不是很容易。
最后,引用以下Marz对Lambda架构的说明:
加速层要使用支持随机读取和随机写入的数据库,所以,加速层所使用的存储要比在服务层使用的数据库复杂得多。
参考资料:公众号(Flink)-《说说大数据要知道的Lambda架构》
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/152813.html原文链接:https://javaforall.cn