从单体到Flink:一文读懂资料架构的演变
导读:近年来随着开源社群的发展,越来越多新的技术被开源,例如雅虎的Hadoop分散式计算框架、UC伯克利分校的Apache Spark等,而伴随着这些技术的发展,促使著企业资料架构的演进,从传统的关系型资料储存架构,逐步演化为分散式处理和储存的架构。
作者:张利兵
首发于过往记忆大资料

01 传统资料基础架构
如图1-1所示,传统单体资料架构(Monolithic Architecture)最大的特点便是集中式资料储存,企业内部可能有诸多的系统,例如Web业务系统、订单系统、CRM系统、ERP系统、监控系统等,这些系统的事务性资料主要基于集中式的关系性数据库(DBMS)实现储存,大多数将架构分为计算层和储存层。储存层负责企业内系统的资料访问,且具有最终资料一致性保障。这些资料反映了当前的业务状态,例如系统的订单交易量、网站的活跃使用者数、每个使用者的交易额变化等,所有的更新操作均需要借助于同一套数据库实现。
▲图1-1 传统资料结构
单体架构的初期效率很高,但是随着时间的推移,业务越来越多,系统逐渐变得很大,越来越难以维护和升级,数据库是唯一的准确资料来源,每个应用都需要访问数据库来获取对应的资料,如果数据库发生改变或者出现问题,则将对整个业务系统产生影响。
后来随着微服务架构(Microservices Architecture)的出现,企业开始逐渐采用微服务作为企业业务系统的架构体系。微服务架构的核心思想是,一个应用是由多个小的、相互独立的微服务组成,这些服务执行在自己的程序中,开发和释出都没有依赖。不同的服务能依据不同的业务需求,构建的不同的技术架构之上,能够聚焦在有限的业务功能。
▲图1-2 微服务架构
如图1-2所示,微服务架构将系统拆解成不同的独立服务模组,每个模组分别使用各自独立的数据库,这种模式解决了业务系统拓展的问题,但是也带来了新的问题,那就是业务交易资料过于分散在不同的系统中,很难将资料进行集中化管理。
对于企业内部进行资料分析或者资料探勘之类的应用,则需要通过从不同的数据库中进行资料抽取,将资料从数据库中周期性地同步到资料仓库中,然后在资料仓库中进行资料的抽取、转换、载入(ETL),从而构建成不同的资料集市和应用,提供给业务系统使用。
02 大资料资料架构
起初资料仓库主要还是构建在关系型数据库之上,例如Oracle、Mysql等数据库,但是随着企业资料量的增长,关系型数据库已经无法支撑大规模资料集的储存和分析,因此越来越多的企业开始选择基于Hadoop构建企业级大资料平台。同时众多Sql-On-Hadoop技术方案的提出,也让企业在Hadoop上构建不同型别的资料应用变得简单而高效,例如通过使用Apache Hive进行资料ETL处理,通过使用Apache Impala进行实时互动性查询等。
大资料技术的兴起,让企业能够更加灵活高效地使用自己的业务资料,从资料中提取出更多重要的价值,并将资料分析和挖掘出来的结果应用在企业的决策、营销、管理等应用领域。但不可避免的是,随着越来越多新技术的引入与使用,企业内部一套大资料管理平台可能会借助众多开源技术元件实现。
例如在构建企业资料仓库的过程中,资料往往都是周期性的从业务系统中同步到大资料平台,完成一系列ETL转换动作之后,最终形成资料集市等应用。但是对于一些时间要求比较高的应用,例如实时报表统计,则必须有非常低的延时展示统计结果,为此业界提出一套Lambda架构方案来处理不同型别的资料。
例图1-3所示,大资料平台中包含批量计算的Batch Layer和实时计算的Speed Layer,通过在一套平台中将批计算和流计算整合在一起,例如使用Hadoop MapReduce进行批量资料的处理,使用Apache Storm进行实时资料的处理。
这种架构在一定程度上解决了不同计算型别的问题,但是带来的问题是框架太多会导致平台复杂度过高、运维成本高等。在一套资源管理平台中管理不同型别的计算框架使用也是非常困难的事情。总而言之,Lambda架构是构建大资料应用程序的一种很有效的解决方案,但是还不是最完美的方案。
▲图1-3 大资料Lambada架构
后来随着Apache Spark的分散式内存处理框架的出现,提出了将资料切分成微批的处理模式进行流式资料处理,从而能够在一套计算框架内完成批量计算和流式计算。
但因为Spark本身是基于批处理模式的原因,并不能完美且高效地处理原生的资料流,因此对流式计算支援的相对较弱,可以说Spark的出现本质上是在一定程度上对Hadoop架构进行了一定的升级和优化。
03 有状态流计算架构
资料产生的本质,其实是一条条真实存在的事件,前面提到的不同的架构其实都是在一定程度违背了这种本质,需要通过在一定时延的情况下对业务资料进行处理,然后得到基于业务资料统计的准确结果。实际上,基于流式计算技术局限性,我们很难在资料产生的过程中进行计算并直接产生统计结果,因为这不仅对系统有非常高的要求,还必须要满足高效能、高吞吐、低延时等众多目标。
而有状态流计算架构(如图1-4所示)的提出,从一定程度上满足了企业的这种需求,企业基于实时的流式资料,维护所有计算过程的状态,所谓状态就是计算过程中产生的中间计算结果,每次计算新的资料进入到流式系统中都是基于中间状态结果的基础上进行运算,最终产生正确的统计结果。
基于有状态计算的方式最大的优势是不需要将原始资料重新从外部储存中拿出来,从而进行全量计算,因为这种计算方式的代价可能是非常高的。从另一个角度讲,使用者无须通过排程和协调各种批量计算工具,从资料仓库中获取资料统计结果,然后再落地储存,这些操作全部都可以基于流式计算完成,可以极大地减轻系统对其他框架的依赖,减少资料计算过程中的时间损耗以及硬件储存。
▲图1-4 有状态计算架构
如果计算的结果能保持一致,实时计算在很短的时间内统计出结果,批量计算则需要等待一定时间才能得出,相信大多数使用者会更加倾向于选择使用有状态流进行大资料处理。
04 为什么会是Flink
可以看出有状态流计算将会逐步成为企业作为构建资料平台的架构模式,而目前从社群来看,能够满足的只有Apache Flink。Flink通过实现Google Dataflow流式计算模型实现了高吞吐、低延迟、高效能兼具实时流式计算框架。同时Flink支援高度容错的状态管理,防止状态在计算过程中因为系统异常而出现丢失,Flink周期性地通过分散式快照技术Checkpoints实现状态的持久化维护,使得即使在系统停机或者异常的情况下都能计算出正确的结果。
Flink具有先进的架构理念、诸多的优秀特性,以及完善的程式设计界面,而Flink也在每一次的Release版本中,不断推出新的特性,例如Queryable State功能的提出,容许使用者通过远端的方式直接获取流式计算任务的状态资讯,资料不需要落地数据库就能直接从Flink流式应用中查询。对于实时互动式的查询业务可以直接从Flink的状态中查询最新的结果。
在未来,Flink将不仅作为实时流式处理的框架,更多的可能会成为一套实时的状态储存引擎,让更多的使用者从有状态计算的技术中获益。

