前言

话说今天是1024,程序猿(媛)节,在“屌丝”盛行之时,称为屌丝节。随着全面小康社会的展望,为了彰显IT界码农的身份,程序猿(媛)由屌丝晋升为“爱码仕”,也许是为了与双十一与时俱进吧。
以上纯tx! 还是来点干货吧…

Kafka架构

消息队列 发布订阅 消息队列key_java


从上图可以看出,Kafka主要有生产者、broker、消费者群、消费者、zookeeper概念,各个概念一一来讲解。

Producer

注:生产者

消息队列 发布订阅 消息队列key_java_02


生产者,以ProducerRecord为对象推送给Kafka broker,ProducerRecord的主要以topic主题、分区partition(可选)、key(可选)、消息体,timestamp(可选)。

源码如下:

消息队列 发布订阅 消息队列key_队列_03

Topic

注:主题

消息队列 发布订阅 消息队列key_kafka_04

Kafka以主题topic的方式推送消息,一个主题可以被多个消费者消费。主题里的消息体又以多个分区partition来存储的

Partition

注:分区

  • 如果ProducerRecord的partition指定了某个分区,那么消息体存储到指定的分区里
  • 如果ProducerRecord的partition(其实就是分区号),如果没有指定分区器,则使用默认分区器DefaultPartitioner来计算,然后根据ProducerRecord的key来计算
  • 如果key为空,则以轮询的方式来给主题下的各个可用分区来发送消息(注意这里,是可用分区)。
  • 如果key不为空,则根据hash算法(采用MurmurHash2算法,具备高运算性能及低碰撞率)计算分区号,相同的key会分配到同一个分区。

Offset

注:偏移量

消息队列 发布订阅 消息队列key_消息队列 发布订阅_05


每个分区都有一个Offset,这个Offset就是这个生产者的Offset,并且是分区的最大的offset。

当然还有消费者偏移量。下一期,我会详细介绍。

Segment

一个分区其实由多个大小相等的Segment(段)组成,每个段Segment file 的消息数量可以不相同,这样方便删除旧的Segment

  • 其存储结构
    生产者发送消息到主题后,消息会根据分区策略被分配到多个分区里,Kafka broker会把消息往分区里的最后一个Segment里添加消息,如果Segment消息的数量达到了阈值或时间超时时,Segment上的消息会flush到磁盘里,flush的消息才会被消费者消费,如果Segment的消息大小达到一定值时,就不会往旧的Segment写入,而是新建一个Segment。
  • Segment file 组成
  1. index file,后缀名.index,表示Segment的索引文件,对应Segment第一个消息
  2. data file , 后缀名.log, 表示数据文件
    以上两个文件成对出现
  • Segment 命名规则
  1. Partition的第一个Segment从0开始
  2. 后面的Segment都是从上一个全局的Partition的最大Offset
  3. 数值最大为64位long大小,19位数字字符长度,没有数字用0填充。
  • 每个segment中存储很多条消息,消息id由其逻辑位置决定,即从消息id可直接定位到消息的存储位置,避免id到位置的额外映射
  • 上图查找offset=1001过程:
  1. 先查找Segment file文件,00000000000000000000.index为全局Partition 的Segemtnt起始文件,那么offset=1001偏移量的消息的Segemnt文件名为00000000000000001001.index
  2. 然后找到对应数据文件00000000000000001001.log,其起始偏移量为1001+1=1002,其他偏移量也是如此查找(二分查找文件名)
  3. 定位index文件物理位置Position,其直接映射内存物理地址,然后按照顺序查找到对应的00000000000000001001.index.

Consumer Group

注:消费群组

多个消费者在同一个组里,成为消费者群。一个分区的消息,只能被同一个消费群里的某一个消费者消费,但能被其它消费者群的某一个消费者消费。

#Consumer

注:消费者

消费群组:消费者 = 1:1

broker消费者分区分配:所有分区的消息被一个消费者消费

消息队列 发布订阅 消息队列key_java_06

消费群组:消费者 = 1:N,且分区数量>消费者

broker消费者分区分配过程:p0->c1消费; p1->c2消费; p2->c1消费

消息队列 发布订阅 消息队列key_群组_07

消费群组:消费者 = 1:N,且分区数量=消费者

broker消费者分区分配过程:p0->c1消费; p1->c2消费; p2->c3消费

消息队列 发布订阅 消息队列key_队列_08

消费群组:消费者 = 1:N,且分区数量<消费者

broker消费者分区分配过程:p0->c1消费; p1->c2消费; p2->c3消费 ; c4不消费。

因为同一个消费群组里,一个分区只能被其下的一个消费者消费。为什么要这样,其实想想很简单,避免重复消费。

消息队列 发布订阅 消息队列key_群组_09

消费群组:消费者 = N:N

broker消费者分区分配过程:
消费群组group1:p0->c1消费; p1->c2消费; p2->c1消费;
消费群组group2:p0->c1消费; p1->c2消费; p2->c3消费;
消费群组group3:p0->c1消费; p1->c2消费; p2->c3消费 ; c4不消费。

消息队列 发布订阅 消息队列key_群组_10