broker能够理解成一个kafka服务node,是一个运行的kafka服务。broker与broker之间是平等的关系,任意broker均可以down机而不影响其余broker正常工做。kafaka在启动的时候,会将本身的信息同步到zk上。数据存储使用了zk的零时节点,broker须要经过心跳机制维护与zk的注册关系,一旦broker宕机,zk上面对应的零时节点也会被删除。
咱们能够把controller当成集群的管理者,集群中borker启动时若是没有controller回主动的去zk上注册znode节点来抢夺controller的位置,注册成功的broker会被当选为kafka controller。若当前的controller宕机其余borker会从从新进入controller争抢流程,从而选出新的controller。controller主要的功能以下:html
Zookeeper的/brokers/topics
下建立znode来触发建立逻辑,而controller会监听该path下的变动来执行真正的“建立topic”逻辑。/admin/delete_topics/<topic>
节点来触发删除topic,controller执行真正的逻辑/admin/reassign_partitions
节点来触发,controller负责按照方案分配分区/admin/preferred_replica_election
写数据,controller提取数据执行preferred leader分配Topic至关于传统消息系统MQ中的一个队列queue,能够把topic当成是消息的分类。partiton能够当作是topic的一个分区,目的是突破IO瓶颈。kafka在存储topic日志的时候,将topic分开存储,这样就能将同一个消息的写压力分配到不一样的分区,这样能够提高kafka的总体吞吐能力。为了保证数据的高可用,kafka使用partiton-Replica进行数据备份,若partition leader挂了,kafka controller会自动从partiton-Replica选举新的leader。提到备份不得不提到ISR,这是一个同步备份列表,每当用户添加新的消息时,分区leader成功写入日志后,后必须保证ISR列表里面的备份也成功写入日志后,才能给客户端相应成功。所以ISR列表的备份的日志老是和leader保持一致,在leader宕机的时候,可使用ISR列表的备份取代leader的位置。node
kafka最终的数据承载是经过log的方式进行,kafka会按照请求的顺序将消息存储到log中。咱们知道一个topic可能会被分配到到个分区partiton来减轻单点负载。每一个partiton实际上在写log的时候也会存在,单个文件大小物理极限的问题。所以kafka引入了segment解决方案,即将日志分段存储。不一样的segment log组合起来的数据就是分区的存储消息数据。为了方便经过offset定位消息,segment log使用first-offset格式进行文件命名,first-offset是该文件存储的第一条消息的offset。这样就能经过消费者提供的offset很快定位到文件,而后经过offset偏移量能够快速定位消息的存储位置。apache
生产者负责消息的发送,生产者须要指定消息的topic来区分不一样消息。kafka收到消息后经过loadbalance策略,使用hash(message) % topic分片数
决定将数据存储到哪个分片。 而后将message发送到制定分片的leader,leader收到消息后,将消息保存下来,接着等待ISR(a set of in-sync replicas,该列表的备份数据时刻保持和leader数据一致)中的replica消费消息并发送ack,若ISR列表中的备份分区都已经确认收到消息并保存成功后,leader将成功的消息返回给producer以代表,消息被妥善保存。并发
与其余消息系统不一样的是:kafka不会复制去保存客服端以前消费了那条消息,以及下一条应当消费那条消息,kafka将这些工做交给了消费客服端来作,所以kafka在消息消费能够作到无状态。offset就是用来保存某个消费组(consumer group)消费的在当前分区日志下的偏移量的。一般状况下,多个客服端在同时消费同一个消息分区消息的时候会存在并发问题,对于offset的控制就会出现问题,这样就会出现消费重复的状况,kafka使用无锁机制解决这个问题。kafka规定,同一个分区(partition)下的数据只能被通一个consumer group中的一个线程消费,这样就避免了不一样线程之间争夺通一个资源,经过这种设计kafka作到了无锁,这样能够避免锁竞争形成效率降低。所以建议consumer group里面的线程数应当和分区数保持一致,这样作能够有效的利用线程资源,线程多了会被浪费掉,少了一个线程可能会处理多个分区的数据。若是你须要多个业务消费同一个消息,因为不一样的consumer group对赞成主题分区的offset是分开存储的,咱们能够建立多个consumer group实现多个线程来消费同一个消息的目的。.net
写数据:经过上面消息的存储过程能够发现,除了数据存储和备份操做,并无其余耗时操做。路由分区->leader写数据->数据复制,这些操做都和现有数据规模没有任何关系。每次写数据只会在原来的基础上作追加存储。因为kafka使用了顺序存储而不是非随机存储(听说磁盘的顺序存储效率远高于磁盘的随机存储、有时候甚至比内存的随机写效率还高),同时kafka还使用了批量存储的方式减小了对io的操做,提高了io效率。
读数据:consumer在消费某个topic的时候,消费者会将全部的分区数据消费完,kafka要求,同一时刻对同一分区的数据只会被一个线程消费,这样避免了锁操做。同时经过consumer group提供的offset数据,经过kafka的文件存储机制能够快速的定位到一个segment文件,而且经过计算offset偏移量能够快速定位到数据。从整个消费流程来看,数据规模对每一个过程效率是不敏感的。线程
高可用的解决方案一般是采用数据冗余以及快速恢复来解决的。kafka经过分区数据备份(partition replica)&分区数据分散到不一样的机器以及kafka controller能够快速检测到宕机节点,经过读取节点的分区数据,能够快速从新选取分区leader,以恢复故障。同时在故障的处理过程当中,就算该分区不可用,不往分区写入数据便可,对kafka的数据读取也是没有影响的。kafka使用hash 取余的目的在于均衡负载,并不在于为了经过message能够快速的查找到这个message所在位置,这个不是kafka关注的业务。kafka经过数据复制和快速恢复作到了高可用,同时基于message不关注经过某个具体message的具体存存储位置,所以在扩展kafka的时候,或者在扩展消息分区的时候,不须要进行额为的数据复制操做,下降了扩展时候的成本。设计
更多文章能够访问jframe.cn日志