Kafka 知识体系保姆级教程宝典

本文目录

一、消息队列    Apache Pulsar    Pulsar 与 Kafka 对比二、Kafka基础三、Kafka架构及组件四、Kafka集群操作五、Kafka的JavaAPI操作六、Kafka中的数据不丢失机制七、Kafka配置文件说明八、CAP理论九、Kafka中的CAP机制十、Kafka监控及运维十一、Kafka大厂面试题

Kafka 涉及的知识点如下图所示,本文将逐一讲解:

docx image

本文档参考了关于 Kafka 的官网及其他众多资料整理而成,为了整洁的排版及舒适的阅读,对于模糊不清晰的图片及黑白图片进行重新绘制成了高清彩图

docx image

一、消息队列

1. 消息队列的介绍

消息(Message)是指在应用之间传送的数据,消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,有消息系统来确保信息的可靠专递,消息发布者只管把消息发布到MQ中而不管谁来取,消息使用者只管从MQ中取消息而不管谁发布的,这样发布者和使用者都不用知道对方的存在。

2. 消息队列的应用场景

消息队列在实际应用中包括如下四个场景:

应用耦合

异步处理

限流削峰

消息驱动的系统

下面详细介绍上述四个场景以及消息队列如何在上述四个场景中使用:

具体场景:用户为了使用某个应用,进行注册,系统需要发送注册邮件并验证短信。对这两个操作的处理方式有两种:串行及并行。

docx image

串行方式:新注册信息生成后,先发送注册邮件,再发送验证短信;

在这种方式下,需要最终发送验证短信后再返回给客户端。

docx image

并行处理:新注册信息写入后,由发短信和发邮件并行处理;

在这种方式下,发短信和发邮件 需处理完成后再返回给客户端。假设以上三个子系统处理的时间均为50ms,且不考虑网络延迟,则总的处理时间:

串行:50+50+50=150ms并行:50+50 = 100ms

若使用消息队列:

docx image

在写入消息队列后立即返回成功给客户端,则总的响应时间依赖于写入消息队列的时间,而写入消息队列的时间本身是可以很快的,基本可以忽略不计,因此总的处理时间相比串行提高了2倍,相比并行提高了一倍;

具体场景:用户使用QQ相册上传一张图片,人脸识别系统会对该图片进行人脸识别,一般的做法是,服务器接收到图片后,图片上传系统立即调用人脸识别系统,调用完成后再返回成功,如下图所示:

docx image

该方法有如下缺点:

人脸识别系统被调失败,导致图片上传失败;

延迟高,需要人脸识别系统处理完成后,再返回给客户端,即使用户并不需要立即知道结果;

图片上传系统与人脸识别系统之间互相调用,需要做耦合;

若使用消息队列:

docx image

客户端上传图片后,图片上传系统将图片信息如uin、批次写入消息队列,直接返回成功;而人脸识别系统则定时从消息队列中取数据,完成对新增图片的识别。

此时图片上传系统并不需要关心人脸识别系统是否对这些图片信息的处理、以及何时对这些图片信息进行处理。事实上,由于用户并不需要立即知道人脸识别结果,人脸识别系统可以选择不同的调度策略,按照闲时、忙时、正常时间,对队列中的图片信息进行处理。

docx image

具体场景:购物网站开展秒杀活动,一般由于瞬时访问量过大,服务器接收过大,会导致流量暴增,相关系统无法处理请求甚至崩溃。而加入消息队列后,系统可以从消息队列中取数据,相当于消息队列做了一次缓冲。该方法有如下优点:

请求先入消息队列,而不是由业务处理系统直接处理,做了一次缓冲,极大地减少了业务处理系统的压力;

队列长度可以做限制,事实上,秒杀时,后入队列的用户无法秒杀到商品,这些请求可以直接被抛弃,返回活动已结束或商品已售完信息;

消息驱动的系统

docx image

具体场景:用户新上传了一批照片,人脸识别系统需要对这个用户的所有照片进行聚类,聚类完成后由对账系统重新生成用户的人脸索引(加快查询)。这三个子系统间由消息队列连接起来,前一个阶段的处理结果放入队列中,后一个阶段从队列中获取消息继续处理。该方法有如下优点:

避免了直接调用下一个系统导致当前系统失败;

每个子系统对于消息的处理方式可以更为灵活,可以选择收到消息时就处理,可以选择定时处理,也可以划分时间段按不同处理速度处理;

3. 消息队列的两种模式

消息队列包括两种模式,点对点模式(point to point, queue)和发布/订阅模式(publish/subscribe,topic)

1) 点对点模式

点对点模式下包括三个角色:

docx image

点对点模式特点:

2) 发布/订阅模式

