1、概念
Producer:
消息生产者,就是向kafka broker发消息的客户端。
Consumer:
消费消息。每个consumer属于一个特定的consumer group(可为每个consumer指定group name,若不指定group name则属于默认的group)。同一topic的一条消息只能被同一个consumer group内的一个consumer消费,但多个consumer group可同时消费这一消息。Consumer Group中的每个Consumer读取Topic的一个或多个Partitions,并且是唯一的Consumer;一个Consumer group的多个consumer的所有线程依次有序地消费一个topic的所有partitions,如果Consumer group中所有consumer总线程大于partitions数量,则会出现空闲情况。这样可以做到负载均衡,也可以实现顺序消费(group中只有一个consumer)。
Broker:
一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
topic:
可以理解为一个MQ消息队列的名字。每条发布到Kafka集群的消息都有一个类别,这个类别被称为topic。(物理上不同topic的消息分开存储,逻辑上一个topic的消息虽然保存于一个或多个broker上但用户只需指定消息的topic即可生产或消费数据而不必关心数据存于何处)。
Partition:
parition是物理上的概念,每个topic包含一个或多个partition,创建topic时可指定parition数量。每个partition对应于一个文件夹,该文件夹下存储该partition的数据和索引文件。为了实现扩展性,一个非常大的topic可以分布到多个 broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息 都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体 (多个partition间)的顺序。也就是说,一个topic在集群中可以有多个partition,那么分区的策略是什么?(消息发送到哪个分区上,有两种基本的策略,一是采用Key Hash算法,一是采用Round Robin算法)
Offset:
kafka的存储文件都是按照offset.kafka来命名,用offset做名字的好处是方便查找。例如你想找位于2049的位置,只要找到2048.kafka的文件即可。当然the first offset就是00000000000.kafka
2、架构
leader-followers结构
每个分区都由一个服务器作为“leader”,零或若干服务器作为“followers”,leader负责处理消息的读和写,followers则去复制leader.如果leader down了,followers中的一台则会自动成为leader。集群中的每个服务都会同时扮演两个角色:作为它所持有的一部分分区的leader,同时作为其他分区的followers,这样集群就会据有较好的负载均衡。同时,副本也保证了kafka的容错能力。
Zookeeper负责选择leader和保存kafka的元数据(服务器和topic名称等信息)
3、Kafka消息处理
Producer根据指定的partition方法(round-robin、hash等),将消息发布到指定topic的partition里面。
kafka集群接收到Producer发过来的消息后,将其持久化到硬盘,并保留消息指定时长(可配置),而不关注消息是否被消费。
Consumer从kafka集群pull数据,并控制获取消息的offset。
Kafka需要维持的元数据只有一个–消费消息在Partition中的offset值,Consumer每消费一个消息,offset就会加1。其实消息的状态完全是由Consumer控制的,Consumer可以跟踪和重设这个offset值,这样的话Consumer就可以读取任意位置的消息。
4、消息存储的策略
Paste_Image.png1)kafka以topic来进行消息管理,每个topic包含多个partition,每个partition对应一个逻辑log,有多个segment组成。
2)每个segment中存储多条消息(见下图),消息id由其逻辑位置决定,即从消息id可直接定位到消息的存储位置,避免id到位置的额外映射。
3)每个segment在内存中对应一个index,记录每个segment中的第一条消息偏移。
4)发布者发到某个topic的消息会被均匀的分布到多个partition上(或根据用户指定的路由规则进行分布),broker收到发布消息往对应partition的最后一个segment上添加该消息,当某个segment上的消息条数达到配置值或消息发布时间超过阈值时,segment上的消息会被flush到磁盘,只有flush到磁盘上的消息订阅者才能订阅到,segment达到一定的大小后将不会再往该segment写数据,broker会创建新的segment。
顺序读写
由于kafka存储消息时,都是在最后一个segment末尾追加数据,顺序写入。(segment写满创建新的segment,默认一个segment下log文件是500兆),而且kafka消费后不删除消息(只是每个segment log文件设置保留时间,默认7天)。
segment的log文件名都是以segment中最后一个记录id为名称,读取消息时,首先通过二分查找可以很迅速找到对应的segment的log文件,然后根据log文件对应的index文件的索引找到所需的记录。(index中存储的是对应log文件中记录的稀疏索引。存储key-value格式,key即为log文件中消息的编号,1,3,6,8...并不连续,这样的稀疏索引避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中,value即为索引编号在log文件中的物理位移。当然稀疏索引不能直接定位到消息记录,但也保证顺序扫描的范围就足够小)
以查找368773消息为例,通过二分查找,可以定位到368769.log文件,为该文件中的第(368773-368769=4)条记录,然后根据368769.index中的索引,得到扫描的范围在368769.log文件的497到1407之间,最终找368773消息在log中830的位置。
网友评论