一、kafka数据结构
先说结论,kafka是持久化的消息队列框架。接下来,我会以kafka设计者的角色,带你理解其文件目录结构的设计初衷。
1.主题Topic
假设kafka接受到一个消息之后,不管是什么类型的消息,都直接将其写入同一个文件末端。那么在我们消费端要消费一个订单类型消息时,由于订单类型消息分散地分布在这个文件中,其效率是非常低的。所以kafka根据主题(比如订单消息、客户消息等)分类,然后作为日志数据放入对应主题所属的持久化文件末端,提供消息消费者读取。
2.日志段LogSegment
如果只设置一个主题文件,那么这个文件会越来越大。虽然硬盘空间相对内存空间宽裕,但是如果需要检索数据或删除其中过期的数据,显然效率会很低。同时,由于实际kafka运行时操作的是日志文件加载在PageCache中的内存数据(通过系统的分页技术持久化到硬盘文件中),大文件加载到内存中的消耗会很大,于是,就有了日志段的概念,我们将一个主题的文件拆分成一个文件夹底下对应多个日志段,我们可以手动设置日志段的大小,当一个日志段文件达到上限之后,写入一个新的日志段文件,这样一来,我们就可以方便地删除过期数据。
3.分区Partition
容易理解的是,一个主题的持久化文件,文件头部为消息队列队头,文件尾部为队尾,提供消费者消费,日志段只不过是将一个队列对应的有序文件数据队列拆分成多个文件块而已。那么,这个主题对应的所有日志段,就是一个队列。队列的操作大家都清楚,必然是队头第一个数据出队被消费之后才能消费下一个,从而保证有序。假设有三个线程要来消费这个队列的文件,只能加锁操作,1线程先操作拿到a数据,然后2线程拿到b数据以此类推(否则2线程可能又拿到a),这种方式实现复杂且性能表现不好。所以,就有了分区的概念。我们将一个主题拆分为多个分区,每个分区对应一个文件夹,相当于将一个主题的队列拆成多个队列,每个分区对应的队列都可以独立地提供消费,再结合分区独占的特性(消费者章节会详细说),从而在满足高并发的前提下避免并发控制带来的消耗。显然,到这一步,主题就失去了物理结构了,分区是主题的拆分,而不是主题的附属,就像你把一个队列A拆分成队列a和队列b之后,队列A就没有存在的必要了。
4.副本broker
假设只有一台机器在处理消息,那么就可能因为这台机器宕机或硬件故障导致丢失消息。所以kafka就搞了个副本机制出来,把所有消息同步复制到多个副本机器上,每个副本叫做一个broker。不过,假设所有broker都能执行入队操作,那么如何保证队列的数据一致性呢,所以,broker也区分leader和follower,只有leader能执行入队(写)操作,follower只能处理出队操作(实际不会删除消息队列数据),leader宕机之后,从follower中选举一个leader就好了。
5.分散leader
假设机器一上BrokerA为leader,机器二上BrokerB为follower。在前面我们知道,入队操作都在leader上,follower只处理出队操作。实际上,B作为副本,其数据相对leaderA可能会落后,所以,出队即消费行为也倾向于在A上进行。显然,B的性能就会闲置,对于大规模的并发入队操作,B节点有性能闲置也帮不上什么忙,A会非常繁忙。回过头想想,kafka并不是一个队列处理所有消息。消息区分了主题,主题又拆为分区,所以有多个队列。聪明的你应该想到了,我们将A设置为订单主题的分区队列1的leader,B设置为订单主题的队列2的leader,同时A上有队列2的容灾副本,B上面有队列1的容灾副本。这样一来,每个队列都有副本,且leader分散在不同机器的broker上,性能压力也就分散开了。
恭喜你!你设计了如下图的的kafka架构

6、消息ProducerRecord
消息主要包含 主题(Topic)、分区(Partit


555

被折叠的 条评论
为什么被折叠?



