Kafka通俗易懂的简介

Kafka是一个分布式消息系统,由LinkedIn开发并用Scala编写。它提供高吞吐量、持久化、分区和多副本功能。消息通过Producer发送到Broker,再由Consumer消费。ConsumerGroup用于实现消息的广播和单播。Kafka使用Zookeeper进行集群扩展和协调,确保高可用性和负载均衡。每个Partition有多个副本以保证容错,Consumer通过Pull机制消费消息,且ConsumerGroup保证每个消息只被消费一次。Partition的Segment文件结构和索引文件支持高效的数据存储和检索。
摘要由CSDN通过智能技术生成

一、Kafka通俗易懂的简介

1.1、apache Kafka概要介绍

​ Kafka是最初由Linkedin公司开发,使用Scala语言编写。Kafka是一个分布式、分区的、多副本的、多订阅者的日志系统(分布式MQ系统),可以用于web/nginx日志,搜索日志,监控日志,访问日志等等。kafka目前支持多种客户端语言:java,python,c++,php等等。

1.2、kafka总体架构

kafka名词解释和工作方式:

  • Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
  • Topic :可以理解为一个队列。
  • Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。
  • Producer :消息生产者,就是向kafka broker发消息的客户端。
  • Consumer :消息消费者,向kafka broker取消息的客户端。
  • Consumer Group (CG):这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个CG只会把消息发给该CG中的一个consumer。如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic。
  • Segment:partition物理上由多个segment组成。
  • Offset:每个partition都由一系列有序的、不可变的消息组成,这些消息被连续的追加到partition中。partition中的每个消息都有一个连续的序列号叫做offset,用于partition唯一标识一条消息。

kafka特性

  • 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。
  • 高吞吐量:即使是非常普通的硬件kafka也可以支持每秒数十万的消息。
  • 支持同步和异步复制两种HA
  • Consumer客户端pull,随机读,利用sendfile系统调用,zero-copy ,批量拉数据消费状态保存在客户端消息存储顺序写数据迁移、扩容对用户透明
  • 支持Hadoop并行数据加载。
  • 支持online和offline的场景。
  • 持久化:通过将数据持久化到硬盘以及replication防止数据丢失。
  • scale out:无需停机即可扩展机器。
  • 定期删除机制,支持设定partitions的segment file保留时间。

1.3、可靠性(一致性)

传统的MQ系统通常都是通过broker和consumer间的确认(ack)机制实现的,并在broker保存消息分发的状态。即使这样一致性也是很难保证的。

kafka的做法是由consumer自己保存状态,也不要任何确认。这样虽然consumer负担更重,但其实更灵活了。因为不管consumer上任何原因导致需要重新处理消息,都可以再次从broker获得。

1.4、kafka系统扩展性

  • kafka使用zookeeper来实现动态的集群扩展,不需要更改客户端(producer和consumer)的配置。
  • broker会在zookeeper注册并保持相关的元数据(topic,partition信息等)更新。
  • 而客户端会在zookeeper上注册相关的watcher。一旦zookeeper发生变化,客户端能及时感知并作出相应调整。这样就保证了添加或去除broker时,各broker间仍能自动实现负载均衡。\

1.5、kafka设计目标

  • 高吞吐量是其核心设计之一。
  • 数据磁盘持久化:消息不在内存中cache,直接写入到磁盘,充分利用磁盘的顺序读写性能。
  • zero-copy:减少IO操作步骤。
  • 支持数据批量发送和拉取。
  • 支持数据压缩。
  • Topic划分为多个partition,提高并行处理能力。

1.6、Producer负载均衡和HA机制

  • producer根据用户指定的算法,将消息发送到指定的partition。
  • 存在多个partiiton,每个partition有自己的replica,每个replica分布在不同的Broker节点上。
  • 多个partition需要选取出lead partition,lead partition负责读写,并由zookeeper负责fail over。
  • 通过zookeeper管理broker与consumer的动态加入与离开。

1.7、Consumer的pull机制

​ 由于kafka broker会持久化数据,broker没有cahce压力,因此,consumer比较适合采取pull的方式消
费数据,具体特别如下:

  • 简化kafka设计,降低了难度。
  • Consumer根据消费能力自主控制消息拉取速度。
  • consumer根据自身情况自主选择消费模式,例如批量,重复消费,从制定partition或位置(offset)开始消费等。