发布/订阅模式下包括三个角色:

docx image

发布/订阅模式特点:

4. 常用的消息队列介绍

1) RabbitMQ

RabbitMQ 2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。

2) ActiveMQ

ActiveMQ是由Apache出品,ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。它非常快速,支持多种语言的客户端和协议,而且可以非常容易的嵌入到企业的应用环境中,并有许多高级功能。

3) RocketMQ

RocketMQ出自 阿里公司的开源产品,用 Java 语言实现,在设计时参考了 Kafka,并做出了自己的一些改进,消息可靠性上比 Kafka 更好。RocketMQ在阿里集团被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理等。

4) Kafka

Apache Kafka是一个分布式消息发布订阅系统。它最初由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统( a distributed commit log),,之后成为Apache项目的一部分。Kafka系统快速、可扩展并且可持久化。它的分区特性,可复制和可容错都是其不错的特性。

5. Pulsar

Apahce Pulasr是一个企业级的发布-订阅消息系统,最初是由雅虎开发,是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体,采用计算与存储分离架构设计,支持多租户、持久化存储、多机房跨区域数据复制,具有强一致性、高吞吐、低延时及高可扩展性等流数据存储特性。

Pulsar 非常灵活:它既可以应用于像 Kafka 这样的分布式日志应用场景,也可以应用于像 RabbitMQ 这样的纯消息传递系统场景。它支持多种类型的订阅、多种交付保证、保留策略以及处理模式演变的方法,以及其他诸多特性。

1. Pulsar 的特性

内置多租户

多层体系结构

虚拟 topic

N 层存储

2. Pulsar 存储架构

Pulsar 将 topic 分区划分为分片(segment),然后将这些分片存储在 Apache BookKeeper 的存储节点上,以提高性能、可伸缩性和可用性

docx image

Pulsar 的无限分布式日志以分片为中心,借助扩展日志存储(通过 Apache BookKeeper)实现,内置分层存储支持,因此分片可以均匀地分布在存储节点上。由于与任一给定 topic 相关的数据都不会与特定存储节点进行捆绑,因此很容易替换存储节点或缩扩容。另外,集群中最小或最慢的节点也不会成为存储或带宽的短板。

分区管理,负载均衡

通过性能强大的 Netty 架构,数据从 producers 到 broker,再到 bookie 的转移都是零拷贝,不会生成副本。这一特性对所有流应用场景都非常友好,因为数据直接通过网络或磁盘进行传输,没有任何性能损失。

3. Pulsar 消息消费

Pulsar 的消费模型采用了流拉取的方式。流拉取是长轮询的改进版,不仅实现了单个调用和请求之间的零等待,还可以提供双向消息流。通过流拉取模型,Pulsar 实现了端到端的低延迟,这种低延迟比所有现有的长轮询消息系统(如 Kafka)都低。

6. Kafka与Pulsar对比

1. Pulsar 的主要优势:

更多功能:Pulsar Function、多租户、Schema registry、n 层存储、多种消费模式和持久性模式等;

更大的灵活性:3 种订阅类型(独占,共享和故障转移),用户可以在一个订阅上管理多个 topic;

易于操作运维:架构解耦和 n 层存储;

与 Presto 的 SQL 集成,可直接查询存储而不会影响 broker;

借助 n 层自动存储选项,可以更低成本地存储;

2. Pulsar 的劣势

Pulsar 并不完美,Pulsar 也存在一些问题:

相对缺乏支持、文档和案例;

n 层体系结构导致需要更多组件:BookKeeper;

插件和客户端相对 Kafka 较少;

云中的支持较少,Confluent 具有托管云产品。

3. 什么时候应该考虑 Pulsar

同时需要像 RabbitMQ 这样的队列和 Kafka 这样的流处理程序;

需要易用的地理复制;

实现多租户,并确保每个团队的访问权限;

需要长时间保留消息,并且不想将其卸载到另一个存储中;

需要高性能,基准测试表明 Pulsar 提供了更低的延迟和更高的吞吐量;

总之,Pulsar还比较新,社区不完善,用的企业比较少,网上有价值的讨论和问题的解决比较少,远没有Kafka生态系统庞大,且用户量非常庞大,目前Kafka依旧是大数据领域消息队列的王者!所以我们还是以Kafka为主!

7. 其他消息队列与Kafka对比

docx image

二、Kafka基础

1. kafka的基本介绍

官网:http://kafka.apache.org/

kafka是最初由linkedin公司开发的,使用scala语言编写,kafka是一个分布式,分区的,多副本的,多订阅者的日志系统(分布式MQ系统),可以用于搜索日志,监控日志,访问日志等。

