1. Kafka入门介绍
1.1 Apache Kafka是一个分布式的流平台。这到底意味着什么?
我们认为,一个流平台具有三个关键能力:
① 发布和订阅消息。在这方面,它类似一个消息队列或企业消息系统。(生产和消费消息)
② 以容错的方式存储消息流。(存储消息)
③ 当消息流发生时处理它们。(处理消息)
1.1.1 kafka的优势
它应用于两大类应用:
① 构建实时的流数据管道,可靠地获取系统和应用程序之间的数据。(获取数据)
② 构建实时流的应用程序,对数据流进行转换或反应。(处理数据)
1.1.2 几个概念
① kafka作为一个集群运行在一个或多个服务器上。
② kafka集群以topic为类别来存储消息。
③ 每个消息是由一个key,一个value和时间戳timestamp构成的。
1.1.3 kafka的四个核心API
- 应用程序使用Producer API发布消息到1个或多个topic。(生产消息)
- 应用程序使用Consumer API订阅1个或多个topic,并处理产生的消息。(消费消息,相当于处理消息)
- 应用程序使用Streams API去充当一个流处理器,从1个或多个topic消费输入流,并生成一个输出流到1个或多个输出topic,有效地将输入流转换到输出流。(处理消息流)
- Connector API允许构建和运行可重复使用的生产者或消费者,它们将kafka topic连接到现有的应用程序或数据系统。例如,一个关系型数据库的连接器可捕获一个表的每一个变化。(监控消息变化)
在Kafka中,客户端和服务器之间的通讯,是通过一条简单,高性能并且语言无关的TCP协议来完成的。该协议是版本化的,并兼容旧版本。Kafka提供Java Client(客户端),还有非常多其他编程语言的Client。
1.2 Topics和Logs(分区和偏移量)
让我们更深入的了解Kafka中的Topic。
Topic是发布的消息的类别。Kafka中的Topic是面向多订阅者的,这就意味着,一个topic可以有0,1,或者多个消费者去订阅写入的数据。对于每个topic,Kafka集群维护一个分区日志,如下所示:
每个分区是顺序的、不可变的消息队列,并且可以持续的添加。分区中的消息都被分了一个序列id号,称之为偏移量offset,用于唯一标识在分区中的每条消息。
Kafka集群保留所有发布过的消息——无论它们是否已经被消费——直到它们过期。例如,如果保留策略设置为两天,那么在消息发布后的两天内可以使用,之后将被丢弃以释放空间。
事实上,在每个消费者的基础上保留的唯一元数据是消费者在日志中的偏移量offset或位置。这个偏移量offset由消费者控制;正常情况下,当消费者消费消息的时候,偏移量offset也线性的增加。但事实上,由于偏移量由消费者控制,所以它可以以任何喜欢的顺序消费消息。例如,消费者可以重置偏移量为较旧的偏移量以重新处理过去的数据,或者跳至最近的消息并从“now”开始消费。
这些功能的组合意味着kafka消费者非常cheap——他们可以来来去去,对集群或其他消费者没有太大的影响。例如,你可以使用命令行工具来“tail”(查看)任何topic的内容末尾,而不会改变现有的消费者所消费的内容。
在log中分区有几个目的。首先,他们允许日志的大小规模超过单台服务器适合的的大小。每个独立分区必须适合托管它的服务器,一个topic可能有多个分区,因此它可以处理任意数量的数据。第二,分区作为并行处理的单元。
1.3 Distribution (分布式)
Log的分区被分布到集群中的多个服务器上。每个服务器处理数据并请求共享分区。根据配置每个分区可以复制到其他服务器作为备份容错。
每个分区有一个leader,零或多个follower。leader处理此分区所有读写请求,而followers被动的复制数据。如果leader宕机,followers中的一个会自动成为新的leader。每台服务器充当它的一些分区的leader,其他的followers,因此集群内的负载平衡得很好。
1.4 Producers
producers将数据发布到它们选择的topic上。producer负责选择哪条消息分配给topic中的哪个分区。这可以通过循环的方式去平衡负载来完成,或者根据一些semantic分区功能(比如消息中的某个键)来完成。
1.5 Consumers
Consumers用消费者组名来标记它们自己,并将每条发布到topic的消息传递给每个订阅消费者组中的一个consumer实例。消费者实例可以是独立的进程,也可以是独立的机器。
如果所有的消费者实例都具有相同的消费者组,那么消息将有效地在消费者实例上进行负载平衡。
如果所有的消费者具有不同的消费者组,那么每条消息将会广播到所有的消费者进程。
两台服务器组成的Kafka集群持有四个分区(P0-P3),两个消费者组。消费者组A有两个消费者实例,而消费者B有四个消费者实例。
然而,通常,我们发现topics有一小部分消费者组,一个用于“逻辑订阅者”。每组由许多可伸缩性和容错性的消费者实例组成。这只不过是发布-订阅semantics,订阅者是一个消费者集群,而不是单个进程。
在Kafka中实现消费的方法是通过将日志中的分区划分给消费者实例,因此每个消费者实例在任何时间点都是分区的“公平份额”的独占使用者。保持组中成员资格的过程是由kafka协议动态处理的。如果新实例加入组,它们将接管组中成员的一些分区。如果一个实例挂掉,它的分区将会分配给剩下的实例。
Kafka只在一个分区中提供超过消息的总订单(a total order over records),而不是在一个topic中的不同分区之间。每个分区排序加上根据key对数据进行分区的能力对于大多数应用程序来说已经足够了。然而,如果你要求超过消息的总订单(a total order over records),这可以通过只有一个分区的topic实现,但是这意味着每个消费者组只有一个消费者进程。
1.6 Guarantees(保证)
Kafka给出了如下保证:
- 由producer发送到特定主题分区的消息将按其发送的顺序追加。那就是说,如果消息M1和M2被同一producer发送,并且M1先被发送,那么M1将比M2有更低的偏移量和更早在日志中出现。
- 消费者实例按照消息存储在日志中的顺序来获取消息。
- 对于带有复制因子N的主题,我们将容忍N-1个服务器故障,而不会丢失提交给日志的任何消息。
1.7 Kafka作为一个消息传递系统
Kafka的流概念与传统的企业消息传递系统相比如何?
传统上,消息传递有两种模式:队列和发布-订阅。在队列中,消费者池从服务器读取消息,并且每条消息只能被消费者中的一个读取。这两种模式都有优点和缺点。队列的优点是它允许多个消费者瓜分处理数据,这使你可以扩展处理过程。不幸的是,队列不是多个订阅者,一旦进程读取数据故障,消息就会丢失。发布-订阅允许你广播数据到多个进程,但是由于每条消息都传递给每个订阅者,所以没有缩放处理的方法。
kafka中消费者组涵盖了两个概念。队列:消费者组允许你对进程集合(消费者组成员)进行分割处理。发布-订阅:Kafka允许你将消息广播到多个消费者组。
Kafka模型的优点是每个topic都有这两个属性——它可以扩展处理,而且是多用户,不需要选择一个或另一个。
Kafka比传统的消息传递系统具有更强的排序保证。
传统的队列在服务器上按次序保留消息,如果多个消费者从队列中消费,那么服务器按照它们存储的顺序分发消息。然而,虽然服务器按顺序发送消息,但异步地将消息传递给消费者,因此它们可能会在不同的用户上发生故障。这实际上意味着在并行消费的情况下,消息的顺序丢失了。消息传递系统经常通过只运行一个进程从队列中消费的概念“exclusive sonsumer”来解决这个问题,但在处理过程中没有并行性。
Kafka做的更好。通过对topics中的并行性(即partition)概念的理解,Kafka能够在一个消费者过程池中提供顺序保证和负载平衡。这是通过将主题中的分区分配给消费者从而使每个分区完全有组中的一个消费者所消耗来实现的。通过这样做,我们确保消费者是该分区的唯一读者,并按顺序消费数据。由于有许多分区,所以仍然在许多消费者实例之间平衡负载。但是,请注意,消费者组中的消费者实例不能多于分区。
1.8 Kafka作为一个存储系统
允许发布消息而不必消耗它们的任何消息队列,有效地充当了存储系统。kafka的不同之处在于它是一个非常好的存储系统。
写入到Kafka的数据是写到硬盘的,并且被复制用于容错。Kafka允许producers等待消息应答,以便在完全复制到其他服务器之前写入被认为是不完整的,并且即使写入的服务器失败也能保证持续。
Kafka的磁盘结构使用了很好的规模——无论你在服务器上有50KB还是50TB的持久化数据,Kafka都会执行相同的操作。
由于认真考虑存储并允许客户端控制其读取位置,所以可以将Kafka视为用于高性能,低延迟提交日志存储,复制和传播的专用分布式文件系统。
1.9 Kafka的流处理
仅仅读、写和存储数据流是不够的,kafka的目标是实时处理流。
在Kafka中,流处理器是指从输入topics获取连续数据流,对该输入执行一些处理,并产生连续数据流到输出topics。
例如,零售应用程序可能会获取销售和货运的输入流,对这些数据进行重新排序和价格调整后输出。
直接使用producer和consumer APIs可以做简单的处理。但是对于更复杂的转换,Kafka提供了一个完全集成的Streams API。这允许构建应用程序进行非平凡的处理,从而计算聚合关闭流或将流连接在一起。
这个工具有助于解决这类应用程序面临的难题:处理乱序数据,重新处理代码更改的输入,执行有状态的计算等等。
streams API基于Kafka提供的核心构建:它使用生产者和消费者API进行输入,使用Kafka进行有状态存储,并在流处理器实例之间使用相同的组机制来实现容错。
1.10 把管道拼在一起
消息传递、存储和流处理的组合看似不寻常,但是对于Kafka作为流式处理平台,这是必要的。
分布式文件系统,如HDFS,允许存储静态文件用于批处理。像这样的系统可以有效地存储和处理来自过去的历史数据。
传统的企业消息传递系统允许处理在你订阅之后到达的未来消息。利用这种方式构建的应用程序处理未来数据当它到达时。
kafka组合了上述的这两种能力,这种组合对于kafka作为流处理应用和流数据管道平台是至关重要的。
通过组合存储和低延迟订阅,流处理应用可以用相同的方式处理过去和将来的数据。这是单一应用,它可以处理历史、存储的数据,但当它到达最后一个消息时,它可以继续处理未来的数据,而不是结束。这是流处理的概括概念,包括批处理以及消息驱动的应用程序。
同样,对于流式数据管道,订阅实时事件的组合使得Kafka可以用于非常低延迟的管道;但是,可靠地存储数据的能力可以将其用于必须保证数据交付的关键数据,或者用于只能定期加载数据或可能长时间停机进行维护的离线系统集成。流处理设施可以在数据到达时进行转换。
参考资料: