Kafka,是时候深入了解一下了

2017-11-30 22:48:29 织梦安装使用
  • 文章介绍

Kafka,不是村上春树的《海边的卡夫卡》,不是《变形记》的作者弗兰兹·卡夫卡。

程序员世界的 Kafka,三分之一的世界 500 强公司使用它发布和订阅、存储及实时地处理大规模流数据。

Kafka,不只是个消息系统,更是功能完善的分布式流式处理平台。

2017年11月1日,Kafka 1.0.0 版本发布,带动了不少程序员期待深入了解这个人气持续飙升的项目。恰好,图灵新书《Kafka技术内幕》上架。早在本书出版之前,作者郑奇煌的博客就受到了不少读者的喜爱,本书讲述内容的广度和深度是市面上其他 Kafka 图书少见的。唯一的遗憾是,受限于一本书的出版流程,它以 0.10 版本讲解,不过,也算市面上已有图书中版本比较新的。

不管大家最终是否购买这本书,首先,今天咱们借这本书来了解一下 Kafka。

 作为流平台的 Kafka

Apache Kafka(简称Kafka)最早是由 LinkedIn 开源出来的分布式消息系统,现在是Apache旗下的一个子项目,并且已经成为开源领域应用最广泛的消息系统之一。Kafka社区也非常活跃,在 0.10 版本之前,Kafka 仅仅作为一个消息系统,主要用来解决应用解耦、异步消息、流量削峰等问题。

不过在0.10版本之后,Kafka提供了连接器与流处理的能力,它也从分布式的消息系统逐渐成为一个流式的数据平台。

作为一个流式数据平台,最重要的是要具备下面 3 个特点:

  • 类似消息系统,提供事件流的发布和订阅,即具备数据注入功能

  • 存储事件流数据的节点具有故障容错的特点,即具备数据存储功能

  • 能够对实时的事件流进行流式地处理和分析,即具备流处理功能

Kafka是如何实现并组合上面 3 个功能特点的?

  • 消息系统:如图1-1所示,消息系统(也叫作消息队列)主要有两种消息模型:队列和发布订阅。Kafka 使用消费组(consumer group)统一了上面两种消息模型。Kafka 使用队列模型时,它可以将处理工作平均分配给消费组中的消费者成员;使用发布订阅模式时,它可以将消息广播给多个消费组。采用多个消费组结合多个消费者,既可以线性扩展消息的处理能力,也允许消息被多个消费组订阅。

  • 队列模式(也叫作点对点模式)。多个消费者读取消息队列,每条消息只发送给一个消费者。

  • 发布订阅模式(pub/sub)。多个消费者订阅主题,主题的每条记录会发布给所有的消费者。

   

  • 存储系统:任何消息队列要做到“发布消息”和“消费消息”的解耦合,实际上都要扮演一个存储系统的角色,负责保存还没有被消费的消息。否则,如果消息只是在内存中,一旦机器宕机或进程重启,内存中的消息就会全部丢失。Kafka 也不例外,数据写入到 Kafka 集群的服务器节点时,还会复制多份来保证出现故障时仍能可用。为了保证消息的可靠存储,Kafka 还允许生产者的生产请求在收到应答结果之前,阻塞式地等待一条消息,直到它完全地复制到多个节点上,才认为这条消息写入成功。

  • 流处理系统:流式数据平台仅仅有消息的读取和写入、存储消息流是不够的,还需要有实时的流式数据处理能力。对于简单的处理,可以直接使用 Kafka 的生产者和消费者 API 来完成;但对于复杂的业务逻辑处理,直接操作原始的API需要做的工作非常多。Kafka 流处理(Kafka Streams)为开发者提供了完整的流处理API,比如流的聚合、连接、各种转换操作。同时,Kafka 流处理框架内部解决很多流处理应用程序都会面临的问题:处理乱序或迟来的数据、重新处理输入数据、窗口和状态操作等。

  • 将消息系统、存储存储、流处理系统组合在一起:传统消息系统的流处理通常只会处理订阅动作发生之后才到达的新消息,无法处理订阅之前的历史数据。分布式文件存储系统一般存储静态的历史数据,对历史数据的处理一般采用批处理的方式。现有的开源系统很难将这些系统无缝地整合起来,Kafka 则将消息系统、存储系统、流处理系统都组合在一起,构成了以 Kafka 为中心的流式数据处理平台。它既能处理最新的实时数据,也能处理过去的历史数据。

