什么是流式处理呢?这个问题其实我们大部分时候是没有考虑过的,大多数,我们是把流式处理和实时计算放在一起来说的。我们先来了解下,什么是数据流。 数据流(事件流)
流式处理流式处理就是指实时地处理一个或多个事件流。它是一种编程范式。其他编程领域,主要有3种编程范式:
流的定义不依赖某个框架,只要储蓄从一个无边界数据集中读取数据,并对它们进行处理生成结果,就是进行流式处理。重点是:整个过程必须是持续的。 流式处理中的时间上述我们已经说过了,数据流都是有序的。某一时刻的数据是确定的。时间是流式处理中非常重要的概念。大部分流式应用的操作都是基于时间窗口的。 流式系统一般包含以下几个时间概念(熟悉Flink的同学应该会很熟悉):
状态如果流式处理是来一个事件就处理一个事件,那么流式处理就很简单。但如果操作中包含了多个事件,流式处理就有意思了。例如:我们想在流式处理中统计北京用户的订单数量、消费金额等等。此时,就不能光处理单个事件了,我们需要获取更多的事件。事件与事件之间的信息就称之为状态。例如简单的,求某个类型的订单数等。 这些状态一般就保存在流式处理程序本地变量(本地内存)中,例如:使用HashMap来保存计数。但这种做法是很不可靠的,流式处理处理的是无界数据集,一旦应用程序出现异常,就会出现状态丢失,这是我们说不能接受的。所以,每一种流式计算框架都会很小心地持久化状态。如果应用程序重启,需要将这些数据恢复。 流式处理一般包含两种状态:
时间窗口大部分针对流的操作都是基于时间窗口的。例如:计算一周内销量最好的产品。两个流的合并也是基于时间窗口的。流式系统会合并发生在相同时间段上的事件。窗口是有类型的。以下几点是我们设计窗口需要考虑的:
下面这张图,说明了滚动窗口与滑动窗口的区别。 滚动窗口:假设窗口的大小为5分钟,这里确定的3个时间窗口 滑动窗口:假设每分钟滑动一次,那么这个时候会有5个时间窗口,计算结果会发生重叠 流式处理的设计模式单个事件处理这是流式处理最基本的模式。这种模式也叫:map或filter模式。经常被用来过滤无用的事件或者用于转换事件。 这种模式,应用程序读取流中的数据,修改数据,然后把事件生成到另一个流上。这一类应用程序无需在程序内部维护状态,每一个事件都是独立处理的。这种错误恢复和进行负载均衡都很容易。因为无需进行状态恢复操作。 使用本地状态大部分流式处理应用关系如何聚合数据。特别是:基于时间窗口进行聚合。例如:找到每天最低、最高的交易价格。要实现这种操作,就需要维护流的状态。例如:我们需要将最小值、最大值保存下来,用它们与每一个新值对比。这类操作,可以通过本地状态来实现。例如:每一个分组都维护自己分组的状态。 一旦流式处理中包含了本地状态,就需要解决以下问题。
多阶段处理和重分区有些时候,我们要通过所有可用的数据来获得结果。例如:要发布每天的“前10支”股票,这10支股票需要从每天的交易股票中挑选出来。如果仅仅在单个实例上处理是不够的,因为10支股票分布在多个实例上。 此种,我们分为多个阶段来处理。 1、计算每支股票当天的涨跌。这个计算可以在每个实例上执行 2、将结果写入到单个分区 3、再用一个实例找出当天的前10支股票 这一类操作就与MapReduce很像了。 使用外部查找——流和表的连接有时候,流式处理需要将外部数据和流集成在一日。例如:外部数据中保存了一些规则、或者将完整完整地用户信息拉取到流中。 这种case最大的问题,外部查找会带来严重的延迟,一般在 5-15 ms之间,这在很多情况下是不可行的。而且,外部系统也无法承受这种额外的负载——流式处理系统每秒可以处理10-50W个事件,而数据库正常情况下每秒只能处理1W个事件,所以需要伸缩性更强的解决方案。 为了获取更好的性能和更强的伸缩性,需要将外部数据库的信息缓存到流式处理应用中。但考虑以下问题: 如何保证缓存里的数据是最新的? 如果刷新太频繁,仍然会对数据库造成很大压力,缓存也就无用了。 如果刷新不及时,那么流式处理中所用的数据就会过时。 如果能够捕捉数据库的变更事件,并形成事件流,流式处理作业就可以监听事件流,并及时更新缓存。捕捉数据库的变更事件并形成数据流,这个过程称为CDC(Change Data Capture)。例如:我们可以通过Canal来捕获MySQL数据库的变化、可以通过ogg来捕获Oracle数据库的变化 流与流的连接有时候需要连接两个真实的事件流。要连接两个流,就是连接所有的历史事件(将两个妞中具有相同键、发生在相同时间窗口内的事件匹配起来),这种流和流的连接称为:基于时间窗口的连接(windowed-join)。连接两个流,通常包含一个滑动时间窗口。 乱序事件不管对于流式处理、还是传统的ETL系统,处理乱序事件都是一个挑战。物联网领域经常发生乱序事件:一个移动设备断开Wifi连接几个小时,在重新连上WiFi后,将几个小时堆积的事件一并发出去。要让流式处理应用处理好这些场景,需要做到几下:
重新处理该重要模式是重新处理事件:
第一种情况,需要Kafka将事件流长时间地保存在可伸缩的数据存储中
第二种情况,需要应用程序回到输入流的起始位置开始处理,同时重置本地状态,还要清理之前的输出流。这种方式处理起来比较困难。建议还是使用第一种方案。 参考文献: 《Kafka全文指南》 |
|
来自: python_lover > 《待分类》