一 kafka是什么
kafka是一个分布式的消息队列,有高性能,扩展性高等优点。所谓的消息队列就是发送者通过网络套接字发送消息,接收者接收消息,在这一切发生的同时,还需要有工具去管理消费者消费到哪里,以及高可用等问题,这一切就组成了消息队列。
-
kafka架构图
kafka从基本构成上来说有三大要素,producer,broker,consumer,producer负责发送消息,broker负责管理消息,consumer负责消费消息。消息需要按照不同的topic进行分类,topic是一个逻辑上的概念,在物理上,每个topic还要分成不同的partition,对应到真实的存储:每个topic会有一个文件夹,文件夹下面存放着不同的日志文件,这些文件就是partition。producer发送到哪个partition也是可以指定的。kafka的整体结构如图:
- producer,broker,consumer
二 消息发送过程
1 api介绍
kafka有high level api和low level api,high level帮助我们管理了offset等功能,low level需要自己去管理消费的offset,一般来说都是采用high level。
2 消息发送
2.1 基础内容
生产者在发送消息时,api中有若干可选项:topic,value必填,标记着你需要往哪个队列中发送什么内容,key和partition是可选项,可以将message发入指定的分区中,有partition就发往指定partition中,如果没有partition就根据key去发送,有key就将key值hash后除余,如果连key都没有,则根据round-robin轮训写入。
我们都知道,kafka是一个分布式的,高可用的消息队列,所谓的分布式,就是消息的存储具有水平扩展的能力,一个topic的消息可以存储在不同的物理机上;所谓的高可用指的是,同一条消息,会在备份的机器上存在。凡是分布式的系统,就一定存在CAP的问题。下面说明一下,kafka在发送消息时都做了什么:
- 1.正常情况下,在发送消息时,producer就往指定的partition发送消息,由partition拥有的所有broker中的leader进行处理。
- 2.当partition的leader broker挂掉时,会重新选举出新的leader处理producer的写入请求。
2.2 producer怎么才算成功写入消息?
producer写消息的内容分为如下几步:
- producer向partition的leader broker进行写请求。
- leader把消息写入日志中。
- 几台备份broker从leader中pull消息出来。
对应的消息写入成功标志也分为3种,request.required.acks有三个可以设置的值:0,1,-1 - 0 代表不管broker是否返回都算写入成功。
- 1 代表leader返回成功就算成功。
- -1代表所有主备broker都写成功才算成功。
3 offset的保存
offset是partition中一条消息的唯一标识序号,可以通过offet在日志文件中找到指定的消息。
三 消息消费过程
1 基本概念
消费的基本要求是:同一个group内的consumer只会消费同一个topic内的消息一次,不同的group可以消费同一个topic,kafka的做法是:同一个group内的consumer被划分为只能消费指定的partition,如果consumer挂掉,那么由broker进行重新分配。这种关系通过心跳连接维持。
这里需要注意的一点是:partition和consumer的关系是多对一的关系,如果consumer的数量多于partition的数量,那么必定有consumer没有消息可以消费。
2 消费者offset
在kafka 0.1版本之前,消费者的offset保存在zookeeper中,但是由于zookeeper的性能问题,这种方式不太适合kafka,所以后来kafka进行了变更:将其存放在了 __consumeroffsets这个topic中。
在进行消息写入时,具体写入哪个partition由消费组ID的hash值决定。
__consumers_offsets partition =
Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount)
//groupMetadataTopicPartitionCount由offsets.topic.num.partitions指定,默认是50个分区。
__consumeroffsets中存入的是KV型数据,key的值由groupid,partition,topic三者共同决定(groupid-topic-partition),这就意味着:在同一个group内,只能有一个consumer消费指定topic的指定partition消息。
consumer读取消费位置用到了缓存,每次consumer消费完消息后,会追加写一条记录到topic中,同时,系统维护了一个缓存,在提交后,会将consumer的消费offset缓存值进行更新,每次consumer拉取消费位置,从缓存中取出数据即可,不必每次都去遍历这个log记录。
网友评论