Kafka 作为流式数据平台的核心组件,主要包括下面 4 种核心的API,如图1-2所示。

  • 生产者(producer)应用程序发布事件流到 Kafka 的一个或多个主题。

  • 消费者(consumer)应用程序订阅 Kafka 的一个或多个主题,并处理事件流。

  • 连接器(connector)将 Kafka 主题和已有数据源进行连接,数据可以互相导入和导出。

  • 流处理(processor)从 Kafka 主题消费输入流,经过处理后,产生输出流到输出主题。

建立以 Kafka 为核心的流式数据管道,不仅要保证低延迟的消息处理,还需要保证数据存储的可靠性。另外,在和离线系统集成时,将 Kafka 的数据加载到批处理系统时,要保证数据不遗漏; Kafka 集群的某些节点在停机维护时,要保证集群可用。

 Kafka 的基本概念

1. 分区模型

Kafka 集群由多个消息代理服务器(broker server)组成,发布到 Kafka 集群的每条消息都有一个类别,用主题(topic)来表示。通常,不同应用产生不同类型的数据,可以设置不同的主题。一个主题一般会有多个消息的订阅者,当生产者发布消息到某个主题时,订阅了这个主题的消费者都可以接收到生产者写入的新消息。

Kafka 集群为每个主题维护了分布式的分区(partition)日志文件,物理意义上可以把主题看作分区的日志文件(partitioned log)。每个分区都是一个有序的、不可变的记录序列,新的消息会不断追加到提交日志(commit log)。分区中的每条消息都会按照时间顺序分配到一个单调递增的顺序编号,叫作偏移量(offset),这个偏移量能够唯一地定位当前分区中的每一条消息。

如图1-3(左)所示,主题有3个分区,每个分区的偏移量都从0开始,不同分区之间的偏移量都是独立的,不会互相影响。右图中,发布到 Kafka 主题的每条消息包括键值和时间戳。消息到达服务端的指定分区后,都会分配到一个自增的偏移量。原始的消息内容和分配的偏移量以及其他一些元数据信息最后都会存储到分区日志文件中。消息的键也可以不用设置,这种情况下消息会均衡地分布到不同的分区。

2. 消费模型

消息由生产者发布到 Kafka 集群后,会被消费者消费。消息的消费模型有两种:推送模型(push)和拉取模型(pull)。基于推送模型的消息系统,由消息代理记录消费者的消费状态。消息代理在将消息推送到消费者后,标记这条消息为已消费,但这种方式无法很好地保证消息的处理语义。

Kafka 采用拉取模型,由消费者自己记录消费状态,每个消费者互相独立地顺序读取每个分区的消息。如图1-4所示,有两个消费者(不同消费组)拉取同一个主题的消息,消费者A的消费进度是 3,消费者B的消费者进度是 6。消费者拉取的最大上限通过最高水位(watermark)控制,生产者最新写入的消息如果还没有达到备份数量,对消费者是不可见的。这种由消费者控制偏移量的优点是:消费者可以按照任意的顺序消费消息。比如,消费者可以重置到旧的偏移量,重新处理之前已经消费过的消息;或者直接跳到最近的位置,从当前时刻开始消费。  

3. 分布式模型

Kafka 每个主题的多个分区日志分布式地存储在 Kafka 集群上,同时为了故障容错,每个分区都会以副本的方式复制到多个消息代理节点上。其中一个节点会作为主副本(Leader),其他节点作为备份副本(Follower,也叫作从副本)。主副本会负责所有的客户端读写操作,备份副本仅仅从主副本同步数据。当主副本出现故障时,备份副本中的一个副本会被选择为新的主副本。

Kafka 的生产者和消费者相对于服务端而言都是客户端,生产者客户端发布消息到服务端的指定主题,会指定消息所属的分区。Kafka 的消费者通过订阅主题来消费消息,并且每个消费者都会设置一个消费组名称。消息就会负载均衡到所有的消费者;如果要实现“发布订阅”模型,则每个消费者的消费组名称都不相同,这样每条消息就会广播给所有的消费者。

分区是消费者线程模型的最小并行单位。如图1-5(左)所示,生产者发布消息到一台服务器的3个分区时,只有一个消费者消费所有的3个分区。在图1-5(右)中,3个分区分布在3台服务器上,同时有3个消费者分别消费不同的分区。假设每个服务器的吞吐量是 300 MB,在图1-5(左)中分摊到每个分区只有100 MB,而在图1-5(右)中集群整体的吞吐量有 900 MB。可以看到,增加服务器节点会提升集群的性能,增加消费者数量会提升处理性能。

同一个消费组下多个消费者互相协调消费工作,Kafka 会将所有的分区平均地分配给所有的消费者实例,这样每个消费者都可以分配到数量均等的分区。Kafka 的消费组管理协议会动态地维护消费组的成员列表,当一个新消费者加入消费组,或者有消费者离开消费组,都会触发再平衡操作。

Kafka 的消费者消费消息时,只保证在一个分区内消息的完全有序性,并不保证同一个主题中多个分区的消息顺序。而且,消费者读取一个分区消息的顺序和生产者写入到这个分区的顺序是一致的。

比如,生产者写入“hello”和“kafka”两条消息到分区 P1,则消费者读取到的顺序也一定是“hello”和“kafka”。如果业务上需要保证所有消息完全一致,只能通过设置一个分区完成,但这种做法的缺点是最多只能有一个消费者进行消费。一般来说,只需要保证每个分区的有序性,再对消息加上键来保证相同键的所有消息落入同一个分区,就可以满足绝大多数的应用。

 Kafka 的设计与实现

1. 文件系统的持久化与数据传输效率

人们普遍认为一旦涉及磁盘的访问,读写的性能就严重下降。实际上,现代的操作系统针对磁盘的读写已经做了一些优化方案来加快磁盘的访问速度。比如,预读(read-ahead)会提前将一个比较大的磁盘块读入内存。后写(write-behind)会将很多小的逻辑写操作合并起来组合成一个大的物理写操作。

并且,操作系统还会将主内存剩余的所有空闲内存空间都用作磁盘缓存(disk cache/page cache),所有的磁盘读写操作都会经过统一的磁盘缓存(除了直接I/O会绕过磁盘缓存)。综合这几点优化特点,如果是针对磁盘的顺序访问,某些情况下它可能比随机的内存访问都要快,甚至可以和网络的速度相差无几。

如图1-6(左)所示,应用程序写入数据到文件系统的一般做法是:在内存中保存尽可能多的数据,并在需要时将这些数据刷新到文件系统。但这里我们要做完全相反的事情,右图中所有的数据都立即写入文件系统的持久化日志文件,但不进行刷新数据的任何调用。数据会首先被传输到磁盘缓存,操作系统随后会将这些数据定期自动刷新到物理磁盘。

消息系统内的消息从生产者保存到服务端,消费者再从服务端读取出来,数据的传输效率决定了生产者和消费者的性能。生产者如果每发送一条消息都直接通过网络发送到服务端,势必会造成过多的网络请求。如果我们能够将多条消息按照分区进行分组,并采用批量的方式一次发送一个消息集,并且对消息集进行压缩,就可以减少网络传输的带宽,进一步提高数据的传输效率。

消费者要读取服务端的数据,需要将服务端的磁盘文件通过网络发送到消费者进程,而网络发送通常涉及不同的网络节点。如图1-7(左)所示,传统读取磁盘文件的数据在每次发送到网络时,都需要将页面缓存先保存到用户缓存,然后在读取消息时再将其复制到内核空间,具体步骤如下。

  1. 操作系统将数据从磁盘中读取文件到内核空间里的页面缓存。

  2. 应用程序将数据从内核空间读入用户空间的缓冲区。

  3. 应用程序将读到的数据写回内核空间并放入 socket 缓冲区。

  4. 操作系统将数据从 socket 缓冲区复制到网卡接口,此时数据才能通过网络发送出去。

结合 Kafka 的消息有多个订阅者的使用场景,生产者发布的消息一般会被不同的消费者消费多次。如图1-7(右)所示,使用“零拷贝技术”(zero-copy)只需将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中(发送给不同的使用者时,都可以重复使用同一个页面缓存),避免了重复的复制操作。这样,消息使用的速度基本上等同于网络连接的速度了。

2. 生产者与消费者

Kafka 的生产者将消息直接发送给分区主副本所在的消息代理节点,并不需要经过任何的中间路由层。为了做到这一点,所有消息代理节点都会保存一份相同的元数据,这份元数据记录了每个主题分区对应的主副本节点。生产者客户端在发送消息之前,会向任意一个代理节点请求元数据,并确定每条消息对应的目标节点,然后把消息直接发送给对应的目标节点。

如图1-8所示,生产者客户端有两种方式决定发布的消息归属于哪个分区:通过随机方式将请求负载到不同的消息代理节点(图1-8左图),或者使用“分区语义函数”将相同键的所有消息发布到同一个分区(图1-8右图)。对于分区语义,Kafka 暴露了一个接口,允许用户指定消息的键如何参与分区。比如,我们可以将用户编号作为消息的键,因为对相同用户编号散列后的值是固定的,所以对应的分区也是固定的。

如图1-9所示,消费者读取消息有两种方式。第一种是消息代理主动地“推送”消息给下游的消费者(图1-9左图),由消息代理控制数据传输的速率,但是消息代理对下游消费者是否能及时处理不得而知。

第二种读取方式是消费者从消息代理主动地“拉取”数据(见图1-9右图),消息代理是无状态的,它不需要标记哪些消息被消费者处理过,也不需要保证一条消息只会被一个消费者处理。

3. 副本机制和容错处理

Kafka 的副本机制会在多个服务端节点(简称节点,即消息代理节点)上对每个主题分区的日志进行复制。当集群中的某个节点出现故障时,访问故障节点的请求会被转移到其他正常节点的副本上。副本的单位是主题的分区,Kafka 每个主题的每个分区都有一个主副本以及0个或多个备份副本。备份副本会保持和主副本的数据同步,用来在主副本失效时替换为主副本。

如图1-10所示,所有的读写请求总是路由到分区的主副本。虽然生产者可以通过负载均衡策略将消息分配到不同的分区,但如果这些分区的主副本都在同一个服务器上(见图1-10左图),就会存在数据热点问题。因此,分区的主副本应该均匀地分配到各个服务器上(见图1-10右图)。通常,分区的数量要比服务器多很多,所以每个服务器都可以成为一些分区的主副本,也能同时成为一些分区的备份副本。

分布式系统处理故障容错时,需要明确地定义节点是否处于存活状态。Kafka 对节点的存活定义有两个条件:

  1. 节点必须和ZK保持会话;

  2. 如果这个节点是某个分区的备份副本,它必须对分区主副本的写操作进行复制,并且复制的进度不能落后太多。

满足这两个条件,叫作 正在同步中(in-sync)。每个分区的主副本会跟踪正在同步中的备份副本节点(In Sync Replicas,即ISR)。如果一个备份副本挂掉、没有响应或者落后太多,主副本就会将其从同步副本集合中移除。反之,如果备份副本重新赶上主副本,它就会加入到主副本的同步集合中。

啰嗦了这么多,想必大家对 Kafka 都有了一个整体的认识,接下来就是要快速开始学习 Kafka 了,分别从单机模式、分布式模式和消费组事例三个方面带领小伙伴慢慢走近 Kafka 的世界。是不是等不及要一探究竟了?那么,我们就一起来翻开这本《Kafka 技术内幕》吧!让你知晓更多别人不知的内幕哦~~



