kafka

本文详细介绍了Kafka的存储设计,包括partition、segment结构,通过offset查找message的过程,以及数据的顺序写入和zero-copy读取。此外,还深入探讨了Kafka的ISR副本机制和副本同步策略,确保高可用性和数据一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、kafka简介

Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx日志、访问日志,消息服务等等,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。

主要应用场景是:日志收集系统和消息系统。

Kafka主要设计目标如下:

  1. 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能保证常数时间的访问性能。

  2. 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒100K条消息的传输。

  3. 支持Kafka Server间的消息分区,及分布式消费,同时保证每个partition内的消息顺序传输。

  4. 同时支持离线数据处理和实时数据处理。

二、整体架构

如上图所示,kafka由3种角色组成:消费者(produce)、代理服务器(broker)、消费者(consumer)

  • Broker:每一台机器叫一个Broker,多个Broker组成一个Kafka集群

  • Producer:日志消息生产者,负责往集群中写数据

  • Consumer:消息的消费者,负责从集群中读数据

  • Consumer Group:每个Consumer属于一个特定的Consumer Group

  • Topic:不同消费者去指定的Topic中读,不同的生产者往不同的Topic中写

  • Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列。

  • Message:日志消息,kafka集群内流通的基本单位

  • Segment:partition物理上由多个segment组成

  • Offset:每个partition都由一系列有序的、不可变的消息组成,这些消息被连续的追加到partition中。partition中的每个消息都有一个连续的序列号叫做offset,用于partition唯一标识一条消息。

三、 Kafka高效文件存储设计

Kafka高效文件存储设计特点

  • Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。

  • 通过索引信息(内存缓存)可以快速定位message和确定response的最大大小。

  • 通过index元数据全部映射到memory,可以避免segment file的IO磁盘操作。

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

3.1 partition存储结构

  • Topic与Partition的关系:一个topic被分成多个partition,每个partition在磁盘上就是一个文件夹。

  • partition命名规则:topicName_(partitionNum-1)。

  • 一个partition由多个segment组成,一个segment由两部分组成:一个index索引文件和一个log数据文件。

  • 每个partiton只需要支持顺序读写就行了,segment文件生命周期由服务端配置参数决定。

  • segment命名规则:partition全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值。数值最大为64位long大小,19位数字字符长度,没有数字用0填充。

3.2 segment存储结构

 

  • index索引文件中保存的是messageId,offsetId的关系,采取稀疏索引存储方式

  • log数据文件保存的是全局messageId,offsetId的关系

其中以索引文件中元数据3,497为例,依次在数据文件中表示第3个message(在全局partiton表示第368772个message)、以及该消息的物理偏移地址为497。

  • 从上述图中了解到segment data file由许多message组成,下面详细说明message物理结构如下:

参数说明:

关键字解释说明
8 byte offset在parition(分区)内的每条消息都有一个有序的id号,这个id号被称为偏移(offset),它可以唯一确定每条消息在parition(分区)内的位置。即offset表示partiion的第多少message
4 byte message sizemessage大小
4 byte CRC32用crc32校验message
1 byte “magic"表示本次发布Kafka服务程序协议版本号
1 byte “attributes"表示为独立版本、或标识压缩类型、或编码类型。
4 byte key length表示key的长度,当key为-1时,K byte key字段不填
K byte key可选
value bytes payload表示实际消息数据。

3.3 通过offset查找message过程

由于kafka中设计由consumer来保存offset或指定offset来消费message,所以读取/查找的过程就是通过offset去查找message,举例读取offset=368776的message,需要通过下面2个步骤查找:

  • 第一步查找segment file上述segment内部对应关系图为例,其中00000000000000000000.index表示最开始的文件,起始偏移量(offset)为0.第二个文件00000000000000368769.index的消息量起始偏移量为368770 = 368769 + 1.同样,其他后续文件依次类推,以起始偏移量命名并排序这些文件,只要根据offset 二分查找文件列表,就可以快速定位到具体文件。当offset=368776时定位到00000000000000368769.index|log

  • 第二步通过segment file查找message通过第一步定位到segment file,当offset=368776时,依次定位到00000000000000368769.index的元数据物理位置和00000000000000368769.log的物理偏移地址,然后再通过00000000000000368769.log顺序查找直到offset=368776为止。

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

3.4 数据顺序写入过程

因为硬盘是机械结构,每次读写都会寻址,写入,其中寻址是一个“机械动作”,它是最耗时的。所以硬盘最“讨厌”随机I/O,最喜欢顺序I/O。为了提高读写硬盘的速度,Kafka就是使用顺序I/O。

每条消息都被append到该Partition中,属于顺序写磁盘,因此效率非常高。

message写入: 

  • 消息从java堆转入page cache(即物理内存)。

  • 由异步线程刷盘,消息从page cache刷入磁盘。

3.5 数据zero-copy读取过程

即便是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以Kafka的数据并不是实时的写入硬盘,它充分利用了现代操作系统分页存储来利用内存提高I/O效率。

