Kafka架构及其原理

简介: Kafka架构及其原理

架构图


一个kafka集群中包含一个或多个Producer、一个或多个broker、一个或多个ConsumerGrop以及一个Zookeeper集群。kafka通过Zookeeper管理kafka集群配置、leader副本的选举、生产者的负载均衡等。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。


专业术语

  1. kafkaCluster : kafka集群,由一个或多个Broker节点组成。
  2. Broker : 一个Kafka集群包括一个或多个服务器,一台服务器就是一个Broker节点。Broker用于保存Producer发送的消息。
  3. Producer :生产者,用来发送指定的Topic的消息到Broker。生产者可以是代码,还可以是命令行工具。本质上是一个进程或者线程。
  4. Consumer :消费者,用来接收/消费Kafka集群中的消息。每个Consumer属于一个ConsumerGroup(如果在创建消费者时没有指定Consumer,系统会默认分配一个ConsumerGroup),消费者可以是代码,还可以是命令行工具,本质上就是一个进程/线程。
  5. ConsumerGroup :消费者组,由一个或多个Consumer组成(在同一个消费者组的消费者具有相同的group.id),便于管理Consumer。
  6. Zookeeper :在Kafka集群中用来存储元数据,如:有Broker节点信息、分区的信息、分区与Broker的对应关系、生产者的负载均衡等等。
  7. Topic :主题,主题用于区分业务,比如订单主题业务,购物车主题业务,物流主题业务……方便对消息进行分类管理


  1. Partition :分区,一个Topic的消息由一个或多个Partition存储。分区的作用是提高读写并行度/读写效率。
  2. Segment :分段,发送到kafka集群的消息会先存到内存中,然后划分文件夹、划分文件存入磁盘中

备注: Kafka中有分区和分段的概念,分区就是分文件夹,分段就是分文件。这个思想在Hive中也有:Hive中的分区就是分文件夹,Hive中的分桶就是分文件。

Replication :副本,副本的作用是保证数据的安全性,副本分为Leader(主副本)和Follower(从副本),Leader只有一个,Follower可以有多个,但是副本数一般都为1-3个(副本数过多会占用大量的存储空间)。

注意:读写都只能从Leader进行,Follower在Leader宕机后自动选举出新的Leader。

扩展: 为什么读写都只能从Leader进行?

答:保证数据的一致性,只在Leader中进行写入数据,Follow同步Leader中的数据,在写过程中避免了多个副本中存储的数据不同的问题。Leader 和 Follow之间同步数据存在延时,所以读操作也需要在Leader中进行。

  1. ISR : 表示目前Alive(活着的)且与Leader能够 “Catch-up”(跟得上)的Replicas(Follower)集合。
  2. Record :记录,就是发送到Kafka集群的消息。一条消息就是一条记录。
  3. offset : 偏移量,用于记录消息的序号,各个分区的偏移量都是从0开始。

分区原理

在Kafka生产者代码演示(具体看上一篇代码帖子)中,我们将发送到Kafka的消息封装为record对象,即:、

 //将需要发送到Kafka的消息封装为record对象
 ProducerRecord<String, String> record = new ProducerRecord<>("test_topic", "key_" + i, "value_" + i);

在new ProducerRecord<>()有多个不同的构造方法,可以指定传入多个不同的参数。如下图所示:

这里我们思考一个问题:key有什么作用?如果不指定key如何分区的?指定了key不指定partition又是如何分区的?

默认分区策略各种分区现象

  1. 当我们不指定partition(分区)时,仅仅指定topic、key、value时,即
ProducerRecord<String, String> record = new ProducerRecord<>("order", "key_", "value_" + i);

现象为:

key如果相同,会将所有消息发送到同一个分区下。那么key如果不同呢?

 ProducerRecord<String, String> record = new ProducerRecord<>("order", "key_" + i, "value_" + i);

现象为:

消息会被发送到多个不同的分区下

  1. 不指定partition(分区),不指定key时,仅指定topic、value时,即
ProducerRecord<String, String> record = new ProducerRecord<>("order", "value_" + i);

现象为:

消息被发送到不同分区下

  1. 指定topic、partition、key、value时,即
ProducerRecord<String, String> record = new ProducerRecord<>("order", 0,"key_" + i, "value_" + i);

现象为:

消息被全部发送到指定的分区下。