1.8、Consumer与topic关系以及机制

  • 本质上kafka只支持Topic。每个consumer属于一个consumer group;反过来说,每个group中可以有多个consumer。对于Topic中的一条特定的消息,只会被订阅此Topic的每个group中的一个consumer消费,此消息不会发送给一个group的多个consumer;那么一个group中所有的consumer将会交错的消费整个Topic。
  • 如果所有的consumer都具有相同的group,这种情况和JMS queue模式很像;消息将会在consumers之间负载均衡。
  • 如果所有的consumer都具有不同的group,那这就是"发布-订阅";消息将会广播给所有的消费者。
  • 在kafka中,一个partition中的消息只会被group中的一个consumer消费(同一时刻);每个group中consumer消息消费互相独立;我们可以认为一个group是一个"订阅"者,一个Topic中的每个partions,只会被一个"订阅者"中的一个consumer消费,不过一个consumer可以同时消费多个partitions中的消息。
  • kafka只能保证一个partition中的消息被某个consumer消费时是顺序的。事实上,从Topic角度来说,当有多个partitions时,消息仍不是全局有序的。
  • 通常情况下,一个group中会包含多个consumer,这样不仅可以提高topic中消息的并发消费能力,而且还能提高"故障容错"性,如果group中的某个consumer失效,那么其消费的partitions将会有其他consumer自动接管。kafka的设计原理决定,对于一个topic,同一个group中不能有多于partitions个数的consumer同时消费,否则将意味着某些consumer将无法得到消息。

1.9、Producer均衡算法

  • kafka集群中的任何一个broker,都可以向producer提供metadata信息,这些metadata中包含"集群中存活的servers列表"/"partitions leader列表"等信息(请参看zookeeper中的节点信息)。
  • 当producer获取到metadata信心之后, producer将会和Topic下所有partition leader保持socket连接;
  • 消息由producer直接通过socket发送到broker,中间不会经过任何"路由层"。事实上,消息被路由到哪个partition上,有producer客户端决定。比如可以采用"random"“key-hash”"轮询"等,如果一个topic中有多个partitions,那么在producer端实现"消息均衡分发"是必要的。
  • 在producer端的配置文件中,开发者可以指定partition路由的方式。

1.10、Consumer均衡算法

当一个group中,有consumer加入或者离开时,会触发partitions均衡。均衡的最终目的,是提升topic的并发消费能力。

  1. 假如topic1,具有如下partitions: P0,P1,P2,P3
  2. 加入group中,有如下consumer: C0,C1
  3. 首先根据partition索引号对partitions排序: P0,P1,P2,P3
  4. 根据consumer.id排序: C0,C1
  5. 计算倍数: M = [P0,P1,P2,P3].size / [C0,C1].size,本例值M=2(向上取整)
  6. 然后依次分配partitions: C0 = [P0,P1],C1=[P2,P3],即Ci = [P(i * M),P((i + 1) * M -1)]