Kafka is a distributed,partitioned,replicated commit logservice。它提供了类似于JMS的特性,但是在设计实现上完全不同,此外它并不是JMS规范的实现。kafka对消息保存时根据Topic进行归类,发送消息者成为Producer,消息接受者成为Consumer,此外kafka集群有多个kafka实例组成,每个实例(server)成为broker。无论是kafka集群,还是producer和consumer都依赖于zookeeper来保证系统可用性集群保存一些meta信息。

2. kafka的好处

3. 分布式的发布与订阅系统

apache kafka是一个分布式发布-订阅消息系统和一个强大的队列,可以处理大量的数据,并使能够将消息从一个端点传递到另一个端点,kafka适合离线和在线消息消费。kafka消息保留在磁盘上,并在集群内复制以防止数据丢失。kafka构建在zookeeper同步服务之上。它与apache和spark非常好的集成,应用于实时流式数据分析。

4. kafka的主要应用场景

1. 指标分析

kafka 通常用于操作监控数据。这设计聚合来自分布式应用程序的统计信息,   以产生操作的数据集中反馈

2. 日志聚合解决方法

kafka可用于跨组织从多个服务器收集日志,并使他们以标准的格式提供给多个服务器。

3. 流式处理

流式处理框架(spark,storm,flink)重主题中读取数据,对齐进行处理,并将处理后的数据写入新的主题,供 用户和应用程序使用,kafka的强耐久性在流处理的上下文中也非常的有用。

三、Kafka架构及组件

1. kafka架构

docx image

允许应用程序发布记录流至一个或者多个kafka的主题(topics)。

允许应用程序订阅一个或者多个主题,并处理这些主题接收到的记录流。

StreamsAPI

允许应用程序充当流处理器(stream processor),从一个或者多个主题获取输入流,并生产一个输出流到一个或 者多个主题,能够有效的变化输入流为输出流。

允许构建和运行可重用的生产者或者消费者,能够把kafka主题连接到现有的应用程序或数据系统。例如:一个连接到关系数据库的连接器可能会获取每个表的变化。

docx image

在Kafka 2.8.0 版本,移除了对Zookeeper的依赖,通过KRaft进行自己的集群管理

过去Apache ZooKeeper是Kafka这类分布式系统的关键,ZooKeeper扮演协调代理的角色,所有代理服务器启动时,都会连接到Zookeeper进行注册,当代理状态发生变化时,Zookeeper也会储存这些数据,在过去,ZooKeeper是一个强大的工具,但是毕竟ZooKeeper是一个独立的软件,使得Kafka整个系统变得复杂,因此官方决定使用内部Quorum控制器来取代ZooKeeper。

Kafka Raft元数据模式(KRaft)

好,说完在新版本中移除zookeeper这个事,咱们在接着聊kafka的其他功能:

消息消费完后,不会立即删除,会保留历史消息

2. Kafka 主要组件

1. producer(生产者)

producer主要是用于生产消息,是kafka当中的消息生产者,生产的消息通过topic进行归类,保存到kafka的broker里面去。

2. topic(主题)
3. partition(分区)

kafka当中,topic是消息的归类,一个topic可以有多个分区(partition),每个分区保存部分topic的数据,所有的partition当中的数据全部合并起来,就是一个topic当中的所有的数据。

每一个分区内的数据是有序的,但全局的数据不能保证是有序的。

4. consumer(消费者)

consumer是kafka当中的消费者,主要用于消费kafka当中的数据,消费者一定是归属于某个消费组中的。

5. consumer group(消费者组)

同一个组中的消费者对于同一条消息只消费一次

每个消费者都属于某个消费者组,如果不指定,那么所有的消费者都属于默认的组。

每个分区只能由同一个消费组内的一个消费者(consumer)来消费消费组

partition数量决定了每个consumer group中并发消费者的最大数量

docx image

如上面左图所示,如果只有两个分区,即使一个组内的消费者有4个,也会有两个空闲的。如上面右图所示,有4个分区,每个消费者消费一个分区,并发量达到最大4。

在来看如下一幅图:

docx image

如上图所示,不同的消费者组消费同一个topic,这个topic有4个分区,分布在两个节点上。左边的 消费组1有两个消费者,每个消费者就要消费两个分区才能把消息完整的消费完,右边的 消费组2有四个消费者,每个消费者消费一个分区即可。

总结下kafka中分区与消费组的关系

某一个主题下的分区数,对于消费该主题的同一个消费组下的消费者数量,应该小于等于该主题下的分区数

同一个分区下的数据,在同一时刻,不能同一个消费组的不同消费者消费

分区数越多,同一时间可以有越多的消费者来进行消费,消费数据的速度就会越快,提高消费的性能