默认分区策略下分区现象原因

  1. 没有key
    默认使用轮询的方式将消息发送到各个分区
new ProducerRecord<>("order", "value_" + i);
  1. 有key,没有指定分区
    使用Hash取余的方法将消息发送到各个分区。公式为:分区编号 = key的hash % 分区数
new ProducerRecord<>("order","key_"+i, "value_" + i);//key不一样,分区编号结果不一样
new ProducerRecord<>("order","key_", "value_" + i);//key一样,分区编号结果一样
  1. 有key,有指定的分区
    将消息发送到指定的分区下
new ProducerRecord<>("order", 0,"key_"+i, "value_" + i);//只要指定了分区就发送到指定的分区

回答之前留下的问题:key的作用

  1. 如果没有指定分区,可以根据key将数据发送到各个分区,让数据均匀分布!
  2. 如果指定了分区,那么key就不起到分区的作用,但是可以进一步区分业务,如order主题下的,不同地区,可以用key来表示。

自定义分区策略

这是系统默认的分区策略,我们可以参考public class DefaultPartitioner implements Partitioner编写自定义的分区策略。自定分区策略需要实现Partitioner接口。

架构详解

1.生产者

  1. 生产者采用push(推模式)向集群发送消息,并且消息是被顺序写磁盘追加到分区中,提高了kafka的写效率(吞吐量)
    备注:顺序写效率>>随机写效率
  2. 生产者只需要连接上任意一个活着的Broker就可以连接上Kafka集群
  3. 生产者发送消息时可以指定Topic、分区编号、key、value
  4. 分区编号和key都可以决定消息或者说是记录进入到哪个分区,具体规则如下:
  • 没有key,默认轮询方式写入到分区
  • 有key,没有分区编号,使用key的hash % 分区数得到分区编号
  • 有key,有分区编号,直接使用指定的分区编号
  • 也可以使用自定义分区策略,可以参考DefaultPartitioner实现Partitioner接口即可
  1. 分区的作用:
  • 提高读写效率/并行度
  • 方便集群扩展,业务扩张,数据增加的时候,可以增加机器,并增加分区数,以提升Kafka处理能力
  1. 分区的目的是为了提高并行度,数据的安全由副本保证,且副本是以分区来备份的!所以就有了:partition0的leader副本,partition0的follow副本! 注意:只能从leader读写,follow只负责备份
  2. 消息是局部有序(分区内有序)
    生产者发送消息到Kafka的各个分区中,根据消息发送的分区策略,不能保证发送的分区是有序的,但是在分区内按照offset的顺序追加写的。每个主题的每个分区中offset都是从0开始。
  3. 消息确认机制

acks=0,意思就是KafkaProducer客户端,只要把消息发送出去,不管那条数据有没有在Partition Leader上落到磁盘,都不管他了,直接就认为这个消息发送成功了

acks=1,只要Partition Leader接收到消息,就认为成功了,不管他其他的Follower有没有同步过去这条消息了。

acks=all/-1,意思就是说Partition Leader接收到消息之后,还必须要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。

all即所有副本都同步到数据时send方法才返回, 以此来完全判断数据是否发送成功, 理论上来讲数据不会丢失

2.Broker节点

  1. 分区体现在分文件夹,分段体现在分文件


数据发送到Kafka集群,最终会存储在分区下的分段中,也就是partition下的segment文件中,而kafka是一个消息系统,并不是一个存储系统,所以这些消息/数据/记录是有生命周期

默认配置如下所示:

1)基于时间:log.retention.hours=168 # 7天

2)基于大小:log.retention.bytes=1073741824 #单个segment达到1个G
满足上面任意一个就会被删除!

数据存储在在ZK中
注意:新版本中逐渐的将部分数据存在Kafka的自己主题中,如consumer_offsets中

如何根据offset从分段文件中找到需要读取的数据

1)根据segment的index文件后缀,使用offset去二分查找,确定文件。

2)根据index文件中记录的offset=3对应的.log文件的756(文件字节/便宜),去对应的.log文件中从756开始读offset为3的message-3


3.消费者细节

1.消费者从Kafka消费消息,使用的pull拉取模式

注意:Kafka为什么生产者是push推模式,消费者是pull拉模式,因为这样Kafka的压力较小,性能较高!类似与日常生活中的快递柜!


