kafka的架构中包含了kafka集群的设计,在kafka集群中,其中包含了几个重要部分:
(1)broker
kafka 集群包含一个或多个服务器,每个服务器节点称为一个broker。
(2)topic
每条发布到kafka集群的消息都有一个类别,这个类别称为topic,其实就是将消息按照topic来分类,topic就是逻辑上的分类,同一个topic的数据既可以在同一个broker上也可以在不同的broker结点上。
(3)partition
分区,每个topic被物理划分为一个或多个分区,每个分区在物理上对应一个文件夹,该文件夹里面存储了这个分区的所有消息和索引文件。在创建topic时可指定parition数量,生产者将消息发送到topic时,消息会根据分区策略追加到分区文件的末尾,属于顺序写磁盘,因此效率非常高,如图2.2所示(经验证,顺序写磁盘效率比随机写内存还要高,这是Kafka高吞吐率的一个很重要的保证)。
(4)controller
broker的leader,kafka集群中多个broker,有一个会被选举为controller,注意与partition的leader区分,一个是broker的leader,我们称为controller,一个是分区副本的leader,我们称为leader。
(5)leader
partition的leader,每个partition有多个副本,其中有且仅有一个作为leader,leader会负责所有的客户端读写操作。
(6)follower
follower不对外提供服务,只与leader保持数据同步,如果leader失效,则选举一个follower来充当新的leader。当follower卡住或者同步太慢,leader会把这个follower删除重新创建一个follower。
(7)offset
partition中的每条消息都被标记了一个序号,这个序号表示消息在partition中的偏移量,称为offset,每一条消息在partition都有唯一的offset,消息者通过指定offset来指定要消费的消息。如图2.2中partition的消息写入示意图。
正常情况下,消费者在消费完一条消息后会递增offset,准备去消费下一条消息,但也可以将offset设成一个较小的值,重新消费一些消费过的消息,可见offset是由consumer控制的,consumer想消费哪一条消息就消费哪一条消息,所以kafka broker是无状态的,它不需要标记哪些消息被消费过。
(8)rebalance
同一个consumer group下的多个消费者互相协调消费工作,我们这样想,一个topic分为多个分区,一个consumer group里面的所有消费者合作,一起去消费所订阅的某个topic下的所有分区(每个消费者消费部分分区),kafka会将该topic下的所有分区均匀的分配给consumer group下的每个消费者,如下图3.1所示。
rebalance表示"重平衡",consumer group内某个消费者挂掉后,其他消费者自动重新分配订阅主题分区的过程,是 Kafka 消费者端实现高可用的重要手段。如下图Consumer Group A中的C2挂掉,C1会接收P1和P2,以达到重新平衡。同样的,当有新消费者加入consumer group,也会触发重平衡操作。
如图3.3所示,一个典型的kafka集群中包含若干producer,若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高),若干consumer group,以及一个zookeeper集群。kafka通过zookeeper协调管理kafka集群,选举broker的controller、分区leader,以及在consumer group发生变化时进行rebalance。
kafka的topic被划分为一个或多个分区,多个分区可以分布在一个或多个broker节点上,同时为了故障容错,每个分区都会复制多个副本,分别位于不同的broker节点,这些分区副本中(不管是leader还是follower都称为分区副本),一个分区副本会作为leader,其余的分区副本作为follower。其中leader负责所有的客户端读写操作,follower不对外提供服务,仅仅从leader上同步数据,当leader出现故障时,其中的一个follower会顶替成为leader,继续对外提供服务。
对于传统的MQ而言,已经被消费的消息会从队列中删除,但在Kafka中被消费的消息也不会立马删除,在kafka的server.propertise配置文件中定义了数据的保存时间,当文件到设定的保存时间时才会删除,因为Kafka读取消息的时间复杂度为O(1),与文件大小无关,所以这里删除过期文件与提高Kafka性能并没有关系,所以选择怎样的删除策略应该考虑磁盘以及具体的需求。
(1)点对点模式 VS 发布订阅模式
传统的消息系统中,有两种主要的消息传递模式:点对点模式、发布订阅模式。
①点对点模式
生产者发送消息到queue中,queue支持存在多个消费者,但是对一个消息而言,只可以被一个消费者消费,并且在点对点模式中,已经消费过的消息会从queue中删除不再存储。
②发布订阅模式
生产者将消息发布到topic中,topic可以被多个消费者订阅,且发布到topic的消息会被所有订阅者消费。而kafka就是一种发布订阅模式。
(2)消费端 pull 和 push
① push方式
由消息中间件主动地将消息推送给消费者。
优点:优点是不需要消费者额外开启线程监控中间件,节省开销。缺点:无法适应消费速率不相同的消费者。因为消息的发送速率是broker决定的,而消费者的处理速度又不尽相同,所以容易造成部分消费者空闲,部分消费者堆积,造成缓冲区溢出。
② pull方式:
由消费者主动向消息中间件拉取消息。
优点:消费端可以按处理能力进行拉取;缺点:消费端需要另开线程监控中间件,有性能开销;
对于Kafka而言,pull模式更合适。pull模式可简化broker的设计,Consumer可自主控制消费消息的速率,同时Consumer可以自己控制消费方式,既可批量消费也可逐条消费,同时还能选择不同的提交方式从而实现不同的传输语义。
Kafka文件存储也是通过本地落盘的方式存储的,主要是通过相应的log与index等文件保存具体的消息文件。
生产者不断的向log文件追加消息文件,为了防止log文件过大导致定位效率低下,Kafka的log文件以1G为一个分界点,当.log文件大小超过1G的时候,此时会创建一个新的.log文件,同时为了快速定位大文件中消息位置,Kafka采取了分片和索引的机制来加速定位。
在kafka的存储log的地方,即文件的地方,会存在消费的偏移量以及具体的分区信息,分区信息的话主要包括.index和.log文件组成,分区目的是为了备份,所以同一个分区的不同副本存储在不同的broker上。
如图3.5所示,“.index” 文件存储大量的索引信息,“.log” 文件存储大量的数据。首先通过二分查找对应的.index文件,在0.index中;然后通过第一个0.index文件定位元素的位置3,定位到之后获取起始偏移量+当前文件大小=总的偏移量;获取到总的偏移量之后,直接定位到.log文件即可快速获得当前消息。