6. partition replicas(分区副本)

kafka 中的分区副本如下图所示:

docx image

副本数

创建主题时,副本因子应该小于等于可用的broker数

副本因子操作以分区为单位的。每个分区都有各自的主副本和从副本;

处于同步状态的副本叫做in-sync-replicas(ISR)

消费者和生产者都是从leader读写数据,不与follower交互

副本因子的作用:让kafka读取数据和写入数据时的可靠性。

副本因子是包含本身,同一个副本因子不能放在同一个broker中。

如果某一个分区有三个副本因子,就算其中一个挂掉,那么只会剩下的两个中,选择一个leader,但不会在其他的broker中,另启动一个副本(因为在另一台启动的话,存在数据传递,只要在机器之间有数据传递,就会长时间占用网络IO,kafka是一个高吞吐量的消息系统,这个情况不允许发生)所以不会在另一个broker中启动。

如果所有的副本都挂了,生产者如果生产数据到指定分区的话,将写入不成功。

lsr表示:当前可用的副本。

7. segment文件

一个partition当中由多个segment文件组成,每个segment文件,包含两部分,一个是 .log 文件,另外一个是 .index 文件,其中 .log 文件包含了我们发送的数据存储,.index 文件,记录的是我们.log文件的数据索引值,以便于我们加快数据的查询速度。

索引文件与数据文件的关系

既然它们是一一对应成对出现,必然有关系。索引文件中元数据指向对应数据文件中message的物理偏移地址。

比如索引文件中 3,497 代表:数据文件中的第三个message,它的偏移地址为497。

再来看数据文件中,Message 368772表示:在全局partiton中是第368772个message。

注:segment index file 采取稀疏索引存储方式,减少索引文件大小,通过mmap(内存映射)可以直接内存操作,稀疏索引为数据文件的每个对应message设置一个元数据指针,它比稠密索引节省了更多的存储空间,但查找起来需要消耗更多的时间。

.index 与 .log 对应关系如下:

docx image

上图左半部分是索引文件,里面存储的是一对一对的key-value,其中key是消息在数据文件(对应的log文件)中的编号,比如“1,3,6,8……”,分别表示在log文件中的第1条消息、第3条消息、第6条消息、第8条消息……

那么为什么在index文件中这些编号不是连续的呢?这是因为index文件中并没有为数据文件中的每条消息都建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。但缺点是没有建立索引的Message也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。

value 代表的是在全局partiton中的第几个消息。

以索引文件中元数据 3,497 为例,其中3代表在右边log数据文件中从上到下第3个消息,497表示该消息的物理偏移地址(位置)为497(也表示在全局partiton表示第497个消息-顺序写入特性)。

log日志目录及组成

在目录下的文件,会根据log日志的大小进行切分,.log文件的大小为1G的时候,就会进行切分文件;如下:

在kafka的设计中,将offset值作为了文件名的一部分。

segment文件命名规则

通过索引信息可以快速定位到message。通过index元数据全部映射到内存,可以避免segment File的IO磁盘操作;

通过索引文件稀疏存储,可以大幅降低index文件元数据占用空间大小。

稀疏索引:为了数据创建索引,但范围并不是为每一条创建,而是为某一个区间创建;好处:就是可以减少索引值的数量。不好的地方:找到索引区间之后,要得进行第二次处理。

8. message的物理结构

生产者发送到kafka的每条消息,都被kafka包装成了一个message

message 的物理结构如下图所示:

docx image

所以生产者发送给kafka的消息并不是直接存储起来,而是经过kafka的包装,每条消息都是上图这个结构,只有最后一个字段才是真正生产者发送的消息数据。

四、Kafka集群操作

1. 创建topic

创建一个名字为test的主题, 有三个分区,有两个副本:

2. 查看主题命令

查看kafka当中存在的主题:

3. 生产者生产数据

模拟生产者来生产数据:

4. 消费者消费数据

执行以下命令来模拟消费者进行消费数据:

5. 运行describe  topics命令

执行以下命令运行describe查看topic的相关信息:

结果说明:

这是输出的解释。第一行给出了所有分区的摘要,每个附加行提供有关一个分区的信息。由于我们只有一个分 区用于此主题,因此只有一行。

“leader”是负责给定分区的所有读取和写入的节点。每个节点将成为随机选择的分区部分的领导者。(因为在kafka中 如果有多个副本的话,就会存在leader和follower的关系,表示当前这个副本为leader所在的broker是哪一个)

“replicas”是复制此分区日志的节点列表,无论它们是否为领导者,或者即使它们当前处于活动状态。(所有副本列表0,1,2)

“isr”是“同步”复制品的集合。这是副本列表的子集,该列表当前处于活跃状态并且已经被领导者捕获。(可用的列表数)

