Kafka中的消息是以topic进行分类的,生产者生产消息,消费者消费消息都是面向topic。而每个topic里面都是有分区的概念,一个topic有三个分区,而每个分区都是有分区leader(partition leader)和partition follower,注意重点,每个leader和follower对应的在不同的服务器,否则一个服务器挂掉了,则没有任何备份的意义。每个数据都有offset,主要是记录每次消费到哪个位置,方便kafka宕机后从当前位置继续消费。
比如broker0里有topicA-partition0-leader 和 topicA-partition1-follower
Broker1里有topicB-partition1-leader 和 topicB-partition0-follower
Topic是逻辑上的概念,partition是物理上的概念,每个partition都对应一个log文件,producer生成数据的信息就存储在这个log文件里,每次生产数据都会append进入。
这时候kafka为了防止数据过大,采用了分段segment和索引的机制来方便查找数据,每个segment都有对应的log文件和index文件。
Kafka在通过producer保证数据的可靠性,当topic的分区接受到消息时,会返回一个ack确认收到消息,如果收到消息,则会进入下一轮发送新的数据,否则会一直重复发送当前数据。
副本数据同步有两种方案,半数以上topic分区完成同步则直接发送ack,这种方案有点延迟低,速度快,但是当宕机选举新的leader时候,容忍n台故障机器,这时候需要2n+1个副本。第二种方案则延迟高,这个选举新的leader时候,容忍n台故障机器,需要n+1个副本。
Kafka选择了第二种方案,因为kafka毕竟是存储高并发大数据的,数据量大的是时候,副本越多成本越大,而网络延迟对kafka影响比较小。
采用第二种方案后,如果leader收到数据,follower都开始同步数据,但有一个follower发生故障,这时候就会影响整个流程,所以就有了ISR机制,当有其中一个follower宕机的时候,会将该follower踢出ISR,这里会有一个过期时间,过期时间由replica.lag.time.max.ms参数设定,当leader发生故障则重新选举新的leader。
对于一些不是很重要的数据,可以允许丢失,所以每次等topic回复ack很影响效率,这时候有三个ack的应答机制:
0、producer不等待broker的ack,这个机制延迟最低,但宕机时候可能数据会丢失。
1、Producer等待broker的ack,当leader成功后返回ack,这时候宕机会导致follower数据丢失。
-1、也就是all,这个是延迟最高,必须所有的都返回ack。但可能会造成数据重复,当同步到leader和follower之后,leader挂掉了,这时候选举新的leader,于是再次通过leader同步一次数据到follower。
分区分配策略:一个consumer group有多个consumer,一个topic会有多个partition,所以必然涉及到partition分配问题,确定哪个partition由consumer来消费。Kafka有两种分配策略,一个是RoundRobin,一个是Range。
RoundRobin:轮询消费,但是缺点是会消费到未订阅的数据,比如吧消费者consumerA 和consumerB看做一个整体,然后消费topicA和topicB,如果consumerA只订阅了topicA,但是因为他们是一个整体,所以会消费到未订阅的数据,优点是负载均衡。
Range:按范围分配,每个consumer消费特定的区间partition,但是缺点就是可能消费不均衡。
Kafka在0.9版本之前是吧offset保存在zookeeper种,但是在之后的版本,是吧offset保存在kafka内置的topic种,这个topic叫做_consumer_offset。
Kafka高效读写数据
Kafka是分布式消息队列,因为topic的分区特性,并发读写能力强。
顺序写磁盘:kafka需要producer写入log文件种,磁盘写都是很慢的,但是kafka采用顺序写方式,因为随机写会在磁盘种找地址值,kafka官方文档测试表示随机写100kb/s,顺序写能600m/s。
零复制技术:直接由系统内核来处理文件读写,省去了与用户空间交互部分。
Zookeeper在kafka中会负责选举新的broker作用,当其中主的broker宕机时候,则会通过zookeeper来选举,还有前面说的存储offset但是0.9版本之后就没存了。
Kafka事务在11版本之后引入了事务,当消费者和生产者跨分区时候,要么全部成功,要么全部失败。
Producer事务:为了实现事务跨分区,所以事务ID肯定是全局的,又为了防止宕机数据事务消失,所以又会吧事务id存入kafka其中一个topic,为了管理事务,引入了transaction coordinator组件。
Consumer事务:上述事务主要针对producer,对于消费端而言事务相对来说较弱,尤其无法保证commit信息精准消费,这是由于consumer可以通过offset访问任意信息。