Flink的具体优势有以下几点。
1. 同时支援高吞吐、低延迟、高效能
Flink是目前开源社群中唯一一套集高吞吐、低延迟、高效能三者于一身的分散式流式资料处理框架。像Apache Spark也只能兼顾高吞吐和高效能特性,主要因为在Spark Streaming流式计算中无法做到低延迟保障;而流式计算框架Apache Storm只能支援低延迟和高效能特性,但是无法满足高吞吐的要求。而满足高吞吐、低延迟、高效能这三个目标对分散式流式计算框架来说是非常重要的。
2. 支援事件时间(Event Time)概念
在流式计算领域中,视窗计算的地位举足轻重,但目前大多数框架视窗计算采用的都是系统时间(Process Time),也是事件传输到计算框架处理时,系统主机的当前时间。
Flink能够支援基于事件时间(Event Time)语义进行视窗计算,也就是使用事件产生的时间,这种基于事件驱动的机制使得事件即使乱序到达,流系统也能够计算出精确的结果,保持了事件原本产生时的时序性,尽可能避免网络传输或硬件系统的影响。
3. 支援有状态计算
Flink在1.4版本中实现了状态管理,所谓状态就是在流式计算过程中将算子的中间结果资料储存在内存或者档案系统中,等下一个事件进入算子后可以从之前的状态中获取中间结果中计算当前的结果,从而无须每次都基于全部的原始资料来统计结果,这种方式极大地提升了系统的效能,并降低了资料计算过程的资源消耗。
对于资料量大且运算逻辑非常复杂的流式计算场景,有状态计算发挥了非常重要的作用。
4. 支援高度灵活的视窗(Window)操作
在流处理应用中,资料是连续不断的,需要通过视窗的方式对流资料进行一定范围的聚合计算,例如统计在过去的1分钟内有多少使用者点选某一网页,在这种情况下,我们必须定义一个视窗,用来收集最近一分钟内的资料,并对这个视窗内的资料进行再计算。
Flink将视窗划分为基于Time、Count、Session,以及Data-driven等型别的视窗操作,视窗可以用灵活的触发条件定制化来达到对复杂的流传输模式的支援,使用者可以定义不同的视窗触发机制来满足不同的需求。
5. 基于轻量级分散式快照(Snapshot)实现的容错
Flink能够分散式执行在上千个节点上,将一个大型计算任务的流程拆解成小的计算过程,然后将tesk分布到并行节点上进行处理。在任务执行过程中,能够自动发现事件处理过程中的错误而导致资料不一致的问题,比如:节点宕机、网络传输问题,或是由于使用者因为升级或修复问题而导致计算服务重启等。
在这些情况下,通过基于分散式快照技术的Checkpoints,将执行过程中的状态资讯进行持久化储存,一旦任务出现异常停止,Flink就能够从Checkpoints中进行任务的自动恢复,以确保资料在处理过程中的一致性。
6. 基于JVM实现独立的内存管理
内存管理是所有计算框架需要重点考虑的部分,尤其对于计算量比较大的计算场景,资料在内存中该如何进行管理显得至关重要。针对内存管理,Flink实现了自身管理内存的机制,尽可能减少JVM GC对系统的影响。
另外,Flink通过序列化/反序列化方法将所有的资料物件转换成二进位制在内存中储存,降低资料储存的大小的同时,能够更加有效地对内存空间进行利用,降低GC带来的效能下降或任务异常的风险,因此Flink较其他分散式处理的框架会显得更加稳定,不会因为JVM GC等问题而影响整个应用的执行。
7. Save Points(储存点)
对于7*24小时执行的流式应用,资料来源源不断地接入,在一段时间内应用的终止有可能导致资料的丢失或者计算结果的不准确,例如进行丛集版本的升级、停机运维操作等操作。
值得一提的是,Flink通过Save Points技术将任务执行的快照储存在储存介质上,当任务重启的时候可以直接从事先储存的Save Points恢复原有的计算状态,使得任务继续按照停机之前的状态执行,Save Points技术可以让使用者更好地管理和运维实时流式应用。
关于作者:张利兵,资深架构师,流式计算领域专家。有多年大资料、流式计算方面的开发经验,对Hadoop、Spark、Flink等大资料计算引擎有着非常深入的理解,积累了丰富的专案实践经验。
本文摘编自《Flink原理、实战与效能优化》,经出版方授权释出。
延伸阅读《Flink原理、实战与效能优化》
推荐语:从功能、原理、实战和调优4个维度循序渐进讲解利用Flink进行分散式流式应用开发,指导读者从零基础入门到进阶。适读人群:流计算开发工程师、大资料架构工程师、大资料开发工程师、资料探勘工程师、高校研究生以及高年级本科生。