6. 增加topic分区数

执行以下命令可以增加topic分区数:

7. 增加配置

动态修改kakfa的配置:

8. 删除配置

动态删除kafka集群配置:

9.  删除topic

目前删除topic在默认情况下知识打上一个删除的标记,在重新启动kafka后才删除。

如果需要立即删除,则需要在server.properties中配置:

delete.topic.enable=true

然后执行以下命令进行删除topic:

五、Kafka的JavaAPI操作

1. 生产者代码

使用生产者,生产数据

kafka当中的数据分区

kafka生产者发送的消息,都是保存在broker当中,我们可以自定义分区规则,决定消息发送到哪个partition里面去进行保存查看ProducerRecord这个类的源码,就可以看到kafka的各种不同分区策略

kafka当中支持以下四种数据的分区方式:

自定义分区策略

主代码中添加配置

2. 消费者代码

消费必要条件

消费者要从kafka  Cluster进行消费数据,必要条件有以下四个:

地址:bootstrap.servers=node01:9092

序列化:key.serializer=org.apache.kafka.common.serialization.StringSerializer value.serializer=org.apache.kafka.common.serialization.StringSerializer

主题(topic):需要制定具体的某个topic(order)即可。

消费者组:group.id=test

1) 自动提交offset

消费完成之后,自动提交offset:

2) 手动提交offset

如果Consumer在获取数据后,需要加入处理,数据完毕后才确认offset,需要程序来控制offset的确认。

关闭自动提交确认选项:props.put(“enable.auto.commit”, “false”);

手动提交offset值:kafkaConsumer.commitSync();

完整代码如下:

3) 消费完每个分区之后手动提交offset

上面的示例使用commitSync将所有已接收的记录标记为已提交。在某些情况下,可能希望通过明确指定偏移量来更好地控制已提交的记录。在下面的示例中,我们在完成处理每个分区中的记录后提交偏移量:

注意事项

提交的偏移量应始终是应用程序将读取的下一条消息的偏移量。因此,在调用commitSync(偏移量)时,应该在最后处理的消息的偏移量中添加一个。

4) 指定分区数据进行消费

如果进程正在维护与该分区关联的某种本地状态(如本地磁盘上的键值存储),那么它应该只获取它在磁盘上维护的分区的记录。

如果进程本身具有高可用性,并且如果失败则将重新启动(可能使用YARN,Mesos或AWS工具等集群管理框 架,或作为流处理框架的一部分)。在这种情况下,Kafka不需要检测故障并重新分配分区,因为消耗过程将在另一台机器上重新启动。

注意事项

要使用此模式,只需使用要使用的分区的完整列表调用assign(Collection),而不是使用subscribe订阅主题。

主题与分区订阅只能二选一。

5) 重复消费与数据丢失

说明:

已经消费的数据对于kafka来说,会将消费组里面的offset值进行修改,那什么时候进行修改了?是在数据消费 完成之后,比如在控制台打印完后自动提交;

提交过程:是通过kafka将offset进行移动到下个message所处的offset的位置。

拿到数据后,存储到hbase中或者mysql中,如果hbase或者mysql在这个时候连接不上,就会抛出异常,如果在处理数据的时候已经进行了提交,那么kafka伤的offset值已经进行了修改了,但是hbase或者mysql中没有数据,这个时候就会出现数据丢失。

4.什么时候提交offset值?在Consumer将数据处理完成之后,再来进行offset的修改提交。默认情况下offset是 自动提交,需要修改为手动提交offset值。

6) consumer消费者消费数据流程

流程描述

Consumer连接指定的Topic partition所在leader broker,采用pull方式从kafkalogs中获取消息。对于不同的消费模式,会将offset保存在不同的地方官网关于high level  API  以及low  level  API的简介:http://kafka.apache.org/0100/documentation.html#impl_consumer

高阶API(High Level API)

kafka消费者高阶API简单;隐藏Consumer与Broker细节;相关信息保存在zookeeper中:

说明

低级API(Low Level API)

kafka消费者低级API非常灵活;需要自己负责维护连接Controller Broker。保存offset,Consumer Partition对应关系:

说明

3. kafka Streams API开发

需求

第一步

node01服务器使用以下命令来常见一个 topic 名称为test2:

第二步

testtest2

第三步

node01执行以下命令,向test这个topic当中生产数据:

第四步

node02执行一下命令消费test2这个topic当中的数据:

六、Kafka中的数据不丢失机制

1. 生产者生产数据不丢失

发送消息方式

同步方式异步方式

同步方式

发送一批数据给kafka后,等待kafka返回结果:

异步方式