2.消费者只需要连接上任意一个活着的Broker就可以连接上整个Kafka集群


3.消费者消费消息的时候可以指定从哪个offset开始消费,如果有记录则从记录的位置开始消费,如果没有记录,取决于auto.offset.reset,值为earliest表示从最开始的数据,latest表示从最新的数据,none报错


4.offset可以自动提交也可以手动提交:

自动提交

//是否自动提交offset,true表示自动提交
props.put("enable.auto.commit", "true");
//自动提交偏移量时的时间间隔ms值
props.put("auto.commit.interval.ms", "1000");

手动提交

//是否自动提交offset,true表示自动提交,false表示使用手动提交
props.put("enable.auto.commit", "false");
kafkaConsumer.commitSync();//每消费5条就提交一次!//同步
 //kafkaConsumer.commitAsync();//每消费5条就提交一次!//异步

5.老版本offset提交到zk中,新版本提交到默认主题__consumer_offsets中

6.消费者消费消息的时候,可以指定订阅主题–用的较多!

kafkaConsumer.subscribe(Arrays.asList("order"));

也可以指定订阅主题和分区

String topic = "foo";
TopicPartition partition0 = new TopicPartition(topic, 0);
TopicPartition partition1 = new TopicPartition(topic, 1);
kafkaConsumer.assign(Arrays.asList(partition0, partition1));

7.消费者可以指定消费者组名,方便对消费者进行管理

注意:

  • 1.一个消费者组中可以有1~n个消费者
  • 2.一个主题可以被多个消费者组订阅
  • 3.一个消费者组可以订阅多个主题
  • 4.同一个主题的同一个分区下的某一条消息,只能被同一个消费者组中的一个消费者消费!
  • 5.同一个消费者组消费某个主题的多个分区时是无序的
  • 6.如果要有序消费怎么办?–只设置一个分区,但是需要注意:一般不这么做!因为分区是为了提升性能,单分区性能较差!
  • 7.分区数最好==消费者组中的消费者数!
     
