先来看看Kafka中的一些相关术语
Producer | 消息生产者,就是向 kafka broker 发消息的客户端 |
Consumer | 消息消费者,向 kafka broker 取消息的客户端 |
Consumer Group (CG) | 消费者组,由多个 consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者 |
Broker | 一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker可以容纳多个 topic |
Topic | 可以理解为一个队列,生产者和消费者面向的都是一个 topic |
Partition | 为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列 |
Replica | 副本,为保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失,且 kafka 仍然能够继续工作,kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本,一个 leader 和若干个 follower |
leader | 每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是 leader |
follower | 每个分区多个副本中的“从”,实时从 leader 中同步数据,保持和 leader 数据的同步。leader 发生故障时,某个 follower 会成为新的 follower。 |
一、基础概念
Topic是一个逻辑概念,消息都是按照Topic来进行逻辑区分,而Partition是物理概念,Kafka中Topic都是以Partition分区来存放的,每个 Partition 从物理层面来讲都是一个单独的 log 文件
如上图就是一个Kafka集群,一个 Kafka 集群由多个 Broker(就是 Server) 构成,每个 Broker 中含有集群的部分数据。Kafka 集群把 Topic 的多个 Partition 分布在多个 Broker 中,创建Topic时可以指明创建多个Partition分区。
二、Partition如何读取与写入
Partition内部会维护一个Offsets(偏移量),消费者消费完了消息是不会被立刻删除的,每个消费者把消费的数据消费到哪里了就需要做个记录,这就是Offsets。Offsets在0.10版本后,是保存在kafka内部topic:__consumer_offsets,消费者提交过去的时候,key是consumerGroupId+topic+分区号,value就是当前offset的值,kafka会定期清理topic⾥的消息,最后就保留最新的那条数据 。
1、写入
Producer发送消息时,会根据Key值进行Hash,相同Key值的会被路由写入到同一个分区,对于单个Partition来说,所有消息都是顺序写入Partittion,即单个Partittion中消息是有序的(局部有序),不同Partittion消息是无法保证顺序的,如果想队列的强顺序一致性,可以让所有的消息都设置为同一个Key。
2、读取
一般来说我们的消费模型有两种:推送模型(push)和拉取模型(pull),Kafka采取拉取模型(poll)。由自己控制消费速度,以及消费的进度。消息又可具体分为两种:
(1)单播消息
单播消息:一条消息只能被某一个消费者消费,要实现单播,只要让这些消费者属于同一个消费者组即可。
(2)多播消息
多播消息:一条消息能够被多个消费者消费的模式称为多播。之所以不称之为广播,是因为一条消息只能被Kafka同一个分组下某一个消费者消费,而不是所有消费者都能消费。所以从严格意义上来讲并不能算是广播模式,当然如果希望实现广播模式只要保证每个消费者均属于不同的消费者组。
消费关键细节,见下图所示:
(1)根据单播和多播特性可知,一个Partittion里的消息只能被同一个消费组中的一个消费者消费,从而保证消费顺序。
(2)一个消费者可以消费多个Partition
(3)Partittion数量决定了消费组中的消费者的数量,同一个消费组中消费者的数量如果超过Partittion的数量,多的消费者消费不到消息
三、分区的设计优势
总结来说就是水平扩展:磁盘写入速度就是kafka处理速度的极限,处理不过来就要加机器。每台机器持有不同的partition,这样就减轻了单台服务器的压力,并且多分区,消费者也可以并行的去消费。
四、与RocketMq的ConsumeQueue对比
RocketMq其实模仿了Kafka,但是Rocketmq不是仅仅把Partition改成了ConsumeQueue,Kafka里面Partition存储的是整个消息,而ConsumeQueue里面是存储消息的存储地址,具体的消息主体是存放在CommitLog中。RocketMq存储结构不理解请看我这篇文章