发送一批数据给kafka,只是提供一个回调函数:

注:如果broker迟迟不给ack,而buffer又满了,开发者可以设置是否直接清空buffer中的数据。

ack机制(确认机制)

生产者数据发送出去,需要服务端返回一个确认码,即ack响应码;ack的响应有三个状态值0,1,-1

0:生产者只负责发送数据,不关心数据是否丢失,丢失的数据,需要再次发送

1:partition的leader收到数据,不管follow是否同步完数据,响应的状态码为1

-1:所有的从节点都收到数据,响应的状态码为-1

如果broker端一直不返回ack状态,producer永远不知道是否成功;producer可以设置一个超时时间10s,超过时间认为失败。

2. broker中数据不丢失

在broker中,保证数据不丢失主要是通过副本因子(冗余),防止数据丢失。

3. 消费者消费数据不丢失

在消费者消费数据的时候,只要每个消费者记录好offset值即可,就能保证数据不丢失。也就是需要我们自己维护偏移量(offset),可保存在 Redis 中。

文章首发于公众号:五分钟学大数据,深度钻研大数据技术

七、Kafka配置文件说明

Server.properties配置文件说明

consumer消费者配置详细说明

八、CAP理论

1. 分布式系统当中的CAP理论

分布式系统(distributed system)正变得越来越重要,大型网站几乎都是分布式的。

分布式系统的最大难点,就是各个节点的状态如何同步。

为了解决各个节点之间的状态同步问题,在1998年,由加州大学的计算机科学家 Eric Brewer 提出分布式系统的三个指标,分别是:

Consistency:一致性

Availability:可用性

Partition tolerance:分区容错性

Eric Brewer 说,这三个指标不可能同时做到。最多只能同时满足其中两个条件,这个结论就叫做 CAP 定理。

CAP理论是指:分布式系统中,一致性、可用性和分区容忍性最多只能同时满足两个

一致性:Consistency

可用性:Availability

分区容错性:Partition tolerance

一般而言,都要求保证分区容忍性。所以在CAP理论下,更多的是需要在可用性和一致性之间做权衡。

docx image

2. Partition tolerance

先看 Partition tolerance,中文叫做”分区容错”。

大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。

docx image

上图中,G1 和 G2 是两台跨区的服务器。G1 向 G2 发送一条消息,G2 可能无法收到。系统设计的时候,必须考虑到这种情况。

一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是存在的。即永远可能存在分区容错这个问题

3. Consistency

docx image

docx image

Consistency 中文叫做”一致性”。意思是,写操作之后的读操作,必须返回该值。举例来说,某条记录是 v0,用户向 G1 发起一个写操作,将其改为 v1。接下来,用户的读操作就会得到 v1。这就叫一致性。问题是,用户有可能向 G2 发起读操作,由于 G2 的值没有发生变化,因此返回的是 v0。G1 和 G2 读操作的结果不一致,这就不满足一致性了。

docx image

为了让 G2 也能变为 v1,就要在 G1 写操作的时候,让 G1 向 G2 发送一条消息,要求 G2 也改成 v1。

docx image

这样的话,用户向 G2 发起读操作,也能得到 v1。

docx image

4. Availability

Availability 中文叫做”可用性”,意思是只要收到用户的请求,服务器就必须给出回应。用户可以选择向 G1 或 G2 发起读操作。不管是哪台服务器,只要收到请求,就必须告诉用户,到底是 v0 还是 v1,否则就不满足可用性。

九、Kafka中的CAP机制

kafka是一个分布式的消息队列系统,既然是一个分布式的系统,那么就一定满足CAP定律,那么在kafka当中是如何遵循CAP定律的呢?kafka满足CAP定律当中的哪两个呢?

kafka满足的是CAP定律当中的CA,其中Partition  tolerance通过的是一定的机制尽量的保证分区容错性

其中C表示的是数据一致性。A表示数据可用性

kafka首先将数据写入到不同的分区里面去,每个分区又可能有好多个副本,数据首先写入到leader分区里面去,读写的操作都是与leader分区进行通信,保证了数据的一致性原则,也就是满足了Consistency原则。然后kafka通过分区副本机制,来保证了kafka当中数据的可用性。但是也存在另外一个问题,就是副本分区当中的数据与leader当中的数据存在差别的问题如何解决,这个就是Partition tolerance的问题。

kafka为了解决Partition tolerance的问题,使用了ISR的同步策略,来尽最大可能减少Partition tolerance的问题

每个leader会维护一个ISR(a set of in-sync replicas,基本同步)列表。

ISR列表主要的作用就是决定哪些副本分区是可用的,也就是说可以将leader分区里面的数据同步到副本分区里面去,决定一个副本分区是否可用的条件有两个:

