1.概述
流处理是一种用来处理无穷数据集的数据处理引擎。通常无穷数据集具有以下几个特点:
- 无穷数据:持续产生的数据,它们通常会被称为流数据。例如:银行信用卡交易订单、股票交易就、游戏角色移动产生的数据等;
- 低延时:流数据通常都是实时处理,数据实时产生,然后流处理引擎实时处理流数据,因此延时很短。
2.内容
2.1 什么是流处理
对于存储在Kafka系统内的数据,Kafka系统提供了一种进行处理和分析的功能——流处理,它具有以下特性。
1. 是一个轻量级的类库
Kafka流处理提供了一个非常轻量级的Java类库,它能够轻而易举地集成到任意的Java应用程序中,打包和部署的方式也没有特殊的要求。
2. 拥有良好的可扩展性和容错性
Kafka流处理除了依赖Kafka系统外,对外界不存在任何依赖。在系统达到瓶颈时,Kafka流处理可以使用Kafka系统的分区机制,轻松地实现水平扩展来解决瓶颈问题。同时,通过记录状态(窗口操作、聚合操作等)来实现高效的操作。
3. 拥有丰富的应用接口
Kafka流处理对底层的应用接口进行了封装,同时,对拓扑结构进行了高度抽象。
4. 具有灵活的弹性伸缩功能
在只读取数据一次的情况下,流处理应用程序无需用户介入,也能自动修改参数,实现应用程序的自动扩容和减容。
2.2 什么是流式计算
通常情况下,流式计算与批处理计算会放在一起做比较分析。
(1)在流式计算模型中,数据的输入是持续不断的,这意味着永远不知道数据的上限是多少,因此,计算产生的结果也是持续输出的,流程如下图所示。流式计算一般对实时性要求较高,为了提升计算效率,通常会采用增量计算来替代全量计算。
(2)在批处理计算模型中,通常数据上限是可知的,一般会先定义计算逻辑,然后进行全量计算,并将计算结果一次性输出。流程如下图所示。
2.3 为何需要流处理
在大数据生态圈中存在很多流处理系统或框架,下面介绍三个非常流行的开源流处理框架。
- Flink:一个对流数据和批次数据进行分布式处理的框架,它主要由Java代码实现。对于Flink而言,处理的主要是流数据,批次数据只是流数据的一个特例而已。当前Flink支持SQL语法来操作流数据。
- Spark Streaming:一种构建在Spark上的实时计算框架,用来处理流数据。Spark功能强大,同样支持SQL语法来操作流数据。
- Storm:一个用于事件流的分布式处理框架,主要由Clojure实现。该框架的目标是将输入流、处理、以及输出模块结合在一起,并组建成一套有向无环图。当前Storm也支持SQL语法来操作流数据。
既然已存在这些优秀的实时处理框架,为何Kafka还需要设计流处理呢?原因有以下几点:
1. 简单易用
Flink、Spark、Storm都属于流式处理框架,而Kafka流处理是基于Kafka系统的流处理类库,并非框架。
通常情况下,框架有固定的运行方式,用户需要了解框架的执行流程,这使得学习成本增加。而Kafka流处理作为一个类库,用户可以直接调用具体的类,整个执行逻辑都在用户的掌控之中,不会产生额外的学习成本。
2. 方便部署
Kafka流处理作为一个类库,可以非常方便地集成到应用程序中,并且对应用程序的打包和部署没有任何限制。
3. 资源使用率低
流式处理框架在启动实例时会预分配系统资源,即使是应用程序实例,框架自身也需要占用一部分系统资源。例如,一个Spark Streaming应用程序需要给Shuffle和Storage事先申请内存。
使用Kafka流处理不涉及框架实例的运行,所以不会额外占用系统资源。
提示:
Shuffle可以理解为一个沟通数据连接的桥梁。
Storage负责把数据存储到内存、磁盘或者堆外内存,有时还需要在其他节点创建副本来保存。
3.了解流处理架构
Kafka流处理使用Kafka系统的消费者类库和生产者类库来构建应用程序,并利用Kafka系统自身的特性来提供数据并行性、分布式协调性、容错性、易操作性等,从而简化用户开发应用程序的步骤。具体工作流程如下图所示:
Kafka流处理输入的数据来源于Kafka系统中的业务主题,处理后的结果会存储到Kafka系统中新的业务主题中。 上图中,消费者程序和生产者程序并不需要用户在应用程序中显式地实例化,而是通过Kafka流处理根据参数来隐式地实例化和管理,这让操作变得更加简单。用户只需关心核心业务逻辑(即上图中的任务模块)的编写,其他的都交由Kafka流处理来实现。
3.1 流分区与任务
Kafka流处理通过流分区来处理数据,内容包含存储和传输数据。Kafka流处理使用分区和任务概念来作为并发模型中的逻辑单元。在并发环境中,通过分区数据来保证灵活性、可扩展性、高效性和容错性。
1. 流分区的作用
在Kafka流处理中,每个流分区是完全而有序的数据队列。这些有序数据记录会映射到Kafka系统主题分区中。
流数据中映射的消息数据来自于Kafka系统主题。消息数据中键(Key)值是Kafka和Kafka流处理的关键,它决定了数据如何被路由到指定分区。
2. 任务的作用
一个应用程序可以被拆分成多个任务来执行。Kafka流处理会根据输入流分区来创建固定数量的任务,每个任务分配一个输入流分区列表。
任务是应用程序并行执行时的固定单元,因此分区对任务的分配不会造成影响。任务可以基于分配到的分区来实现相关处理流程,同时为每个分配到的分区保留一个缓冲区,并从这些缓冲区逐一地处理消息,这样可以让Kafka流处理的任务自动并行处理。
提示:
在一个子处理流程中,如果一个Kafka流处理应用程序指定了多个处理流程,则每个任务只实例化一个处理对象。
另外,一个处理流程可以被拆分为多个独立的子处理流程,只要保证子处理流程与其他子处理流程没有交集即可。通过这种方式可以让任务之间保持负载均衡。
Kafka流处理不是一个资源管理器,而是一个类库。 Kafka流处理可以运行在任何流处理应用程序中。应用程序的多个实例可以运行在同一台主机上,也可以分发到不同的主机进行执行。如果一个应用程序实例发生异常导致不可用,则该任务将会自动地在其他的实例上重新创建,并从相同的分区中继续读取数据。
3.2 线程模型
Kafka流处理允许用户配置多个线程,并通过多线程来均衡应用程序中的任务数。每个线程的处理流程可以执行一个或者多个任务。
1. 线程模型的处理流程
下图所示是使用一个线程来处理多个流任务。
启动多个流线程或更多的应用程序,只需要复制执行流程即可。比如,将一份业务逻辑处理代码复制到不同的主机上进行执行。这样做的好处是,通过多线程来并行处理不同Kafka系统主题分区中的数据,能提升处理效率。这些线程之间的状态是不共享的。因此,不需要线程间的协作。这使得运行一个多并发的处理流程实例变得非常简单。
2. 线程模型的优点
- 易扩展:对Kafka流处理应用程序进行扩展是很容易的,只需要运行应用程序的实例即可。
- 自动分配分区:Kafka流处理会监听任务数量的变化,并自动给任务分配分区。
- 多线程:用户在启动应用程序时,可以根据Kafka系统输入主题中的分区数来设置线程数。每个线程至少对应一个分区。
3. 多线程并发场景
假设有一个Kafka流处理应用程序,它从两个业务主题(A和B)中读取数据,每个业务主题都有3个分区。当用户在一台主机上启动一个应用程序实例,并设置线程数为2,最终会出现两个Kafka流处理线程。
由于输入主题A和输入主题B的最大分区数均为3,所以Kafka流处理会默认将其拆分为3个任务,然后将合计的6个分区(主题A和主题B的分区总和)均匀地分布到3个任务中。
这种情况下,每个任务会同时从两个分区中读取数据。最终,这3个任务会被均匀地分布在两个线程当中。两个线程的作用分别如下。
线程1包含两个任务,从四个分区(主题A的两个分区和主题B的两个分区)中读取数据;
线程2包含一个任务,从两个分区(主题A的一个分区和主题B的一个分区)中读取数据。
随着业务数据量的增加,需要对现有的应用程序进行拓展。实施的具体方案是,在另外一台主机上启动该应用程序,并设置线程数为1。具体实现流程如下图所示。
当前总分区数为6个,线程总数为3个。当任务被重新分配时,相同的分区、任务和存储状态,都会被移到新的线程,从而使应用程序达到负载均衡。
3.3 本地状态存储
Kafka流处理提供的状态存储机制,可用来保存和查询应用程序产生的状态数据。例如,在执行连接、聚合操作时,Kafka流处理会自动创建和管理这些状态存储。
下图展示了两个流处理任务,以及它们专用的本地状态存储。
在Kafka流处理应用程序中,每个流任务可以集成一个或多个本地状态存储,这些本地状态存储可以通过应用接口来进行存储和查询。同时,Kafka流处理也为本地状态存储提供了容错机制和自动恢复功能。
3.4 容错性
Kafka流处理继承了Kafka系统主题分区的两大能力——高可用能力、副本故障自动转移能力。因而,在流数据持久化到Kafka系统主题时,即使应用程序失败也会自动重新处理。
Kafka流处理中的任务利用Kafka系统客户端提供的容错机制来处理异常问题。如果某个任务在发生故障的主机上执行,则Kafka流处理会自动在应用程序的其他运行实例中重新启动该任务。
每个状态存储都会维护一个更改日志主题的副本,用来跟踪状态的更新。这些更改日志主题也进行了分区,以便每个本地状态存储实例和访问存储的任务都有其专属的更改日志主题分区。在更该日志主题上启用日志压缩,可以方便、安全地清理无用数据,避免主题数据无限增长。
如果任务在一台主机上运行失败,之后在另一台主机重新启动,则Kafka流处理在恢复对新启动的任务之前,通过回滚机制将关联的状态存储恢复到故障之前,整个过程对于用户来说是完全透明的。
需要注意的是,任务初始化所耗费的时间,通常取决于回滚机制恢复状态存储所用的时间。为了缩短恢复时间,用户可以将应用程序配置为本地状态的备用副本。当发生任务迁移时,Kafka流处理会尝试将任务分配给已存在备用副本的应用程序实例,以减少任务初始化所耗费的时间。
提示:
可以通过设置属性num.standby.replicas来分配每个任务的备用副本数。
4.总结
通过对Kafka Streams的研究,它的优势可以总结为以下几点。首先,它提供了轻量级并且易用的API来有效的降低流数据的开发成本,之前要实现这类处理,需要使用Spark Streaming,Storm,Flink,或者自己编写Consumer。其次,它开发的应用程序可以支持在YARN,Mesos这类资源调度中,使用方式灵活。而对于异步操作,不是很友好,需要谨慎处理;另外,对SQL语法的支持有限,需要额外开发。
版权归原作者 程序猿小乙 所有, 如有侵权,请联系我们删除。