1.11、Broker之间replica机制

  • kafka中,replication策略是基于partition,而不是topic;kafka将每个partition数据复制到多个server上,任何一个partition有一个leader和多个follower(可以没有);

  • 备份的个数可以通过broker配置文件来设定。leader处理所有的read-write请求,follower需要和leader保持同步。Follower就像一个"consumer",消费消息并保存在本地日志中;leader负责跟踪所有的follower状态,如果follower"落后"太多或者失效,leader将会把它从replicas同步列表中删除。

  • 当所有的follower都将一条消息保存成功,此消息才被认为是"committed",那么此时consumer才能消费它,这种同步策略,就要求follower和leader之间必须具有良好的网络环境。

  • 即使只有一个replicas实例存活,仍然可以保证消息的正常发送和接收,只要zookeeper集群存活即可。(备注:不同于其他分布式存储,比如hbase需要"多数派"存活才行)

  • kafka判定一个follower存活与否的条件有2个:

    • follower需要和zookeeper保持良好的链接
    • 它必须能够及时的跟进leader,不能落后太多

    如果同时满足上述2个条件,那么leader就认为此follower是"活跃的"。

  • 如果一个follower失效(server失效)或者落后太多,leader将会把它从同步列表中移除[备注:如果此replicas落后太多,它将会继续从leader中fetch数据,直到足够up-to-date,然后再次加入到同步列表中;kafka不会更换replicas宿主!因为"同步列表"中replicas需要足够快,这样才能保证producer发布消息时接受到ACK的延迟较小。

  • 当leader失效时,需在followers中选取出新的leader,可能此时follower落后于leader,因此需要选择一个"up-to-date"的follower。

  • kafka中leader选举并没有采用"投票多数派"的算法,因为这种算法对于"网络稳定性"/"投票参与者数量"等条件有较高的要求,而且kafka集群的设计,还需要容忍N-1个replicas失效。对于kafka而言,每个partition中所有的replicas信息都可以在zookeeper中获得,那么选举leader将是一件非常简单的事情。选择follower时需要兼顾一个问题,就是新leader server上所已经承载的partition leader的个数,如果一个server上有过多的partition leader,意味着此server将承受着更多的IO压力。

  • 在选举新leader,需要考虑到"负载均衡",partition leader较少的broker将会更有可能成为新的leader。在整几个集群中,只要有一个replicas存活,那么此partition都可以继续接受读写操作。

总结:

  • Producer端直接连接broker.list列表,从列表中返回TopicMetadataResponse,该Metadata包含Topic下每个partition leader建立socket连接并发送消息。

  • Broker端使用zookeeper用来注册broker信息,以及监控partition leader存活性。

  • Consumer端使用zookeeper用来注册consumer信息,其中包括consumer消费的partition列表等,同时也用来发现broker列表,并和partition leader建立socket连接,并获取消息。

二、Kafka文件存储机制

2.1、分析过程

分析过程分为以下4个步骤:

  • topic中partition存储分布;
  • partiton中文件存储方式;
  • partiton中segment文件存储结构;
  • 在partition中如何通过offset查找message

通过上述4过程详细分析,我们就可以清楚认识到kafka文件存储机制的奥秘。

2.2、topic中partition存储分布

​ 假设实验环境中Kafka集群只有一个broker,kafka/kafka-logs为数据文件存储根目录,在Kafka broker中server.properties文件配置(参数log.dirs=kafka/kafka-logs),例如创建2个topic名称分别为report_push、launch_info,partitions数量都为partitions=4 存储路径和目录规则为: kafka/kafkalogs;

|--report_push-0
|--report_push-1
|--report_push-2
|--report_push-3
|--launch_info-0
|--launch_info-1
|--launch_info-2
|--launch_info-3

​ 在Kafka文件存储中,同一个topic下有多个不同partition,每个partition为一个目录,partiton命名规则为topic名称+有序序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。 如果是多broker分布情况会分散到不同的broker上,具体的分配规则和分配算法请看下面示例。
​ Kafka集群partition replication默认自动分配分析,以一个Kafka集群中4个Broker举例,创建1个topic包含4个Partition,2个 Replication;数据Producer流动如图所示:

在这里插入图片描述

当集群中新增2节点,Partition增加到6个时分布情况如下:

在这里插入图片描述

2.3、副本分配逻辑规则

  • 在Kafka集群中,每个Broker都有均等分配Partition的Leader机会;
  • 上述图Broker Partition中,箭头指向为副本,以Partition-0为例:broker1中parition-0为Leader,Broker2中Partition-0为副本;
  • 上述图种每个Broker(按照BrokerId有序)依次分配主Partition,下一个Broker为副本,如此循环迭代分配,多副本都遵循此规则。

副本分配算法:

  • 将所有N Broker和待分配的i个Partition排序.
  • 将第i个Partition分配到第(i mod n)个Broker上.
  • 将第i个Partition的第j个副本分配到第((i + j) mod n)个Broker上

2.4、partiton中文件存储方式

下面示意图形象说明了partition中文件存储方式:
在这里插入图片描述

  • 每个partion(目录)相当于一个巨型文件被平均分配到多个大小相等segment(段)数据文件中。但每个段segment file消息数量不一定相等,这种特性方便old segment file快速被删除;
  • 每个partiton只需要支持顺序读写就行了,segment文件生命周期由服务端配置参数决定。

这样做的好处就是能快速删除无用文件,有效提高磁盘利用率。

2.5、partiton中segment文件存储结构

上面我们了解到Kafka文件系统partition存储方式,接下来深入分析partion中segment file组成和物理结构。

  • segment file组成:由2大部分组成,分别为index file和data file,此2个文件一一对应,成对出现,后缀”.index”和“.log”分别表示为segment索引文件、数据文件。
  • segment文件命名规则:partion全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值。数值最大为64位long大小,19位数字字符长度,没有数字用0填充。

下面文件列表是在Kafka broker上做的一个实验,创建一个topic包含1 partition,设置每个segment大小为500MB,并启动producer向Kafka broker写入大量数据,如图所示segment文件列表形象说明了上述2个规则:

在这里插入图片描述

以上述图中一对segment file文件为例,说明segment中index<—->data file对应关系物理结构如下:

在这里插入图片描述

上图中索引文件存储大量元数据,数据文件存储大量消息,索引文件中元数据指向对应数据文件中message的物理偏移地址。 其中以索引文件中元数据3,497为例,依次在数据文件中表示第3个message(在全局partiton表示第368772个message)、以及该消息的物理偏移地址为497。
从上述图了解到segment data file由许多message组成,下面详细说明message物理结构如下:

在这里插入图片描述

参数说明

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

查看segment 内容:

kafka附带了一个叫DumpLogSegment的工具,可以用它查看片段的内容。它可以显示每个消息的偏移量、校验和、魔术数字节、消息大小和压缩算法。运行该工具的方式如下
/kafka-run-class.sh kafka.tools.DumpLogSegments
如果使用–deep-iteration参数,可以显示被压缩到包装消息里的消息。
–files参数,用于指定想查看的分区片段
–print-data-log参数,指定打印详细内容

bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files /data/kafka/kafkalogs/test-0/00000000000000000000.log --print-data-log

2.6、在partition中如何通过offset查找message

例如读取offset=368776的message,需要通过下面2个步骤查找。

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值