第一章 Kafka概述
1.1 定义
Kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue),主要应用于大数据实时处理领域。
1.2 消息队列
1.2.1 应用场景
传统消息队列有同步处理和异步处理。同步处理是说当流程走完后才能向用户返回结果;异步处理是某一流程结束后,就可以向用户返回结果,后续步骤可以在向用户返回结果后接着执行。
使用消息队列(MQ)的好处:
1)解耦合
MQ两侧的内容可以修改和扩展,只要保持接口不变
2)可恢复性
系统的一部分组件失效时,不会影响到整个系统。当用户填写的注册信息加入到MQ消息队列后,即使运营商发送消息的进程出现故障,也可以在故障修复后从MQ中读取消息并向用户发送消息。不会影响前一阶段的用户注册。
3)缓存
当生产者的生产速率过大而消费者的消费速率低于前者时,可能导致消息丢失或者积压。通过MQ可以先将消息写入到队列中,消费者直接从队列中获取。
4)峰值处理能力
如果某一时刻有源源不断的消息加入到MQ中,运营商不会因为并发量过大而宕机。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
5)异步通信
消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
1.2.2 消息队列的两种模式
(1)点对点模式
消费者主动拉取数据,消息收到后清除队列中的消息,对一个消息而言只能被一个消费者读取消费
(2)发布-订阅模式
生产者将消息发布到topic中,每个订阅了这个topic的消费者都会消费这个topic的消息。同时可以有多个消费者消费同一条消息。
1.3 Kafka基础架构
Kafka Cluster:每个集群中的机器都有一个brokerID,而且ID不可重复
Producer:消息生产者,向kafk broker的某个topic生产消息
Cosumer:消息消费者,从kafka broker中某个topic取消息
Consumer Group(CG):消费者组,由多个consumer组成。
规则:一个消费者组中的一个消费者可以同时消费一个topic中的多个分区的数据。
一个topic中的一个分区只能被通一个消费者组中的一个消费者消费
Broker:一台kafka服务器就是一个broker,一个集群由多个broker组成。一个broker可以容纳多个topic
Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列;
Replica:副本,为保证集群中的某个节点发生故障时,该节点上的partition数据不丢失,且kafka仍然能够继续工作,kafka提供了副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower。
leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。
follower:每个分区多个副本中的“从”,实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,某个follower会成为新的leader。
第二章 kafka命令行操作
1**)**查看当前服务器中的所有topic
kafka-topics.sh --list --bootstrap-server hadoop102:9092
2**)**创建topic
kafka-topics.sh --create --bootstrap-server hadoop102:9092 --topic topic1
--partitions 分区数
--replication-factor 副本数
3**)**删除topic
kafka-topics.sh --delete --bootstrap-server hadoop102:9092 --topic topic1
4**)**发送消息(生产)
kafka-console-producer.sh --broker-list hadoop102:9092,hadoop103:9092 --topic topic1
5**)**消费消息
kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic topic1
6**)**查看Topic的详情
kafka-topics.sh --describe --bootstrap-server hadoop102:9092 --topic topic1
kafka-topics.sh --describe --bootstrap-server hadoop102:9092 查看所有topic详情
7**)**修改分区数
kafka-topics.sh --alter --bootstrap-server hadoop102:9092 --topic topic1 --partitions 4
只可以往大了修改,不可以往小了修改,修改分区后涉及到重新分配分区,有多种策略
第三章 Kafka架构深入
3.1 Kafka工作流程及文件存储机制
3.1.1 工作流程
Kafka中消息是以topic进行分类的,生产者生产消息到某个topic,消费者从某个topic中消费消息。
3.1.2 文件存储机制
topic只是逻辑上的概念,partition是物理上的概念,就是在底层是以partition为单位存储的。生产者生产的消息在linux中显示为topic名称+分区号。
每个partition中有log文件和index文件,log文件存储的就是producer生产的数据,index文件对应的是log文件中每条消息的偏移量。producer生产的消息会不断的追加到log文件的末尾,index文件记录每条消息从哪里开始,以便于查找。
当log文件过大时,记录的index就是失去身的意义,查找也变得缓慢。为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition分为多个segment。每个segment对应两个文件——“.index”文件和“.log”文件。当log文件大于1G时,才会分成多个segment。每个分区的多个.index和.log位于对应的topic+分区号文件夹中。
比如,second这个topic中有2个分区,其对应的文件夹为second-0, second-1。每个文件夹中有多个segment,每个segment有对应的index和log文件
index和log文件以当前segment的第一条消息的offset命名。
“.index”文件存储大量的索引信息,“.log”文件存储大量的数据,索引文件中的元数据指向对应数据文件中message的物理偏移地址。
3.2 Kafka 生产者
3.2.1 分区策略
(1) 分区的原因
1)方便在集群中扩展,一个topic可以分成多个partition,增加分区就可以增加存储的数据大小。
2)可以提高并发,Kafka 是以partition为单位进行读写的,每个partition互不影响。
(2) 分区的原则
将producer生产的数据包装成一个ProducterRecord对象发送到分区中。
1)指明分区就直接发送到指定的partition中
2)未指明分区,但指定了key的值,将key的hash码与topic的分区个数取余得到的结果作为partition值
3)既为指明分区,又未指明key,现在kafka采用黏性分区。先随机使用一个分区,然后尽可能的一直使用该分区,等该分区的batch已满或者等待时间够再换另一个分区使用。
3.2.2 数据可靠性保证
(1)生产者发送数据到topic partition的可靠性保证
生产者发送数据到topic的某个分区,分区收到数据后向生产者发送ack确认。如果producer收到ack后,会进行下一轮的数据发送,否则等待一段时候后重新发送此次数据。
(2)topic partition存储数据的可靠性保证
主要取决于集群中的leader何时发送ack确认。
1)副本数据同步策略
方案 | 优点 | 缺点 |
---|---|---|
半数以上完成同步,就发送ack | 延迟低 | 选举新的leader时,容忍n台节点的故障,需要2n+1个副本 |
全部完成同步,才发送ack | 选举新的leader时,容忍n台节点的故障,需要n+1个副本 | 延迟高 |
2)ISR
Leader维护了一个ISR列表,列表中存储和leader保持同步的follower集合。当ISR中的follower完成数据同步后,会给leader发送ack消息。若follower发生故障,长时间未向leader同步数据,leader长时间没有收到ISR列表中某个follower的ack消息,就会把这台机器从ISR移除。这段时间阈值由replica.lag.time.max.ms参数设定。
此外leader发生故障后,会从ISR中选举出新的leader。
3)ack应答级别
如果数据不太重要,允许部分丢失的情况下,就没必要等到ISR中的follower全部接受成功。Kafka提供了三种应答级别,用户可以根据可靠性和延迟的要求进行权衡选择配置。
acks参数配置:
0:leader收到数据还未写入到磁盘就发送ack。此时当leader发生故障会造成数据丢失。
1:leader收到数据后写入磁盘,但follower还未进行同步,此时leader发生故障会造成数据丢失。
-1(all):leader收到数据后写入磁盘,并且所有的follower从leader同步数据并写入磁盘后返回ack。如果在follower写入磁盘后,但是leader发送ack之前,leader发生故障,会从ISR中选举出一个新的leader,而producer未收到上次发送数据的ack确认消息,会重新发送上次数据,可能会造成数据重复。
(3)故障处理
HW高水位:HW之前包括HW的数据已经发送ack确认。
LEO:指的是每个副本最大的offset
HW:指的是消费者能见到的最大的offset,ISR队列中最小的LEO
1)leader发生故障
选举ISR中下一个follower为leader,为保证多个副本之间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据。
2)follower 故障
follower发生故障后会被临时踢出ISR,待该follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向leader进行同步。等该follower的LEO大于等于该Partition的HW,即follower追上leader之后,就可以重新加入ISR了。
3.2.3 Exactly Once语义
ack=-1时只能保证数据不丢失,不能保证不重复。即就是At Least Once语义。ack=0时能保证数据不重复,不能保证数据不丢失。即At Most Once语义。如何保证既不丢失又不重复呢?kafka在0.11版本引入了一条特性:幂等性。就是producer server无论发送了多少条重复数据,server段只会持久化一条。At Least Once + 幂等性 = Exactly Once
要启用幂等性,只需要将Producer的参数中enable.idempotence设置为true即可。Kafka的幂等性实现其实就是将原来下游需要做的去重放在了数据上游。开启幂等性的Producer在初始化的时候会被分配一个PID,发往同一Partition的消息会附带Sequence Number。而Broker端会对<PID, Partition, SeqNumber>做缓存,当具有相同主键的消息提交时,Broker只会持久化一条。
但是PID重启就会变化,同时不同的Partition也具有不同主键,所以幂等性无法保证跨分区跨会话的Exactly Once。