作者:郑奇煌
定价:119.00元

  • 图文详解Kafka的内部原理、设计与实现

  • 全面分析以Kafka为中心的分布式流平台

  • Kafka新特性详解,包括连接器、流处理

Kafka 自 LinkedIn 开源以来就以高性能、高吞吐量、分布式的特性著称,本书以 0.10 版本的源码为基础,深入分析了 Kafka 的设计与实现,包括生产者和消费者的消息处理流程,新旧消费者不同的设计方式,存储层的实现,协调者和控制器如何确保Kafka集群的分布式和容错特性,两种同步集群工具 MirrorMaker 和 uReplicator ,流处理的两种 API 以及 Kafka 的一些高级特性等。

 作者简介

郑奇煌,目前就职于杭州某互联网风控公司,主要专注于大数据和流计算。对源码研究有一定的心得体会,乐于分享,个人博客:zqhxuyuan.github.io。

 本书使用指南

本书主要以 0.10 版本的 Kafka 源码为基础,并通过图文详解的方式分析Kafka 内部组件的实现细节。对于Kafka流处理的一些新特性,本书也会分析 0.11 版本的相关源码。本书各章的主要内容如下。

第1章 首先介绍了 Kafka 作为流式数据平台的3个组成,包括消息系统、存储系统和流处理系统,接着从分区模型、消费模型和分布式模型这三个模型介绍了Kafka的几个基本概念,然后介绍了Kafka几个比较重要的设计思路,最后讨论了如何在一台机器上模拟单机模式与分布式模式,以及如何搭建开发环境。

第2章 从一个生产者的示例开始,引出了新版本生产者的两种消息发送方式。生产者客户端通过记录收集器和发送线程,对消息集进行分组和缓存,并为目标节点创建生产请求,发送到不同的代理节点。接着介绍了与网络相关的Kafka通道、选择器、轮询等NIO操作。另外,还介绍了Scala版本的旧生产者,它使用阻塞通道的方式发送请求。最后,介绍了服务端采用Reactor模式处理客户端的请求。

第3章 首先介绍了消费者相关的基础概念,然后从一个消费者的示例开始,引出了基于ZooKeeper(后面简称ZK)的高级消费者API。要理解高级API,主要是要理解消费线程的模型以及变量的传递方式。接着介绍了消费者提交分区偏移量的两种方式。最后,我们举了一个低级API的示例。开发者需要自己实现一些比较复杂的逻辑处理,才能保证消费程序的健壮性和稳定性。

第4章 介绍了新版本的消费者。不同于旧版本的消费者,新版本去除了ZK的依赖,统一了旧版本的高级API和低级API,并提供了两种消费方式:订阅和分配。新版本引入订阅状态来管理消费者的订阅信息,并使用拉取器拉取消息。新版本的消费者没有使用拉取线程,而是采用轮询的方式拉取消息,它的性能比旧版本的消费者更好。另外,还介绍了消费者采用回调器、处理器、监听器、适配器、组合模式和链式调用等实现不同类型的异步请求。最后,我们介绍了新消费者的心跳任务、消费者提交偏移量以及3种消息处理语义的使用方式。

第5章 介绍了新版本消费者相关的协调者实现,主要包括“加入组”与“同步组”。每个消费者都有一个客户端的协调者,服务端也有一个消费组级别的协调者负责处理所有消费者客户端的请求。当消费组触发再平衡操作时,服务端的协调者会记录消费组元数据的变化,并通过状态机保证消费组状态的正常转换。本章会通过很多不同的示例场景来帮助读者理解消费组相关的实现。

第6章 介绍了Kafka的存储层实现,包括读写、管理、压缩等一些常用的日志操作。服务端通过副本管理器处理客户端的生产请求和拉取请求。接着介绍了副本机制相关的分区、副本、最高水位、复制点等一些概念。最后,介绍了延迟操作接口与延迟缓存。服务端如果不能立即返回响应结果给客户端,会先将延迟操作缓存起来,直到请求处理完成或超时。