目录
相关文章
|
13天前
|
存储 SQL Cloud Native
Hologres 的架构设计与工作原理
【9月更文第1天】随着大数据时代的到来,实时分析和处理数据的需求日益增长。传统的数据仓库在处理大规模实时数据分析时逐渐显露出性能瓶颈。为了解决这些问题,阿里巴巴集团研发了一款名为 Hologres 的新型云原生交互式分析数据库。Hologres 能够支持 SQL 查询,并且能够实现实时的数据写入和查询,这使得它成为处理大规模实时数据的理想选择。
40 2
|
15天前
|
存储 分布式计算 Hadoop
ChunkServer 原理与架构详解
【8月更文第30天】在分布式文件系统中,ChunkServer 是一个重要的组件,负责存储文件系统中的数据块(chunks)。ChunkServer 的设计和实现对于确保数据的高可用性、一致性和持久性至关重要。本文将深入探讨 ChunkServer 的核心原理和内部架构设计,并通过代码示例来说明其实现细节。
21 1
|
21天前
|
消息中间件 Kafka 数据库
深入理解Kafka的数据一致性原理及其与传统数据库的对比
【8月更文挑战第24天】在分布式系统中,确保数据一致性至关重要。传统数据库利用ACID原则保障事务完整性;相比之下,Kafka作为高性能消息队列,采用副本机制与日志结构确保数据一致性。通过同步所有副本上的数据、维护消息顺序以及支持生产者的幂等性操作,Kafka在不牺牲性能的前提下实现了高可用性和数据可靠性。这些特性使Kafka成为处理大规模数据流的理想工具。
39 6
|
21天前
|
消息中间件 负载均衡 Java
揭秘Kafka背后的秘密!Kafka 架构设计大曝光:深入剖析Kafka机制,带你一探究竟!
【8月更文挑战第24天】Apache Kafka是一款专为实时数据处理及流传输设计的高效率消息系统。其核心特性包括高吞吐量、低延迟及出色的可扩展性。Kafka采用分布式日志模型,支持数据分区与副本,确保数据可靠性和持久性。系统由Producer(消息生产者)、Consumer(消息消费者)及Broker(消息服务器)组成。Kafka支持消费者组,实现数据并行处理,提升整体性能。通过内置的故障恢复机制,即使部分节点失效,系统仍能保持稳定运行。提供的Java示例代码展示了如何使用Kafka进行消息的生产和消费,并演示了故障转移处理过程。
34 3
|
21天前
|
消息中间件 负载均衡 Kafka
Kafka 实现负载均衡与故障转移:深入分析 Kafka 的架构特点与实践
【8月更文挑战第24天】Apache Kafka是一款专为实时数据处理和流传输设计的高性能消息系统。其核心设计注重高吞吐量、低延迟与可扩展性,并具备出色的容错能力。Kafka采用分布式日志概念,通过数据分区及副本机制确保数据可靠性和持久性。系统包含Producer(消息生产者)、Consumer(消息消费者)和Broker(消息服务器)三大组件。Kafka利用独特的分区机制实现负载均衡,每个Topic可以被划分为多个分区,每个分区可以被复制到多个Broker上,确保数据的高可用性和可靠性。
39 2
|
21天前
|
消息中间件 负载均衡 Kafka
【解密Kafka背后的秘密!】为什么Kafka不需要读写分离?深入剖析Kafka架构,带你一探究竟!
【8月更文挑战第24天】Apache Kafka是一款专为高效实时数据处理与传输设计的消息系统,凭借其高吞吐量、低延迟及可扩展性在业界享有盛誉。不同于传统数据库常采用的读写分离策略,Kafka通过独特的分布式架构实现了无需读写分离即可满足高并发需求。其核心包括Producer(生产者)、Consumer(消费者)与Broker(代理),并通过分区复制、消费者组以及幂等性生产者等功能确保了系统的高效运行。本文通过分析Kafka的架构特性及其提供的示例代码,阐述了Kafka为何无需借助读写分离机制就能有效处理大量读写操作。
25 2
|
21天前
|
数据采集 存储 Java
Flume Agent 的内部原理分析:深入探讨 Flume 的架构与实现机制
【8月更文挑战第24天】Apache Flume是一款专为大规模日志数据的收集、聚合及传输而设计的分布式、可靠且高可用系统。本文深入解析Flume Agent的核心机制并提供实际配置与使用示例。Flume Agent由三大组件构成:Source(数据源)、Channel(数据缓存)与Sink(数据目的地)。工作流程包括数据采集、暂存及传输。通过示例配置文件和Java代码片段展示了如何设置这些组件以实现日志数据的有效管理。Flume的强大功能与灵活性使其成为大数据处理及实时数据分析领域的优选工具。
48 1
|
22天前
|
消息中间件 存储 Java
图解Kafka:Kafka架构演化与升级!
图解Kafka:Kafka架构演化与升级!
38 0
图解Kafka:Kafka架构演化与升级!
|
14天前
|
消息中间件 Kafka Java
Spring 框架与 Kafka 联姻,竟引发软件世界的革命风暴!事件驱动架构震撼登场!
【8月更文挑战第31天】《Spring 框架与 Kafka 集成:实现事件驱动架构》介绍如何利用 Spring 框架的强大功能与 Kafka 分布式流平台结合,构建灵活且可扩展的事件驱动系统。通过添加 Spring Kafka 依赖并配置 Kafka 连接信息,可以轻松实现消息的生产和消费。文中详细展示了如何设置 `KafkaTemplate`、`ProducerFactory` 和 `ConsumerFactory`,并通过示例代码说明了生产者发送消息及消费者接收消息的具体实现。这一组合为构建高效可靠的分布式应用程序提供了有力支持。
43 0
|
21天前
|
消息中间件 Java Kafka
Kafka不重复消费的终极秘籍!解锁幂等性、偏移量、去重神器,让你的数据流稳如老狗,告别数据混乱时代!
【8月更文挑战第24天】Apache Kafka作为一款领先的分布式流处理平台,凭借其卓越的高吞吐量与低延迟特性,在大数据处理领域中占据重要地位。然而,在利用Kafka进行数据处理时,如何有效避免重复消费成为众多开发者关注的焦点。本文深入探讨了Kafka中可能出现重复消费的原因,并提出了四种实用的解决方案:利用消息偏移量手动控制消费进度;启用幂等性生产者确保消息不被重复发送;在消费者端实施去重机制;以及借助Kafka的事务支持实现精确的一次性处理。通过这些方法,开发者可根据不同的应用场景灵活选择最适合的策略,从而保障数据处理的准确性和一致性。
57 9