头图

与传统的mq(如rabbitmq)不同,kafka以文件形式存储和传输消息,官方将其定义为事件流式处理平台,它天然具备分布式属性。

2.8版本前,kafka需要zk存储broker和consumer部分信息(注意:producer不依赖zk);2.8之后,kafka已经不再依赖kafka。

但是生产环境目前(kafka 3.1版本)还是要使用zk。

抄一段官方文档:

It is now possible to run Apache Kafka without Apache ZooKeeper! We call this the Kafka Raft metadata mode, typically shortened to KRaft mode. KRaft is intended to be pronounced like craft (as in craftsmanship).
It is currently PREVIEW AND SHOULD NOT BE USED IN PRODUCTION, but it is available for testing in the Kafka 3.1 release.

基本结构

  • 生产者

没啥可说的,负责向broker推送消息

  • broker

image.png

kafka的一个服务节点,多个broker构成kafka集群;broker一般部署在不同的物理机上

  • topic

同一类消息放入同一个主题中,比如订单属于一个主题,支付属于另一个主题;但有一点需要注意,topic只是逻辑层面的概念,消息真实存在于partition中

  • partition
| --topic1-0     --> 这个文件夹就是partition
    | --00000000000000000000.index
    | --00000000000000000000.log
    | --00000000000000368769.index
    | --00000000000000368769.log
| --topic2-0
| --topic2-1

可以看到partition的序号是从0开始的。

partition实际上是服务器磁盘上一个文件夹,同一个topic可以包含很多partition。增加partition能够有效的增加吞吐量,类似于nginx下增加tomcat可有效增加吞吐。

比如上图中topic1,有5个partition均匀分布在3台broker中。如果发送消息时指定主题是topic1,此消息会按一定规则推送到某一个partition上。当然,发送时也可以指定

消息在一个partition中是有序的,在多个partition中无法保证有序。

  • segment

partition内部是两种文件,*.index*.log文件。

log文件存放消息,index文件存放索引,它们是成对出现的;相同名字的一对log+index文件称之为一个segment,是kafka文件存储的最小单位。

segment是概念性的东西,没啥实际意义。
  • replication

image.png

partition的副本,作为数据备份不对外提供服务。replication和partion一般不在同一台broker上以增加容错,类似上图的分布。

  • consumer

image.png

消费者负责消费消息,通过维护offset来确定消息。
offset可以理解成一个指针,指向当前消费的消息;同时offset也和partition相关,这个后面细说。

消息被消费后offset会增加,但消息本身依然存在于partition中不被清理。partition消息只会被定时清理,默认保存7天。

  • group

消费端有个group的概念,一个group下可以有一个consumer,也可以有多个consumer。

一条消息只会发送到同一个group下的其中一个consumer

多个partition可以对应一个consumer(上图group2);但是一个paratition不能对应多个consumer,最多对应一个(上图group1)。
如果一个group中的consumer数量比partition数多,会出现闲置的consumer(上图consumer3)

消息存储

来看一下kafka消息存储方式

| --topic1-0     --> 这个文件夹就是partition
    | --00000000000000000000.index
    | --00000000000000000000.log
    | --00000000000000368769.index
    | --00000000000000368769.log
    | --00000000000000744271.index
    | --00000000000000744271.log
| --topic2-0
| --topic2-1

消息采用顺序写的方式写入.log文件中,当文件大小到达阈值,会生成新的log和index文件。

开始只有00000000000000000000.log,当文件大小达到500m(默认)会生成
00000000000000368769.log。368769这个数字,正是00000000000000000000.log文件中offset的最大值。

log采用这样的命名方式有一个好处,如果查找offset=728378的消息,可以很快锁定它所在的文件,一定在00000000000000744271.log文件中。

image.png

再看index索引文件,kafka采用稀疏索引的方式——不为每条数据建立索引,索引是不连续的。(上图为第1、3、6、8、N条数据建立了索引,2、4、5就没有索引)

根据log文件的名字(00000000000000368769.log),很容易知道第1条数据对应的offset是368769+1=368770。

我们看一下这个partition中数据offset=368776的消息的查找过程:

  1. 368769<368776<744271,因此定位到00000000000000368769.log文件
  2. 368776-368769=7,因此找文件中的第7条数据
  3. 去00000000000000368769.index中查找,7没在索引中,但6和8都有索引
  4. 根据索引<6,1407>的value,定位到00000000000000368769.log中物理偏移地址1407,定位到消息Message368775;但这是第6条数据数据应该找它的下一条,找到了Message368776

附录

P6-P7知识合辑


青鱼
268 声望25 粉丝

山就在那里,每走一步就近一些