第7章 介绍了作为服务端核心的Kafka控制器,它主要负责管理分区状态机和副本状态机,以及多种类型的监听器,比如代理节点上线和下线、删除主题、重新分配分区等。控制器的一个重要职责是选举分区的主副本。不同代理节点根据控制器下发的请求,决定成为分区的主副本还是备份副本。另外,我们还分析了本地副本与远程副本的区别,以及元数据缓存的作用。

第8章 首先介绍了两种集群的同步工具:Kafka内置的MirrorMaker和Uber开源的uReplicator。接着,介绍了新版本Kafka提供的连接器框架,以及如何开发一个自定义的连接器。最后,介绍了连接器的架构模型的具体实现,主要包括数据模型、Connector模型和Worker模型。

第9章 介绍了Kafka流处理的两种API:低级Processor API和高级DSL。这一章重点介绍了流处理的线程模型,主要包括流实例、流线程和流任务。我们还介绍了流处理的本地状态存储,它主要用来作为备份任务的数据恢复。高级DSL包括两个组件——KStream与KTable,它们都定义了一些常用的流处理算子操作,比如无状态的操作(过滤和映射等)、有状态的操作(连接和窗口等)。

第10章 介绍了Kafka的一些高级特性,比如客户端的配额、新的消息格式和事务特性。本书相关的示例代码在笔者的GitHub主页https://github.com/zqhxuyuan/kafka-book上。


第1章 Kafka入门  1

1.1 Kafka流式数据平台  1

1.2 Kafka的基本概念  3

1.3 Kafka的设计与实现  6

1.4 快速开始  11

1.5 环境准备  18

第2章 生产者  22

2.1 新生产者客户端  22

2.2 旧生产者客户端  43

2.3 服务端网络连接  49

2.4 小结  60

第3章 消费者:高级API和低级API  61

3.1 消费者启动和初始化  67

3.2 消费者再平衡操作  73

3.3 消费者拉取数据  82

3.4 消费者消费消息  94

3.5 消费者提交分区偏移量  97

3.6 消费者低级API示例  108

3.7 小结  117

第4章 新消费者  121

4.1 新消费者客户端  125

4.2 消费者的网络客户端轮询  161

4.3 心跳任务  188

4.4 消费者提交偏移量  195

4.5 小结  206

第5章 协调者  210

5.1 消费者加入消费组  211

5.2 协调者处理请求  229

5.3 延迟的加入组操作  242

5.4 消费组状态机  254

5.5 小结  290

第6章 存储层  293

6.1 日志的读写  293

6.2 服务端处理读写请求  348

6.3 延迟操作  373

6.4 小结  400

第7章 控制器  402

7.1 Kafka控制器  402

7.2 服务端处理LeaderAndIsr请求  448

7.3 元数据缓存  468

7.4 Kafka服务关闭  483

7.5 小结  487

第8章 基于Kafka构建数据流管道  490

8.1 Kafka集群同步工具:MirrorMaker   490

8.2 Uber集群同步工具:uReplicator  98

8.3 Kafka连接器  05

8.4 小结  65

第9章 Kafka流处理  69

9.1 低级Processor API  69

9.2 高级流式DSL  36

9.3 小结  84

第10章 高级特性介绍  86

10.1 客户端配额  86

10.2 消息与时间戳  92

10.3 事务处理  99

10.4 小结  03

京东 7.9 折购买

福利时间

本期送出 3 本《Kafka技术内幕》,小伙伴你用过 Kafka 吗?都用它做了哪些项目?可以说说它的优缺点。没用过的小伙伴最期待 Kafka 带给你什么样的惊喜呢?欢迎小伙伴畅所欲言,精选留言选出 3 位小伙伴获得赠书,截止2017年22日17:00。



点击【阅读原文】购买《Kafka技术内幕》


投诉

上一篇:【每日安全资讯】开源邮件代理服务Ex..

下一篇:服务|浦发银行——您身边的跨境人民..

专业的织梦模板定制下载站,在线购买后即可下载!

商业源码

跟版网模板,累计帮助5000+客户企业成功建站,为草根创业提供助力!

立刻开启你的建站之旅

QQ在线客服

服务热线

织梦建站咨询