流数据的迅速崛起带来了一类全新的应用开发技术。为了应对不断增长的数据(如物联网和机器通信产生的大量数据),同时,利用实时个性化技术改进在线用户体验,越来越多的应用开发引入了流数据技术。对于流数据应用的定义多种多样,但都包含三个基本功能:实时数据采集,实时分析和自动化决策。
流处理的解决方案也可以采取多种形式。通常其体系结构包含:tuple-at-a-time流处理工具(又名复杂事件处理工具);面向批处理的流处理技术,是对灵活性和健壮性的折中方案;内存数据库,强调业务的实时性。虽然这些方法可以解决许多问题,但是就开发量、维护开销、存储容量、性能而言,这些方法存在很大差异。需要注意的是,了解需要用多少组件来实现你需要的功能是十分重要的。开发、测试、运营一个系统的工作量取决于需要整合在一起的组件的数量。
举个例子:Apache Stor m 是最流行的为开发者用于流式应用的工具之一,但是一个使用storm的流式处理方案通常不仅仅需要storm。正如我在 上一篇文章 中讨论到的,Storm通常使用Kafka用于数据采集,而Storm和Kafka都需要Zookeeper用于管理状态。最后,如我下面讨论到的,还需要第四个系统用于管理状态。最终,当所有工作完成后,一个3结点(指计算节点)的Storm集群会很轻易地掉消耗12个结点!
Apache Storm 是一个能近实时地在数据之上运行用户代码片段的流式数据处理框架。它实际上是一系列连在一起的管道。本质上开发者在运行中间部分(指Storm的管道)的代码时,他们将输入数据源和后端数据存储连接起来。Storm的 延时 比基于Hadoop的系统更接近CEP(复杂事件处理)。它提供的通过书写简单代码处理事件,将更多背景交给框架处理的特性,对于有时间修修补补的开发者来说很有吸引力。
Storm 通常用于简单的分析任务 ,诸如计算,以及清洗,使其常规化,并且准备摄入用于长期存储的数据。然而,Storm 不能够有状态操作,这对于进行实时决策非常重要。状态数据的分析正处于快速数据应用程序的中心,诸如:个性化,客户参与,推荐引擎,报警,授权与政策执行。无需诸如 Zookeeper与 Cassandra 之类的额外组件,Storm 不能查找维度数据,更新汇总,或者直接作用于一个事件(那就是,对实时进行决策)。
这些实例就是一个更广泛有关“快”的数据应用程序的类的一部分。开发人员意识到认识的价值和作用于实时数据,并且快速的数据工具正充实着简单的流媒体方式和传统的分析卖场实现价值。考虑问题并且不涉及技术,什么是一个快速应用程序共同的主题呢?
首先,它们都要读入数据,比如日志记录,传感器记录,财务票据,点击流,在线行为触发等等。这些数据来得比消防龙头喷的水还快,快速数据处理系统必须要能流畅读入这些数据。
然后就是实时解析读入进来的数据。在这之前,某些系统可以读入一个流然后提交给 OLAP 系统处理,这样的处理有可能耗时过长,起不到实时的作用。而快速数据处理系统则通过事件模型来处理读入数据,同时拉取已有数据(比方维度表或历史表)来进行处理。系统可以将信息展示出来或发送一个提醒,让相关的人员来做决定;但更合适的做法是让系统自动 来 处理——比如“当X类型的用户满足Y条件时,执行策略Z”。
最后,快速数据处理要和大数据相集成。我们有一个基础假设,就是数据都是有生命周期的。实时数据交给快速数据处理系统来处理,而像机器学习、回归测试和历史查询这样的深度分析,则交给 OLAP 或基于 Hadoop/HDFS 的系统去做。这种情况下,快速数据处理系统不但将扩充后的数据提交给深度分析系统,同时也接收深度分析系统的处理结果,比如规则学习引擎生成的一条规则。
要想理解 Storm 在整个快速数据处理系统中的角色,最简单的就是看它自身能处理哪些问题,以及它把哪些问题丢给开发者解决。Storm 框架的设计目标是以一种可以自由水平扩展并具有一定容错性的方式,将数据从数据源提交给用户处理。它对于输入数据可以是“最多一次”或“最少一次”的处理方式,如果处理失败,它也可以再度重试。
对持久化状态的认识明显是不足的。由于各种各样的原因,高速数据应用需要对状态进行记录。保留之前看到的元组信息,可以是未经处理的生数据,也可以是经过聚合的数据,都能够帮助处理引擎找到数据中蕴藏的模式。在进行任何分析之前,获取更多维度的数据有助于丰富这些元组数据,来进行更广泛的概括和分析。通常来说,最终决策取决于这些持久储存的动态规则。
Storm在这个问题上失误了,它让开发者自己管理对持久状态的访问。在Storm中有两种访问持久状态的方法。第一种是,在Storm中每个工作过程都能够通过增加本地第三方存储来存储自己的状态。Memcached和Redis是如今非常流行的本地存储解决方案。增加本地存储使得每个状态的数据元组能够顾忌之前的数据元组,这样,整个工作过程就变得一目了然了。但是这种“自我构建”的方法有它的负面效果:它无法集成到Storm的容错代码机制当中。Storm必须通过在一个正在运行的机器上重启工作过程并将数据元组从之前的作业迁移到新的工作过程中,来处理运行失败的工作过程或出错的硬件问题。这种迁移不包含任何本地状态,无论它是驻留在这个过程中,还是在像Memcached这样的系统中。新的工作过程将失去失败作业中所有的上下文信息。
并且,也很难甚至不可能直接查询那些分散在所有工作进程中的分布式状态。如果每个进程想要一直聚集统计,这些统计数据必须推到另一个系统,使用强大查询工具进行查询。使用Storm的分布式RPC(远程过程调用)功能来对一些数据进行直接抓取也许是可行的。但是,与如今的SQL和NoSQL数据存储技术的查询功能相比,这些数据获取的功能被严格限制了。
第二种访问状态的方法是将Storm的工作进程连接到一个集中式的或者分布式的持久化存储当中,例如Cassandra或HBase。采用这种方法,Storm的处理代码能够访问GB或者TB级别的状态信息,并且能够简单地、独立地从Storm系统中查询持久化存储的数据。这解决了本地化存储的如上问题:状态不能在唤醒失败进程后重建,并且存储可能以后将要支持更强大的查询。虽然该方法解决了这些问题,但它大大增加了复杂性,并带来了可靠性的问题。
值得注意的是,Storm 与分离存储结合可能会削弱性能。在内存中处理元组是很容易达到以惊人的速度。为了方便查询冗余状态而使用索引来维护其存储,同时尽可能提供一致性保证,要付出更多的代价。Storm 系统将被分布式存储的性能所制约。如果处理每个元组时使用外部存储来查询,会造成大量的网络延迟。隐藏这种延迟需要更多的并行性,更多的管理,意味着更多的复杂性。而现在你可能会有两个系统可能失败。
当分布式存储不可用时,Storm 的工作进程需要处理,这无疑增加来了复杂性。如果这是可能的,即使没有复杂的用户代码,当在 Storm 中使用至少一次语义的时候,开发着也需要在分布式存储中使用至少一次语义。
在当今的存储中,兼容ACID,SQL关系型数据库能够比Sorm和其它可代替产品更简单和容易地运行以前不能运行的应用。伴有ACID事务关系型数据库简化数据获取在至多一次或至少一次语义的的时候是有要求的。因为操作是简单的,要么完全完成或回滚。
大多数关系型数据库允许数据库托管,事务逻辑:一些甚至允许使用java代码,像Storm。因此,Storm在使用关系型的系统中提供更多的逻辑与灵活性。但是不像在Storm中,在一个有着直接并且精心安排的路径状态数据的关系型数据库中,消除出现在混合Storm和一个分布或分区的持久性存储中问题。
既然已经有了像PostgreSQL这种数据库存储系统,Nathan Marz为什么要创造Storm呢?因为PostgreSQL及其分支既不 是横向可扩展的,也没有像Storm那样处理元组数据的吞吐量。但是最近五年 一些新的项目进入事务性存储领域,致力于横向扩展、容错和原始吞吐量。这些系统方案有着和Storm一样的扩展性和容错性,并在处理时结合直接的状态操作提供了强大的处理事务语义的功能。
总之, 这些新平台提供了Storm的处理流程和逻辑,Cassandra的状态能力,Kafka的摄入语义等。 更重要的是,一个分布式的,事务性的(ACID),SQL关系型数据库 能够每秒处理成千上万个输入的事务或应用请求。
对于数据快速增长的应用,开发者们仍在寻求一个比 Storm 和其他流处理方案更完整的流处理平台。Storm 需要一个伙伴数据库去处理它所产出的任何分析内容。相比之下,对比已经有一定规模的SQL数据库,开发者可以从数据库中直接进行计算、存储并做实时的查询分析。
Storm 的数据提取管道中的过滤器,enrich 以及组输入事件流都需要访问查找数据以及额外的输入事件源。Storm 需要伙伴数据库来进行数据的存储和查找。不符合开发者们数据快速增长应用的需求。一个分布式、内存型的关系数据库提供了一套更适用于数据快速增长场景下的更简单、强大、互动性的解决案例。
John Hugg,VoltDB 的高级架构师,工作生涯主要致力于数据库和信息管理。做为VoltDB产品化的第一个工程师,他联络着麻省理工学院的学者、耶鲁大学的团队、H-Store 以及 VoltDB 的研究原型。John 还帮助 VoltDB 建立了世界一流的工程团队继续开发开源和商业产品。