replica.lag.time.max.ms=10000     副本分区与主分区心跳时间延迟

replica.lag.max.messages=4000    副本分区与主分区消息同步最大差

produce 请求被认为完成时的确认值:request.required.acks=0。

十、Kafka监控及运维

在开发工作中,消费在Kafka集群中消息,数据变化是我们关注的问题,当业务前提不复杂时,我们可以使用Kafka 命令提供带有Zookeeper客户端工具的工具,可以轻松完成我们的工作。随着业务的复杂性,增加Group和 Topic,那么我们使用Kafka提供命令工具,已经感到无能为力,那么Kafka监控系统目前尤为重要,我们需要观察 消费者应用的细节。

1. kafka-eagle概述

为了简化开发者和服务工程师维护Kafka集群的工作有一个监控管理工具,叫做 Kafka-eagle。这个管理工具可以很容易地发现分布在集群中的哪些topic分布不均匀,或者是分区在整个集群分布不均匀的的情况。它支持管理多个集群、选择副本、副本重新分配以及创建Topic。同时,这个管理工具也是一个非常好的可以快速浏览这个集群的工具,

2. 环境和安装

1. 环境要求

需要安装jdk,启动zk以及kafka的服务

2. 安装步骤

kafka-eagle官网:http://download.kafka-eagle.org/

我们可以从官网上面直接下载最细的安装包即可kafka-eagle-bin-1.3.2.tar.gz这个版本即可

代码托管地址:

https://github.com/smartloli/kafka-eagle/releases

这里我们选择将kafak-eagle安装在第三台。

直接将kafka-eagle安装包上传到node03服务器的/export/softwares路径下,然后进行解压node03服务器执行一下命令进行解压。

kafka-eagle需要使用一个数据库来保存一些元数据信息,我们这里直接使用msyql数据库来保存即可,在node03服务器执行以下命令创建一个mysql数据库即可。

进入mysql客户端:

执行以下命令修改kafak-eagle配置文件:

修改为如下:

kafka-eagle必须配置环境变量,node03服务器执行以下命令来进行配置环境变量: vim /etc/profile:

修改立即生效,执行: source /etc/profile

执行以下界面启动kafka-eagle:

访问kafka-eagle

http://node03:8048/ke/account/signin?/ke/

用户名:admin

密码:123456

docx image

十一、Kafka大厂面试题

1. 为什么要使用 kafka?

缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间可以起到一个缓冲的作用,把消息暂存在kafka中,下游服务就可以按照自己的节奏进行慢慢处理。

解耦和扩展性:项目开始的时候,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。

冗余:可以采用一对多的方式,一个生产者发布消息,可以被多个订阅topic的服务消费到,供多个毫无关联的业务使用。

健壮性:消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。

异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。

2. Kafka消费过的消息如何再消费?

kafka消费消息的offset是定义在zookeeper中的,如果想重复消费kafka的消息,可以在redis中自己记录offset的checkpoint点(n个),当想重复消费消息时,通过读取redis中的checkpoint点进行zookeeper的offset重设,这样就可以达到重复消费消息的目的了

3. kafka的数据是放在磁盘上还是内存上,为什么速度会快?

kafka使用的是磁盘存储。

速度快是因为:

4. Kafka数据怎么保障不丢失?

分三个点说,一个是生产者端,一个消费者端,一个broker端。

kafka的ack机制:在kafka发送数据的时候,每次发送消息都会有一个确认反馈机制,确保消息正常的能够被收到,其中状态有0,1,-1。

如果是同步模式:ack设置为0,风险很大,一般不建议设置为0。即使设置为1,也会随着leader宕机丢失数据。所以如果要严格保证生产端数据不丢失,可设置为-1。

如果是异步模式:也会考虑ack的状态,除此之外,异步模式下的有个buffer,通过buffer来进行控制数据的发送,有两个值来进行控制,时间阈值与消息的数量阈值,如果buffer满了数据还没有发送出去,有个选项是配置是否立即清空buffer。可以设置为-1,永久阻塞,也就数据不再生产。异步模式下,即使设置为-1。也可能因为程序员的不科学操作,操作数据丢失,比如kill -9,但这是特别的例外情况。

注:ack=0:producer不等待broker同步完成的确认,继续发送下一条(批)信息。ack=1(默认):producer要等待leader成功收到数据并得到确认,才发送下一条message。ack=-1:producer得到follwer确认,才发送下一条数据。

通过offset commit 来保证数据的不丢失,kafka自己记录了每次消费的offset数值,下次继续消费的时候,会接着上次的offset进行消费。

