第1篇:通过流式数据集成实现数据价值(1)
第2篇:通过流式数据集成实现数据价值(2)
第3篇:通过流式数据集成实现数据价值(3)- 实时持续数据收集
第4篇:通过流式数据集成实现数据价值(4)-流数据管道
本篇为通过流式数据集成实现数据价值的第5篇——流处理
流处理的目标是将数据立即转换为目标技术所需的形式。
在某些情况下,使用流集成无需任何流内处理即可将数据从源直接移动到目标。
以下是可能发生这种情况:
- 复制数据库
- 将更改从一个数据库移动到另一个数据库
- 从消息队列读取并将输出原样写入文件
- 将数据从一个文件系统移动到云存储,而无需转换数据
但是,更常见的是,源数据与目标数据结构不匹配。这可能是因为某些源数据需要过滤掉。例如,可能不需要某些事件或事件的字段,因此将其删除。或者某些数据需要混淆,因为其中包含个人身份信息。在交付给目标之前,可能需要添加其他字段。或者,也许出于富集目的,流数据需要与一些参考数据结合在一起。流处理可以对所有收集的数据连续且低延迟地执行所有这些功能。
具有连续查询的基于SQL的流处理
5.1 在内存中
在真正的流集成平台中,需要进行内存中数据处理。 并且该处理需要尽可能高效地执行。
为了实现低延迟和高吞吐量,至关重要的是避免在处理数据之前将数据写入磁盘或使用存储I/O。流处理需要直接在内存中的流式数据上执行,然后再将数据降落到磁盘上 。
进入存储区只有两个原因:
- 写入的目标是基于文件的系统,例如特定的数据库或云存储。
- 使用持久数据流。
流处理还需要根据需要在多个线程(或多个进程和节点)之间并行化,以实现所需的性能。即使在多级数据管道中,中间步骤之间也不应发生磁盘I/O或将数据写入存储的操作。在接收数据和将数据写入目标之间的所有处理都应该在内存中进行,以实现所需的吞吐量。
5.2 持续查询
流架构还需要一个现代的查询范例。对于数据库系统,查询是针对有限的现有数据集运行的。只返回一组数据,仅此而已。要查看随时间变化的查询,您需要一次又一次地运行相同的查询。为了获得更新的结果,您需要重复执行查询。
对于流系统,基于具有特定结构的数据存在的知识来编写单个查询。该查询位于内存中,并等待数据。当数据出现在一个或多个传入数据流上时,该查询将以永无止境的方式持续处理传入数据并输出结果。
实际上,在流处理中发生的内存中的持续查询与过去人们思考查询的方式之间有两个关键的区别。
首先,与驻留在表中的有界且已知的一组数据相反,持续查询处理的是无限的、无限的和无界的数据流。
其次,尽管数据库查询是“一劳永逸的”,但随着新数据出现在传入数据流上,在内存中进行持续查询将不断产生新结果。
与过去的提取、转换和加载(ETL)系统和集成技术不同,后者以批处理为导向,实时流处理系统以24/7的速度连续运行,而这些系统背后的引擎是持续查询。每当新记录出现在数据流上时,查询输出新结果。
重要的是要理解持续查询并不仅限于从数据流中读取数据。它们可以从内存中的缓存,可能已存储的内存中参考数据或通过Windows读取。它们还可以从其他(甚至是永久性的)存储,事件和数据源中读取,具体取决于流系统的体系结构。
重要的是要理解持续查询并不局限于简单地从数据流中读取数据。它们可以从内存缓存中读取数据,也可以从可能已经存储的内存引用数据读取数据,或者通过windows读取数据(稍后将在windows上详细介绍)。它们还可以从其他(甚至是持久性的)存储、事件和数据源读取数据,这取决于流系统的体系结构。
端到端延迟的范围可以从微秒到秒,这取决于需要进行多少处理,而不是批处理ETL解决方案通常需要数小时甚至数天的时间。如前所述,要实现持续产生结果并以非常低的延迟产生结果的目标,查询需要存储在内存中。
5.3 持续查询基于SQL的处理
有许多方法可以处理和操纵数据。我们可以通过脚本语言,Excel电子表格,甚至可以通过用Java,C ,Python或其他某种语言编写代码来做到这一点。
实际上,流处理中有三个选项:
- 低级代码或API
- 基于SQL的处理
- 基于UI的构建块,可以在更高的定义级别执行转换
我们认为,SQL是最好的解决方案–考虑到整体功能、速度和易用性,在其他两个选择之间做出了很大的折衷。我们将在本章中解释原因。
5.3.1 面向用户
首先,通常是从流数据中获取价值的人是数据科学家,数据分析师或业务分析师。
他们都有使用数据库系统的经验,几乎所有人都非常熟悉SQL作为数据处理语言。通过选择SQL作为处理数据的语言,您可以让真正了解数据的人直接使用它,而无需中介 。
SQL也非常丰富。使用WHERE子句定义过滤、定义列转换以及使用case语句执行条件操作都很容易。不同类型的对象可以被连接,也可以被分组、聚合。而对于数据库,通常是连接表,在流中,则要连接流、窗口和缓存以产生结果。在SQL中很容易做到这一点。
当然,SQL是一种高级的声明性语言。因此,为了获得最佳性能,必须将SQL转换为可以在所选的任何流处理平台上执行的高性能代码。如果使用Java,则将SQL转换为高性能Java字节码。这样,您可以兼得两全:SQL的声明性(允许数据专业人员直接处理数据)和高性能,就像开发人员编写了代码一样。
由于以下原因,大多数流技术都向SQL转移:Spark Stream,Kafka和Samsa等提供SQL接口。
5.3.2 基于用户界面的处理
一些流媒体供应商没有提供像SQL这样的声明性语言,而是进入了更高的层次,并通过用户界面(UI)进行所有操作。该UI通常是图形用户界面(GUI),并提供能够执行SQL可以执行的某些操作的转换器组件。鉴于几乎任何用户都可以精通GUI,因此提供这样的界面会使数据的使用更加平民化。
然而,最终的结果是相当长的数据管道。这是因为每个基于GUI的步骤都是作为单独的任务执行的,因为每个转换器都具有非常细粒度的功能。虽然SQL可以通过一条语句(可能使用WHERE子句进行一些过滤和一些连接或列转换)实现其目标,但是需要使用GUI将5个或6个不同的转换器连接在一起。
GUI的好处是,对于任何编程语言(包括SQL)都没有任何经验的人都可以构建转换。但也有不利的一面。首先,没有构建转换经验的人处理关键数据可能不是一件好事。其次,数据管道本身的性能可能会受到影响,因为现在需要很多处理步骤,而不是使用SQL语句执行单个处理步骤。
尽管为管道拥有一个GUI是必要的,但是拥有多个单独的基于UI的转换步骤比一个SQL语句的效率要低。
5.4 多时态
您还记得,任何事情发生时都会创建事件。如果收集了数据,则会生成一个事件。如果您正在从数据库中进行CDC,或者逐行读取文件,或者从IoT设备或消息系统接收数据,则将其分类为事件。每个事件都有进入系统的时间戳。
但是,此类事件可能还会有其他时间因素。例如,对于数据库系统,存在将事件提交到数据库的时间。然后,流系统可能会收到时间戳记。
这两个时间戳可能有所不同,特别是在恢复方案中,在该恢复方案中,数据库系统何时写入和读取数据之间存在差异。通常,至少会有这两个时间戳。它们被视为元数据;即有关您收到的数据的数据。
这些事件将至少是时间性的。但是,数据本身中可能还有其他时序元素值得利用。
5.5 转换
转换是将函数应用于传入数据,转换通常在逐条记录的基础上进行。关键是能够操纵数据,将其转换为所需的形式,将其连接在一起并对其执行功能以产生一些所需的输出。
例如,您可能希望将两个字符串连接在一起,以便可以将名字和姓氏合并为一个全名。
当然,更复杂的功能是可能的,例如涉及SQL中case语句的条件转换,其中,如果特定字段具有特定值,则需要将其与其他字段组合。
5.6 过滤
流处理中的数据流可以任意复杂。例如,它们可能具有拆分或分支。当输出流不需要所有数据输入时,将使用过滤。
5.6.1 过滤以减少数据
进行过滤的一个原因要减少数据。一个简单的示例就是避免处理任何调试日志条目,因为您只对警告或错误消息感兴趣。另一方法是过滤传入的CDC记录,以便它们不包括来自特定数据库用户的输入。在第一种情况下,将过滤数据元素。在第二种情况下,过滤器基于元数据,该元数据包括进行了给定更改的用户,因为您不希望在下游进行这些特定的更改。
当输出流不需要所有传入数据时,使用流内过滤
5.6.2 过滤写入
使用过滤的另一个原因是要确保仅将某些数据写入某些目标。您可能有一个包含大量数据的传入数据流–一个正在进行CDC的大型数据库架构,因此传入数据流包括该架构中所有表的更改。但是,假设您只想在云数据仓库中存储有关产品订单的信息。您不希望将对客户记录的更改或对产品的更改写到此特定的报表实例中,而只是将订单写到该实例中。使用过滤可以解决此需求。
在SQL中,大多数情况下,使用WHERE子句进行过滤。在基于聚合进行过滤的情况下,HAVING子句很有用。
5.6.3 分析
我们还可以将过滤应用于通过分析进行决策。您可以使用分析来确定例如某个事件是否达到或超过了指定的阈值,或者是否生成警报。我们稍后会深入分析。
5.7 窗口
窗口使用首选的条件将无限、无界的传入数据流转换为有限的数据集。然后可以对该数据执行基于集合的操作。窗口的两个主要用途是关联和聚合。有几种类型的窗口。滑动窗口会在新数据传入时或随着时间流逝而改变。每次新记录进入窗口或一段时间后,记录都可以离开窗口。每当窗口更改时,都会触发在该滑动窗口上运行的所有查询。
窗口对于关联和聚合用例至关重要
接下来,我们还有跳跃式窗口或批处理窗口。它们具有确定在输出该数据之前以及从具有窗口数据的触发器触发从该下游窗口读取的查询之前,窗口中需要多少数据的条件。然后清空窗口,准备再次填充。
如果你在滑动窗口上运行一个移动平均线,你会看到一个平滑的移动平均线,而不是一个每隔一分钟就产生一个移动平均线的跳跃/批量窗口。也可以制作混合版本,比如您说,“我不想每次获得新数据时都执行查询,我想每10个事件执行一次查询。”
然后,还有使用时间戳的会话窗口。我们可以这样定义这样的窗口,例如,“保持数据30秒,直到没有新的数据与之对应”。“当客户访问一个网站,并在离开前活跃一段时间,这是很有用的。通过等待直到在指定时间内不做任何其他事情来分组它们的所有活动可以触发查询。
因此,有整个范围的滑动,充分批处理,然后会话窗口。对于任何窗口,我们还可以添加超时,以独立于任何其他事件触发输出。例如,“保持过去30秒内发生的100个事件或输出。“你也可以对这些窗户进行组合。
对于关联和聚合用例来说,窗口是必不可少的。不同类型的窗口适合不同的用途。然而,对于数据库工程师来说,窗口可能并不直观。这是因为数据库本质上是基于设置的。数据存在于一个表中,仅此而已。将数据概念化为不断变化的事物,并围绕它创建集合来完成基本的聚合功能,如总和、平均值或线性回归,这可能是一种新的不同的思维方式。
几乎所有的流媒体集成平台都提供了一定程度的窗口,并且都能够执行基于时间的窗口功能。然而,并不是所有的都支持所有不同类型的窗口或多时间性。这一点很重要,因为窗口是任何类型的流处理平台的基本组件。没有窗口,流集成用例可能是有限的。
5.8 丰富
流数据可能不包含您在目标目的地或进行分析所需的所有信息。这时就需要用到丰富的功能了。
例如,从关系数据库执行CDC时,任何一个特定表中的大多数字段都是引用其他表的ID。例如,来自客户订单项目表的所有已订购产品项目的数据流可能包含一个订单ID,一个客户ID,一个项目ID,也许是数量和时间戳,但是只是可能是。
尝试对这些有限的数据进行下游分析可能没有效果。不可能编写诸如“显示来自加利福尼亚的所有实时订单”或“显示所有的雨伞订单,因为预计会有大风暴”之类的查询。如果没有其他信息或其他内容,您将无法执行丰富的分析。
答案是用参考数据丰富现有数据。
例如,可以将在线商店中的产品(假设有100,000种)加载到内存中并按ID进行索引。然后,每当客户订单物料出现在数据流中时,都可以将其与内存中的物料合并,并添加其他信息:物料名称,其类别,当前库存以及其他相关数据。现在,数据流中包含更多信息,并且更适合于分析。
5.9 分布式缓存
丰富实时数据的挑战是数据的大小和速度。在数据库中,所有内容都在数据存储中。可在同一数据库中访问。两个表可以轻松地连接在一起,以提供所需的所有信息。但是,对于实时流环境,当我们谈论每秒数十万个事件时,这很困难。
例如,如果要加入远程数据库,则必须对每个事件进行查询。每个查询可能需要几毫秒。有了成千上万的事件,就不可能在要求的时间内针对数据流中的每个条目向数据库查询。同样,使用外部缓存或外部数据网格,从该缓存发出远程请求并保持每秒100,000个事件的速度也不可行。
我们可以通过在流集成平台本身中包含分布式缓存或内存数据网格来解决此问题。方法是将数据放入内存中,使其与流数据位于相同的处理空间中,并以与数据流相同的方式对其进行分区。传入的数据事件可能会实现非常高的吞吐量和低延迟,但这并非总是自然发生的。例如,内存中有100,000个项目,一个六节点集群和一个缓存系统,该系统被定义为出于冗余目的始终维护两个数据副本,任何一项特定数据在单个节点上的机会是三分之一。
但是,如果我们可以安排事件以便通过与用于划分参考数据相同的算法对事件进行划分,则事件将始终落在正确的节点上。现在查询完全在该节点的内存中,并且非常快。否则,有必要进行远程查找,这可能需要数十到数百微秒的时间。
5.10 关联
在这种情况下,关联并不表示统计关联。它与匹配变量或使用线性回归来了解变量之间的关联无关。那是分析的一部分。在这里,通过关联,我们是指将数据流中的事件与来自一个或多个其他数据流的事件进行匹配。
一个简单的示例就是拥有代表许多不同主机上活动的数据,这些数据来自不同的来源,也许包括机器信息,CPU使用率和系统日志中的内存。可能包括来自网络路由器的网络流量信息,或来自其他来源的防火墙信息。
在这种情况下,它们将具有共同的IP地址或MAC ID。然后需要将数据流连接在一起以生成单个输出数据流。
但是,使用数据流执行此操作很困难,因为它们的移动速度非常快。完全同时发生事件是不寻常的。这就像在粒子加速器中将两个质子束彼此对准一样。两个质子撞击的机会很小,因为它们很快而且很小。流事件也是如此。
要将数据流连接在一起,通常需要合并数据窗口。想象一下,您有多个物理管道,每个物理管道都有一个温度、流量和压力。每个管道上都有测量这些属性的传感器,这些传感器将数据发送到数据流,并且每个传感器以不同的速率生成数据。
为了了解特定管道的温度、压力和流量,有必要将这三个数据流连接在一起,现在,因为它们的速度不同,所以要做的方法是创建最后一个窗口记录每个管道,每个数据流。每当有一个新条目进入该窗口时,它将替换该管道中的旧条目。
然后针对三个窗口写入查询。每当任何一个窗口发生更改时,查询都会输出一个事件,并且输出将是更改后的窗口上该管道的新值,再加上其他窗口的现有度量值 视窗。
这样,就可以将以不同速度运行的流连接在一起,并在任何一个流上接收到数据时产生输出。
通过决定保留最后几个值而不是仅保留最后一个值,可以做得更好。这允许对可能的值进行计算。也许不是简单地使用最后一个值,而是使用最后三个值的平均值,或者更复杂的回归机制可以基于最后一个10个值来计算该值。
总而言之,窗口不仅可用于以相同的速率将流连接在一起。这对于连接以不同速率流动的流也很有用。窗口是能够跨快速移动的数据流进行实时关联的基本要素。