在Linux Kernal 2.2之后出现了一种叫做“零拷贝(zero-copy)”系统调用机制,就是跳过“用户缓冲区”的拷贝,建立一个磁盘空间和内存空间的直接映射,数据不再复制到“用户态缓冲区”系统上下文切换减少2次,可以提升一倍性能。

四、ISR副本机制 

kafka通过消息副本机制提供高可用消息服务,其副本管理不是在topic消息队列,而是在topic的数据分片(partition)。在配置文件制动partition的副本个数,在多个副本中,只有一个主副本leader,其他均为次副本(slave)。所有针对这个数据分片的消息读写均由主副本响应,次副本从主副本同步数据,当主副本发生故障,选举次副本

ISR机制

将所有次级副本分成两个集合:ISR集合、非ISR集合,ISR集合的数据是即时与主副本数据保持一致的,非ISR集合允许落后于主副本数据,在主副本发生故障时,会从ISR集合选举主副本,维持一致性。数据写入时候,当主副本信息与ISR集合数据均写成功才算成功。假设ISR集合数为f+1,那么最多允许f个副故障。

副本同步机制

Producer在发布消息到某个Partition时,先通过ZooKeeper找到该Partition的Leader(主副本),然后无论该Topic的Replication Factor为多少,Producer只将该消息发送到该Partition的Leader(主副本)。Leader(主副本)会将该消息写入其本地Log。每个Follower(次级副本)都从Leader(主副本) pull数据。这种方式上,Follower(次级副本)存储的数据顺序与Leader保持一致。Follower(次级副本)在收到该消息并写入其Log后,向Leader(主副本)发送ACK。一旦Leader(主副本)收到了ISR中的所有Replica的ACK,该消息就被认为已经commit了,Leader(主副本)将增加HW并且向Producer发送ACK。

为了提高性能,每个Follower(次级副本)在接收到数据后就立马向Leader(主副本)发送ACK,而非等到数据写入Log中。因此,对于已经commit的消息,Kafka只能保证它被存于多个Replica的内存中,而不能保证它们被持久化到磁盘中,也就不能完全保证异常发生后该条消息一定能被Consumer消费。

Consumer读消息也是从Leader读取,只有被commit过的消息才会暴露给Consumer。

 

 

06-07
### Kafka 使用教程和核心技术详解 Kafka 是一个分布式流处理平台,最初由 LinkedIn 开发,并于 2011 年开源。它被设计为高吞吐量、低延迟的消息系统,广泛用于日志收集、监控数据聚合、流式数据处理等领域[^1]。 #### Kafka 的核心概念 Kafka 的架构围绕几个关键概念展开: - **主题(Topic)**:Kafka 中消息的类别或提要名称。生产者将消息发布到特定主题,消费者从主题中订阅消息。 - **分区(Partition)**:每个主题可以划分为多个分区,分区是 Kafka 中并行处理的基础单位。 - **副本(Replica)**:为了提高可靠性,Kafka 会为每个分区创建多个副本,分布在不同的 Broker 上。 - **消费者组(Consumer Group)**:消费者可以组成一个组来共同消费一个主题的消息,组内的每个消费者负责处理一部分分区的消息[^2]。 #### Kafka 的使用方法 Kafka 提供了多种客户端库以支持不同编程语言的开发。以下是一个简单的 Python 示例,展示如何使用 Kafka 生产者和消费者: ```python from kafka import KafkaProducer, KafkaConsumer # 创建 Kafka 生产者 producer = KafkaProducer(bootstrap_servers='localhost:9092') # 发送消息到指定主题 producer.send('my-topic', b'Hello, Kafka!') producer.flush() producer.close() # 创建 Kafka 消费者 consumer = KafkaConsumer( 'my-topic', bootstrap_servers='localhost:9092', auto_offset_reset='earliest', enable_auto_commit=True, group_id='my-group' ) # 消费消息 for message in consumer: print(f"Received message: {message.value.decode('utf-8')}") ``` #### Kafka 的核心技术详解 Kafka 的核心技术主要包括以下几个方面: - **持久化日志**:Kafka 将消息存储在磁盘上,并通过顺序写入操作优化性能。这种设计使得 Kafka 能够提供高吞吐量和持久性保证。 - **分区与并行性**:通过将主题划分为多个分区,Kafka 实现了水平扩展的能力。每个分区可以独立地被多个消费者消费。 - **复制机制**:Kafka 的复制机制确保了即使某些 Broker 出现故障,数据仍然可用。领导者分区负责读写操作,而跟随者分区则同步数据[^3]。 - **消费者偏移量管理**:Kafka 允许消费者自行管理偏移量,这为灵活的消费模式提供了支持,例如重新消费旧消息或跳过某些消息。 #### Kafka 的学习资料 对于初学者,可以从官方文档入手,了解 Kafka 的基本概念和配置选项。此外,还有许多在线课程和书籍可以帮助深入理解 Kafka 的原理和实践[^4]。 ```markdown - 官方文档: https://kafka.apache.org/documentation/ - 在线课程: Coursera、Udemy 等平台提供的 Kafka 课程 - 推荐书籍: "Kafka: The Definitive Guide" by Neha Narkhede, Gwen Shapira, and Todd Palino ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值