而offset的信息在kafka0.8版本之前保存在zookeeper中,在0.8版本之后保存到topic中,即使消费者在运行过程中挂掉了,再次启动的时候会找到offset的值,找到之前消费消息的位置,接着消费,由于 offset 的信息写入的时候并不是每条消息消费完成后都写入的,所以这种情况有可能会造成重复消费,但是不会丢失消息。

唯一例外的情况是,我们在程序中给原本做不同功能的两个consumer组设置KafkaSpoutConfig.bulider.setGroupid的时候设置成了一样的groupid,这种情况会导致这两个组共享同一份数据,就会产生组A消费partition1,partition2中的消息,组B消费partition3的消息,这样每个组消费的消息都会丢失,都是不完整的。为了保证每个组都独享一份消息数据,groupid一定不要重复才行。

每个broker中的partition我们一般都会设置有replication(副本)的个数,生产者写入的时候首先根据分发策略(有partition按partition,有key按key,都没有轮询)写入到leader中,follower(副本)再跟leader同步数据,这样有了备份,也可以保证消息数据的不丢失。

5. 采集数据为什么选择kafka?

采集层 主要可以使用Flume, Kafka等技术。

Flume:Flume 是管道流方式,提供了很多的默认实现,让用户通过参数部署,及扩展API.

Kafka:Kafka是一个可持久化的分布式的消息队列。Kafka 是一个非常通用的系统。你可以有许多生产者和很多的消费者共享多个主题Topics。

相比之下,Flume是一个专用工具被设计为旨在往HDFS,HBase发送数据。它对HDFS有特殊的优化,并且集成了Hadoop的安全特性。

所以,Cloudera 建议如果数据被多个系统消费的话,使用kafka;如果数据被设计给Hadoop使用,使用Flume。

6. kafka 重启是否会导致数据丢失?
7. kafka 宕机了如何解决?

kafka 宕机了,首先我们考虑的问题应该是所提供的服务是否因为宕机的机器而受到影响,如果服务提供没问题,如果实现做好了集群的容灾机制,那么这块就不用担心了。

想要恢复集群的节点,主要的步骤就是通过日志分析来查看节点宕机的原因,从而解决,重新恢复节点。

8. 为什么Kafka不支持读写分离?

主写主读主写从读

数据一致性问题:数据从主节点转到从节点必然会有一个延时的时间窗口,这个时间 窗口会导致主从节点之间的数据不一致。某一时刻,在主节点和从节点中 A 数据的值都为 X, 之后将主节点中 A 的值修改为 Y,那么在这个变更通知到从节点之前,应用读取从节点中的 A 数据的值并不为最新的 Y,由此便产生了数据不一致的问题。

延时问题:类似 Redis 这种组件,数据从写入主节点到同步至从节点中的过程需要经历 网络→主节点内存→网络→从节点内存 这几个阶段,整个过程会耗费一定的时间。而在 Kafka 中,主从同步会比 Redis 更加耗时,它需要经历 网络→主节点内存→主节点磁盘→网络→从节 点内存→从节点磁盘 这几个阶段。对延时敏感的应用而言,主写从读的功能并不太适用。

主写主读

9. kafka数据分区和消费者的关系?

每个分区只能由同一个消费组内的一个消费者(consumer)来消费,可以由不同的消费组的消费者来消费,同组的消费者则起到并发的效果。

10. kafka的数据offset读取流程

连接ZK集群,从ZK中拿到对应topic的partition信息和partition的Leader的相关信息

连接到对应Leader对应的broker

consumer将⾃自⼰己保存的offset发送给Leader

Leader根据offset等信息定位到segment(索引⽂文件和⽇日志⽂文件)

根据索引⽂文件中的内容,定位到⽇日志⽂文件中该偏移量量对应的开始位置读取相应⻓长度的数据并返回给consumer

11. kafka内部如何保证顺序,结合外部组件如何保证消费者的顺序?

kafka只能保证partition内是有序的,但是partition间的有序是没办法的。爱奇艺的搜索架构,是从业务上把需要有序的打到同⼀个partition。

12. Kafka消息数据积压,Kafka消费能力不足怎么处理?

如果是Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数=分区数。(两者缺一不可)

如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间<生产速度),使处理的数据小于生产的数据,也会造成数据积压。

13.  Kafka单条日志传输大小

kafka对于消息体的大小默认为单条最大值是1M但是在我们应用场景中, 常常会出现一条消息大于1M,如果不对kafka进行配置。则会出现生产者无法将消息推送到kafka或消费者无法去消费kafka里面的数据, 这时我们就要对kafka进行以下配置:server.properties

注意:message.max.bytes必须小于等于replica.fetch.max.bytes,否则就会导致replica之间数据同步失败。

最后

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容