kafka是一个分布式的流媒体平台,这意味着:
- 类似消息队列,它可以发布订阅消息流
- 用一个容错的持久化的方式存储消息流
- 实时的处理消息流
kakfa通常被用户下面两大类应用:
- 构建一个能在系统跟应用之间可靠的传输数据的实时的流数据管道
- 构建实时流应用程序,能够转换或响应数据流
一些重要的概念:
- kafka作为一个集群运行在一个或多个服务器上,这些服务可以跨多个数据中心
- kafka集群将记录流存储在称为topics的类别中
- 每个记录包含了一个key,一个value,一个时间戳
kakfa有四个核心的API:
- Producer API :允许一个应用发布消息流到一个或多个topics
- Consumer API:允许一个应用订阅一个或多个topics,并且处理产生给他们的消息流
- Streams API :允许一个应用充当流处理器,使用来自一个或多个主题的输入流,并生成到一个或多个输出主题的输出流,从而有效地将输入流转换为输出流
4.Connector API:允许构建和运行可重用的生产者或消费者,将Kafka主题连接到现有
的应用程序或数据系统
Topics and Logs:
topic是被发布消息的类别或提要名称。在kafka中topic总是多订阅者的,这意味着,一个topic可以没有或者1个或者多个订阅了topic中写入的数据的消费者。
让我们先深入核心抽象Kafka提供了一个记录流 - 主题。
主题是要将记录发布到的类别或供稿源名称。卡夫卡的话题总是多用户的; 也就是说,一个主题可以有零个,一个或多个订阅写入数据的消费者。
对于每个主题,Kafka集群维护一个分区日志,如下所示:
每个分区是一个有序的,不可变的记录序列,不断追加到结构化的提交日志中。分区中的记录每个分配一个连续的id号,称为偏移量,用于唯一标识分区内的每条记录。
Kafka集群使用可配置的保留期限来保留所有已发布的记录(无论是否已被使用)。例如,如果保留策略设置为两天,则在记录发布后的两天内,保留策略可供使用,之后将被丢弃以腾出空间。卡夫卡的性能在数据大小方面是有效的,所以长时间存储数据不成问题
实际上,以消费者为单位保留的唯一元数据是消费者在日志中的偏移或位置。这个偏移量是由消费者控制的:消费者通常会在读取记录时线性地推进其偏移量,但事实上,由于消费者的位置是由消费者控制的,所以它可以以任何喜欢的顺序消费记录。例如,消费者可以重置为较旧的偏移量以重新处理来自过去的数据,或者跳至最近的记录并从“now”开始消费。
这些功能的组合意味着卡夫卡的消费者非常方便 - 他们可以来来去去,对集群或其他消费者没有太大的影响。例如,您可以使用我们的命令行工具来“tail”任何主题的内容,而不会改变现有的使用者所使用的内容。
日志中的分区有几个用途。首先,它们允许日志的大小超出适合单个服务器的大小。每个单独的分区必须适合托管它的服务器,但是一个主题可能有许多分区,因此它可以处理任意数量的数据。其次,它们作为并行的单位 - 更多的是在一点上。
Distribution:
日志的分区分布在Kafka集群中的服务器上,每个服务器处理数据和请求共享分区。每个分区都通过可配置数量的服务器进行复制,以实现容错。
每个分区有一个服务器充当“领导者”,零个或多个服务器充当“追随者”。领导处理分区的所有读取和写入请求,而追随者被动地复制leader。如果leader宕机,其中一个追随者将自动成为新leader。每个服务器充当其中一些分区的领导者和其他人的追随者,因此负载在集群内平衡良好。
Producers:
生产者发布数据到他们选择的主题。生产者负责选择哪个记录分配给主题内的哪个分区。这可以以循环的方式完成,只是为了平衡负载,或者可以根据某些语义分区功能(例如基于记录中的某个键)来完成。
Consumers:
消费者用消费者组名称标记自己,并且发布到主题的每个记录被传递到每个订阅消费者组中的一个消费者实例。消费者实例可以在不同的进程中或在不同的机器上。
如果所有消费者实例具有相同的消费者组,则记录将有效地在消费者实例上进行负载均衡。
如果所有消费者实例具有不同的消费者组,则每个记录将被广播给所有消费者进程。
两个服务器Kafka集群托管四个分区(P0-P3)与两个消费者组。消费者组A有两个消费者实例,而组B有四个消费者实例。
然而,更普遍的是,我们发现话题中有少量消费群体,每个“逻辑用户”都有一个消费群体。每个组由许多消费者实例组成,具有可扩展性和容错性。这不过是发布 - 订阅语义,订阅者是一群消费者而不是一个进程。
在Kafka中实现消费的方式是将日志中的分区划分为消费者实例,以便每个实例在任何时间点都是“公平分享”分区的唯一消费者。这个维护组中成员资格的过程是由Kafka协议动态地处理的。如果新实例加入组,他们将接管来自组中其他成员的一些分区; 如果一个实例死亡,其分区将分配给其余的实例。
卡夫卡只提供一个分区内的记录总数,而不是主题中的不同分区之间。每个分区排序与按键分区数据的能力相结合,足以满足大多数应用程序的需求。但是,如果我们需要的是一个总的顺序,则可以通过仅具有一个分区的主题来实现,但这意味着每个消费者组只有一个消费者进程。
Guarantees:
生产者发送到特定主题分区的消息将按发送顺序追加。也就是说,如果记录M1是由与记录M2相同的生产者发送的,并且M1是先发送的,那么M1的偏移量将比M2低,并且出现在日志的前面。
消费者实例按记录存储在日志中的顺序查看记录
对于具有备份因子N的主题,我们将容忍最多N-1个服务器故障,而不会丢失提交到日志的任何记录。
Kafka as a Messaging System:
Kafka的流概念与传统的企业消息系统相比如何?
消息传递传统上有两种模型:队列和发布-订阅。在队列中,一个消费者池可以从一个服务器读取数据,并且每个记录将被发送到其中一个;在publish-subscribe中,记录被广播给所有消费者
队列的优势在于,它允许我们在多个使用者实例上划分数据处理,从而允许扩展处理。不幸的是,队列不是多订阅者的,一旦一个进程读取了,数据就丢失了。发布-订阅模式将数据广播到多个进程,但是由于每个消息都发送到每个订阅者,因此无法扩展处理。
Kafka中的消费者组概念概括了这两个概念。与队列一样,使用者组允许我们将处理划分到一组进程(消费者组的成员)上。与发布-订阅一样,Kafka允许我们向多个消费者组广播消息。
卡夫卡模型的优势在于,每个主题都具有这两种属性——可以扩展处理,而且是多订阅者的——不需要选择其中之一。
Kafka也比传统的消息传递系统有更强的订阅保证。
传统队列在服务器上按顺序保留记录,如果多个消费者从队列中消费,则服务器按存储记录的顺序分发记录。然而,尽管服务器按顺序分发记录,但是这些记录是异步传递给使用者的,因此它们可能在不同的使用者上出现顺序错误。这实际上意味着记录的顺序在并行使用时丢失。消息传递系统通常通过“独占消费者”的概念来解决这个问题,该概念只允许一个进程从队列中消费,但这当然意味着处理中不存在并行性。
卡夫卡做得更好。通过在主题中具有并行性(分区)的概念,Kafka能够在用户进程池上提供排序保证和负载平衡。这是通过将主题中的分区分配给使用者组中的使用者来实现的,以便每个分区恰好由组中的一个使用者使用。通过这样做,我们确保使用者是该分区的唯一读取者,并按顺序使用数据。由于有许多分区,这仍然可以在许多使用者实例上平衡负载。但是请注意,在一个使用者组中不能有多于分区的使用者实例。
Kafka as a Storage System:
任何允许发布与使用解耦的消息的消息队列都可以有效地充当正在运行的消息的存储系统。Kafka的不同之处在于它是一个非常好的存储系统
写入Kafka的数据被写入磁盘并复制,以获得容错能力。Kafka允许生产者等待确认,直到写入的数据被完全复制,并保证即使写入的服务器发生故障也能持久,这个时候才会被认为写入完成
Kafka使用的磁盘结构伸缩性很好,无论服务器上有50 KB还是50 TB的持久数据,Kafka都会执行相同的操作。
Kafka for Stream Processing:
仅仅读取、写入和存储数据流是不够的,其目的是实现流的实时处理。
在Kafka中,流处理器是指从输入主题获取连续的数据流,对这个输入执行一些处理,并产生连续的数据流到输出主题。
例如,一个零售应用程序可能接受销售和发货的输入流,并根据这些数据计算出重新订购和价格调整的输出流。
可以直接使用生产者和消费者api进行简单的处理。但是对于更复杂的转换,Kafka提供了一个完全集成的Streams API。这允许构建进行非平凡处理的应用程序,这些处理可以计算流之外的聚合或将流连接在一起。
此功能有助于解决此类应用程序所面临的难题:处理无序数据、在代码更改时重新处理输入、执行有状态计算等等。
streams API构建在Kafka提供的核心原语之上:它使用生产者和消费者API进行输入,使用Kafka进行有状态存储,并使用相同的组机制在流处理器实例之间进行容错。
Putting the Pieces Together:
这种消息传递、存储和流处理的组合可能看起来不寻常,但对于Kafka作为流平台的角色来说,这是必不可少的。
像HDFS这样的分布式文件系统允许存储静态文件进行批处理。实际上,这样的系统允许存储和处理来自过去的历史数据。
传统的企业消息传递系统允许处理订阅后到达的未来消息。以这种方式构建的应用程序在未来数据到达时处理它。
Kafka结合了这两种功能,这种结合对于Kafka作为流应用程序的平台以及流数据管道来说都是至关重要的。
通过结合存储和低延迟订阅,流应用程序可以以相同的方式处理过去和未来的数据。也就是说,一个应用程序可以处理历史上存储的数据,但是当它到达最后一条记录时,它可以在未来的数据到达时继续处理,而不是结束。这是流处理的一个广义概念,包括批处理和消息驱动应用程序。
同样,对于流数据管道,订阅实时事件的组合使使用Kafka处理非常低延迟的管道成为可能;但是,可靠地存储数据的能力使其能够用于必须保证数据交付的关键数据,或者用于与离线系统集成,离线系统只定期加载数据,或者可能在很长一段时间内停机以进行维护。流处理设施使得在数据到达时转换数据成为可能。