第三章KafKa关键流程
3.1 Kafka工作流程概述
Kafka以快速,可靠,持久,容错和零停机的方式提供基于发布-订阅和基于队列的消息传递系统。在这两种情况下,生产者只需将消息发送到某个主题,消费者就可以根据自己的需要选择任何一种消息传递系统。让我们按照下一部分中的步骤来了解消费者如何选择自己选择的消息传递系统。
Kafka只是主题(Topic)的集合,分为一个或多个分区。Kafka分区是消息的线性顺序序列,其中每个消息均由其索引(称为偏移)标识。Kafka群集中的所有数据都是分区的脱节联合。传入消息写入分区的末尾,使用者依次读取消息。通过将消息复制到不同的代理来提供持久性。
3.2 生产者端
1.将数据包装为ProducerRecord对象Producer通过调用send(ProducerRecord)发送消息,ProducerRecord对象包含Topic等信息;
2. Interceptor拦截器,通过API可以自定义拦截器,过滤掉不需要的信息;
3. 序列化由于kafka是集群工作模式,集群之间传递需要序列化(Serilizer);
4. 分区(partition)send()函数参数Topic、value为必选项,可选项包括key、partition以及头信息。
(1)当send()函数中指定partition时,将指定的值作为partition的分区;
(2)当send()函数未指定partition时,但有key值时,用topic分区个数对key的hash值取余,余数作为分区值;
(3)当send()函数未指定partition也没有key值时,kafka会随机选择一个分区,直到batch填满或者发送完成,下次发送时再随机选择一个分区,即黏性分区策略。
3.3缓存区
kafka的Producer发送消息采用异步发送,涉及到两个线程sender和main,以及一个共享变量RecordAccumulator。main线程将消息发送给;
RecordAccumulator,sender线程不断从RecordAccumulator中拉去消息。
RecordAccumulator就是不断的把消息装进不同地址的箱子ProducerBatch,装满封箱,堆放起来(Deque
),然后继续生产箱子。
3.4 broker
1. 消息的可靠性保证
(1) 返回ack的策略选择当broker的topic下的partition接收到消息时,为保证leader宕机后,仍然在剩下的follower中能选举出leader,有两种策略,当follower中半数以上拷贝完毕即发送ack,或者全部发送完成后发送ack,同样为保证n台节点宕机后,保证能选举出含有消息的leader,前者延迟低,后者副本数少kafka选择全部拷贝完毕,后再返回ack;
(2)返回ack的优化kafka接收消息中,如果存在follower宕机,导致不能返回ack时,此时leader会将此follower踢出ISR队列后,返回ack;
(3)kafka的ack应答级别kafka对于数据中不太重要的数据,可以调整应答级别;
级别0:接收到消息还未写入磁盘时,即返回ack,此时leader宕机时会丢失数据;
级别1:leader落盘完成,即返回ack,如果follower同步完成之前leader发生故障,那么将会丢失数据;
级别-1:follower同步完成后发送ack,如果follower同步完成之后发送ack之前发送故障,那么会导致数据重复。
(4)
leader故障:从follower中选出新leader,剩余follower会将HW之后的数据删除,重写从新的leader处同步;
follower故障:follower恢复之后,开始从leader处同步数据,待数据同步到HW时,重新将此follower加入IRS队列。
(5)kafka写消息的幂等性及事务机制
当kafka写数据时,将ack设置为-1时,仍存在数据重复的问题,kafka引入幂等性及事务机制解决此问题,kafka幂等性的实现方法,将每个Producer编号ProducerID,将ProducerID、Partition、SequenceNumber作为唯一标识,保证数据的唯一性,为保证Producer宕机导致ProducerID发生改变,引入事务机制保证ProducerID的相同。
2. 文件存储机制
kafka会根据Topic的partition生产不同文件夹,在文件夹内部会根据参数log.segment.bytes来生产文件,默认1G,每个文件对应文件后缀为.log,同时对应一个.index,index文件里为每个消息的offset与position(实际物理位置),.log文件储存文件大小、文件数据本身等。
3.5 消费者端
1. 分区分配策略
(1)轮询(Roundbin)
轮询策略为获取一个随机值,使用分区的个数对随机数取余,将此余数代表的分区放到消费者组中的第一个消费者,然后分区数加1,在放到第二个消费者,依次轮询
(2)随机(Range)
先将分区个数除消费者组中的消费者个数,根据余数及除数获得消费者组内每个消费者获得分区个数,然后按照分区顺序将分区整体随机分配给消费者,如7个分区,3个消费者,分区数0,1,2分配到一个消费者,3,4分配到另一个消费者,5,6分配到最后一个消费者中。
3. offset维护
为了保证consumer出现宕机后,仍能从故障处开始消费,0.9版本之前kafka将offset存在zookeeper中,之后将offset存在kafka中的内置topic,该topic为__consumer_offsets。
offset的提交有两种模式,自动模式以及手动模式,自动模式为每隔一定时间提交,手动提交分为同步提交和异步提交,一般采取异步提交方式
3.6 工作流程
生产者-Kafka集群-消费者组;当生产者往某一个不存在的主题里发数据的时候,它自己会创建一个主题、一个分区和一个副本(server.properties里定义的)。一般是先会创建一个主题,比如说TopicA,有三个分区,有两个副本(leader+follower总共2个),同一个分区的两个副本肯定不在一个服务器。生产者往三个分区发送消息(发送消息可以批量发送、也可以一个个发送),其中0,1,2,3,4,5叫做偏移量,如图发送了15条消息,每一个分区维护了一个从头开始的偏移量。follower会主动同步(备份)leader的消息(就算同步了,某种特定的情况下也会丢数据),消费者只会找leader消费。
Kafka并不能保证消息的全局有序性,只能保证区内有序。就是说消费消息的时候不是按分区顺序来。
Kafka中的消息是以topic进行分类的,生产者生产消息,消费者消费消息,都是面向topic的。
topic是逻辑上的概念,而partition是物理上的概念。每一个partition对应于一个log文件,该log文件中存储的就是producer生产的数据。producer生产的数据会被不断追加到该log文件末端,且每条数据都有自己的offset。消费者组中的每个消费者,都会实时记录自己消费到了哪个offset,以便出错恢复时,从上次的位置继续消费。
3.7 kafka存储机制
由于生产者生产的消息会不断追加到log文件末尾,为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition分为多个segment。每个segment对应两个文件——“.index”文件和“.log”文件。这些文件位于一个文件夹下,该文件夹的命名规则为:topic名称+分区序号。例如,first这个topic有三个分区,则其对应的文件夹为first-0,first-1,first-2。 00000000000000000000.index
00000000000000000000.log
00000000000000170410.index
00000000000000170410.log
00000000000000239430.index
00000000000000239430.log
分区的好处:
1. 方便集群的伸缩
每个Partition可以通过调整以适应它所在的机器,而一个topic又可以有多个Partition组成,因此整个集群就可以适应任意大小的数据了;
2. 可以提高并发
可以以Partition为单位读写,提高集群的读写速度;
分区是如何分配到broker上;
保证所有的分区以及副本可以均衡在分布上所有的broker上;
保证同一个分区及其副本尽量不要分布在同一个broker上;
副本(replication)好处:
提高kafka的系统的可靠性和稳定性,同一个partitation对应一个或者多个副本,创建topic时就可以设置(–replication-factor 2)。没有副本,一旦当前保存消息的服务器宕机,就会造成消息丢失,如果有replication,当保存消 息的服务器宕机后,从新选举新的leader,继续进行消息读写,不会造成消息丢失。
zk保存kafka数据的目录结构:
1. broker在zk中注册:集群启动时,每个broker都会在/brokers/ids/下注册(创临时节点),如果broker挂掉了,zk就会删除该节点。
2. topick会在zk中注册:创建topic时,每个topic都会在/brokers/topics/下注册,topic删除,节点失效。每个broker和topic的对应关系也是由zk进行维护。3,consumer(消费者)在zk注册:当新的消费者都会k进行注册,zk在/consumers/consumer-group/创建3个节点idsoffsets(偏移量) ownersids:记录当前消费者组所有的消费者id;
offsets:消费者在消费topic每个partition时,消费到哪个位置(offset偏移
量);
owners:记录该消费者组消费的topic信息(订阅了哪些topic)。
3.8 生产者如何写入消息的
为保证producer发送的数据,能可靠的发送到指定的topic,topic的每个partition收到producer发送的数据后,都需要向producer发送ack(acknowledgement确认收到),如果producer收到ack,就会进行下一轮的发送,否则重新发送数据。
消息写入时,放入分区的规则:
1. 指定分区,直接按照指定分区写入;
2. 没有指定分区,但是消息中含有key(一般消息是key value的方式),通过key的值进行hash运算,计算得到一个partition,写入到这个分区。(aaa hash运算后可能得到一个和aaa没有任何关系的一个数值123132,对分区的总数量取模,根据结果,得到分区);
3. 如果没有指定分区,key都没有,使用轮询(第一次调用时随机生成一个整数(后面每次调用在这个整数上自增),将这个值与 topic 可用的 partition 总数取余得到 partition 值,也就是常说的 round-robin 算法),找出一个分区,并写入。
ack应答机制:
0 producer不等待broker同步完成的确认,继续发送下一条(批)信息提供了最低的延迟。但是最弱的持久性,当服务器发生故障时,就很可能发生数据丢失。例如leader已经死亡,producer不知情,还会继续发送消息broker接收不到数据就会数据丢失;
1 producer要等待leader成功收到数据并得到确认,才发送下一条message。此选项提