知识点:
消息队列:发布(pub)/订阅模式,点对点(P2P)模式
kafka:是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统
特性: 可以实时的处理大量数据以满足各种需求场景
Broker:Kafka节点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群
Topic:一类消息,消息存放的目录即主题,例如page view日志、click日志等都可以以topic的形式存在,Kafka集群能够同时负责多个topic的分发
Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列,可以削峰,负载均衡等。
Consumer Group:一个Consumer Group包含多个consumer
leaders / followers 以及 同一个消费者组不能同时消费同一个分区的数据。
所有处理都由leader处理,followers只做备份用。
ACK 应答机制:0 1 all ,0 发送不需要管kafka是否接收到数据,1 确保leader接收到数据,all确保leader和所有followers都备份
...............................
视频:
黑马程序员Kafka视频教程,大数据企业级消息队列kafka入门到精通_哔哩哔哩_bilibili
消息队列:
消息队列(Message Queue:MQ) 一种用来存储消息的队列,先进先出
特点:
1 消息队列用于存放消息的组件
2 程序员可以将消息放入队列中,也可以从消息队列中获取消息
3 很多时候消息队列不是一个永久性的存储,是作为临时存储存在的(设置一个期限)
4 消息队列中间件,eg:Kafka,Active MQ,RabbitMQ等
消息队列中间件:
消息队列中间件就是用来存储消息的软件(组件),举个例子:为了分析网站的用户行为,我们需要记录用户的访问日志。这些一条条的日志,可以看作一条条的消息,我们可以把它们存到消息队列中,将来有一些应用程序需要处理这些日志,可以随时将这些消息取出来处理
消息队列的应用场景:
1 异步处理:
用于保存信息的同时,还需要发送邮件,短信等,需要额外等待一段时间,此时可以用消息队列来进行异步处理,从而实现快速响应
2 系统解耦
源系一个微服务是通过接口(HTTP)调用另一个微服务,这时候耦合性很严重,只要接口发生变化就会导致系统不可用
使用消息队列可以将系统进行解耦合,现在第一个微服务可以将消息放入到消息队列中,另一个微服务可以从消息队列中把消息取出来进行处理,进行系统解耦合
3 流量削峰
因为消息队列是低延迟,高可靠,高吞吐,所以可以应对大量并发
4 日志处理(大数据领域常见)
可以使用消息队列作为临时存储,或者一种同学管道
生产者、消费者模型
生产者生产消息,放到消息队列中,消费者从消息队列中拉取消息
消息队列的两种模式:
1 点对点模式(P2P)
发送者发送消息到消息队列中,然后消息接收者从消息队列中取出并消费消息。消息被消费以后,消息队列中不再有存储,所以消息接收者不可能消费到已经被消费的消息
特点:
1.1 每个消息只有一个接收者(consumer): 即一旦被消费,消息就不再消息队列中
1.2 发送者和接收者没有依赖性,发送者发送消息之后,不管有没有接收者在运行,都不会影响到发送者下次发送消息
1.3 接收者在成功接收消息之后需向队列应答成功,以便消息队列删除当前接收的消息
2 发布/订阅模式
特点:
2.1 每个消息可以有多个订阅者
2.2 发布者和订阅者之间有时间上的依赖。 针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布的消息
2.3 为了消费消息,订阅者需要提前订阅该角色主题,并保持在线运行
Kafka集群搭建:
kafka搭建教程:
Kafka配置文件server.properties详解
Kafka配置文件server.properties详解_kafka server.properties-CSDN博客
主要的几个
#这个表示当前broker在集群中的一个唯一标识,如果集群有3个broker,则分别为0,1,2
broker.id=0
#kafka存放数据的地方,如果要存放到多个地址的话用逗号分割 /tmp/kafka-log,/tmp/kafka-log2
log.dirs=/tmp/kafka-logs
#对外端口号
# port=
# sock的监听
listeners=PLAINTEXT://192.168.52.32:9092
#zookeeper集群的地址,可以是多个,多个之间用逗号分割
hostname1:port1,hostname2:port2,hostname3:port3
zookeeper.connect=localhost:2181
#是否允许自动创建topic,如果是false,需要通过命令创建topic
auto.create.topics.enable=true
#一个topic,默认分区的replication(副本)个数,不能大于集群中broker的个数
default.replication.factor=1
#每个topic的分区个数
num.partitions=1
#是否开启日志压缩
log.cleaner.enable=false
#日志的清理策略 有delete和compact,主要针对过期数据的处理
log.cleanup.policy=delete
KafkaTool :
查看kafka里的数据
Kafka命令:
bin下的脚本说明
1、kafka-acls.sh #配置,查看kafka集群鉴权信息
2、kafka-configs.sh #查看,修改kafka配置
3、kafka-console-consumer.sh #消费命令
4、kafka-console-producer.sh #生产命令
5、kafka-consumer-groups.sh #查看消费者组,重置消费位点等
6、kafka-consumer-perf-test.sh #kafka自带消费性能测试命令
7、kafka-mirror-maker.sh #kafka集群间同步命令
8、kafka-preferred-replica-election.sh #重新选举topic分区leader
9、kafka-producer-perf-test.sh #kafka自带生产性能测试命令
10、kafka-reassign-partitions.sh #kafka数据重平衡命令
11、kafka-run-class.sh #kafka执行脚本
12、kafka-server-start.sh #进程启动
13、kafka-server-stop.sh #进程停止
14、kafka-topics.sh #查询topic状态,新建,删除,扩容
常用: kafka-console-consumer.sh,kafka-console-producer.sh,kafka-topics.sh,kafka-server-start.sh,kafka-server-stop.sh
Kafka基准测试
测试kafka的吞吐量,传输速度等
springboot 集成kafka
SpringBoot——集成Kafka详解_springboot kafka-CSDN博客
配置信息可是视情况增加或减少
Kafka的重要概念(参考文档 一文了解kafka相关概念 - 知乎):
生产者(Producer):
Producer 采用推(push)模式将消息发布到broker,每条消息都被追加(append)到分区(partition)中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障kafka吞吐率)
生产者参数配置:
生产者的参数配置
参数 | 描述 |
acks | acks 参数指定了必须要有多少个分区副本收到消息,生产者才会认为消费写入是成功的。acks = 0 生产者在成功写入消息之前不会等待任何来自服务器的响应。(缺点:无法确认消费是否成功;优点:高吞吐量);acks = 1 只要集群的首领节点收到消息,生产者就会收到一个来自服务器的成功响应。如果消费无法到达首领节点(比如首领节点奔溃,新的首领还没有被选举处理),生产者会收到一个错误响应,为了避免数据丢失,生产者会重发消息。不过,如果一个没有收到消息的节点成为新首领,消息还是会丢失。acks = all 只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。 |
buffer.memory | 该参数用来设置生产者缓冲区的大小,生产者用它缓冲要发送到服务器的消息。0.9.0.0 版本被替换成了 max.block.ms,表示在抛出异常之前可以阻塞一段时间 |
compression.type | 默认情况下为none,消费发送时不会被压缩。该参数可以设置为snappy、gzip或lz4,它指定了消息被发送给broker之前使用哪一种压缩算法进行压缩。1. snappy 压缩算法有Google发明,它占用较少的CPU,却能提供较好的性能和相当可观的压缩比(比较关注性能和网路带宽) 2. gzip 压缩算法一般会占用较多的CPU,但会提供更高的压缩比(网络带宽有限次采用) |
retries | 生产者从服务器收到的错误有可能是临时性的错误(比如分区找不到首领)。在这中情况下,retries参数是值决定了生产者可以重发消息的次数,如果达到这个次数,生产者会放弃重试并返回错误。默认情况下,生产者会在每次重试之间等待100ms,可以通过retry.backoff.ms参数来改变这个时间间隔. |
batch.size | 当有多个消息需要被发送到同一个分区时,生产者会把它们放在同一个批次里。该采纳数指定了一个批次可以使用的内存大小,按照字节数计算(而不是消息个数)。1. 批次设置很大 不会造成延迟,只会占用更多的内存 2. 批次设置很小 因为生产者需要更频繁地发送消息,会增加一些额外的开销 |
linger.ms | 该参数指定了生产者在发送批次之前等待更多消息加入批次的时间。 |
client.id | 该参数可以是任意的字符串,服务器会用它来识别消息的来源,还可以用在日志和配额指标里 |
request.timeout.ms | 指定了生产者在发送数据时等待服务器返回响应的时间 |
max.block.ms | 该参数指定了在调用send()方法或使用partitionsFor()方法获取元数据时生产者的阻塞时间。当生产者的发送缓冲区已满,或者没有可用的元数据时,这些方法就会阻塞。在阻塞时间达到max.block.ms时,生产者会抛出超时异常 |
max.request.size | 该参数用于控制生产者发送的请求大小。它可以指能发送的单个消息的最大值,可以指单个请求里所有消息总的大小。 |
消费者(Consumer):
消息接收者称为Consumer
- consumer 采用pull(拉)模式从broker中读取数据
- push(推) 模式很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成consumer来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而pull模式则可以根据consumer的消费能力以适当的速率消费消息
- 对于Kafka而言,pull模式更合适,它可简化broker的设计,consumer可自主控制消费消息的速率,同时consumer可以自己控制消费方式——即可批量消费也可逐条消费, 同时还能选择不同的提交方式从而实现不同的传输语义
- pull 模式不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直等待数据到达。为了避免这种情况,我们在拉请求中有参数,允许消费者请求在的等待数据到达的"长轮询"中进行阻塞(并且可选地等待到给定的字节数,以确保打的传输大小)
消费者组(Consumer Group)
- 这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。topic的消息会复制(概念上的复制)到所有的CG,但每个partition只会把消息发给该CG中的一个consumer。如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic
- 每个分区在同一时间只能由group中的一个消费者读取,但是多个group可以同时消费这个partition。
- 消费者通过向被指派为群组协调器的broker发送心跳来维持它们和群组的从属关系以及它们对分区的所有权关系.
Kafka 消费过程分析:高级Consumer API 和 低级 Consumer API
高级API
高级API 优点
- 高级API写起来简单
- 不需要自行去管理offset,系统通过zookeeper自行管理
- 不需要管理分区,副本等情况,系统自动管理
- 消费者断线会自动根据上一次记录在zookeeper中的offset去接着获取数据(默认设置1分钟更新一下zookeeper中存的offset)
- 可以使用group来区分对同一个topic的不同程序访问分离开来(不同的group记录不同的offset,这样不同程序读取同一个topic才不会因为offset互相影响)
高级API 缺点
- 不能自行控制offset(对于某些特殊需求)
- 不能细化控制,如分区、副本、zk等
低级API
低级API优点
- 能够让开发者自己控制offset,想从哪里读取就从哪里读取
- 自行控制连接分区,对分区自定义进行负载均衡
- 对zookeeper的依赖性降低(如:offset不一定非要靠zk存储,自行存储offset即可,比如存储在文件或则内存中)
低级API缺点
- 太过复杂,需要自行控制offset,连接哪个分区,找到分区leader等
代理(Broker)
已发布的消息保存在一组服务器中,称之为Kafka集群。集群中的每一个服务器都是一个代理
主题(Topic)
- Kafka将消息以topic为单位进行归纳(一条消息必须属于某一个主题)
- 在Kafka集群中,可以有无数的主题
- Kafka 的主题始终是支持多用户订阅的;也就是说,一个主题可以有零个,一个或多个消费者订阅写入的
分区(Partitions)
消息发送时都被发送到一个topic,其本质就是一个目录,而topic是由一些Partition Logs(分区日志)组成
- 每个Topic都有一个或者多个Partitions 构成
- 每个Partition都是有序且不可变的消息队列
- Topic的Partition数量可以在创建时配置
- Partition数量决定了每个Consumer group中并发消费者的最大数量
- 分区的原因:
- 方便在集群中扩展,每个Partition可以通过调整以适应它所在的机器,而一个topic又可以有多个Partition组成,因此整个集群就可以适应任意大小的数据了;
- 可以提高并发,因为可以以Partition为单位读写
- 分区的原则:
- 指定了partition,则直接使用
- 未指定partition但指定key,通过对key的value进行hash出一个partition
- partition和key都未指定,使用轮询选出一个partition
- 偏移量(offset)
- 任何发布到partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset是一个long型数字,它唯一标记一条消息。消费者通过(offset、partition、topic)跟踪记录.
副本(replicas)
已发布的消息保存在一组服务器中,称之为Kafka集群。集群中的每一个服务器都是一个代理。)
副本因子操作的单位是以分区为单位,每个分区都有各自的主副本和从副本,主副本叫做leader,从副本叫做follower,处于同步状态的副本叫做in-sync。
导致副本同步失败的原因:
-
- 网络拥塞导致复制变慢
- broker 发生奔溃导致复制滞后
持续的副本:持续请求得到最新消息副本被称为同步的副本。在leader发生失效时,只有同步副本才有可能被选为新leader
复制
Kafka的复制机制和分区的多副本架构是Kafka可靠性保证的核心。把消息写入多个副本可以是Kafka在发送崩溃时仍能保证消息的持久性。
- Follower 通过拉的方式从leader同步数据。消费者和生产者都是从leader读写数据,不与follower交互
- 当有多个副本数时,kafka并不是将多个副本同时对外提供读取和写入,作用是让kafka读取和写入数据时的高可靠
- log 日志
- kafka-log 目录下,会根据: 主题-分区 值创建目录
- 00000000000000000000.index —— 索引 稀疏索引
- 00000000000000000000.log 数据
- log 默认情况下会根据1G的大小,创建一个新的segment file文件
- 00000000000000001123.index -- 1123 offset的开始值
- 00000000000000001123.log
- log 的优化:可以选择删除或者合并
控制器(controller)
控制器其实就是一个broker。集群里第一个启动的broker通过在Zookeeper里创建一个临时节点 /controller 让自己成为控制器。其他broker在启动时也会尝试创建这个节点,不过它们会收到一个"节点已存在"的异常,然后"意识"到控制器节点已存在,也就是说集群里已经有一个控制器了。其他broker在控制器节点上创建Zookeeper watch对象,这样它们就可以收到这个节点的变更通知。这种方式可以确保集群里一次只有一个控制器存在。
如果控制器被关闭或者Zookeeper断开连接,Zookeeper上的临时节点就会消失。集群里的其他broker通过watch对象得到控制器节点消失的通知,它们会尝试让自己成为新的控制器。第一个在Zookeeper里成功成功创建控制器节点的broker就会成为新的控制器,其他节点会收到"节点已存在"的异常,然后在新的控制器节点上再次创建watch对象。每个新选出的控制器通过Zookeeper的条件递增操作获得一个全新的、数值更大的controller epoch。其他broker在知道当前controller epoch后,如果收到有控制器发出的包含旧epoch的消息,就会忽略它们。
当控制器发现一个broker已经离开集群(通过观察相关的Zookeeper路径),它就知道,那些失去首领的分区需要一个新首领(这些分区的首领刚好在这个broker上)。控制器遍历这些分区,并确定谁应该成为新首领(简单来说就是分区副本列表里的下一个副本),然后向所有包含新首领或现有跟随者的broker发送请求。该请求消息包含了谁是新首领已经谁是分区跟随者的信息。随后新首领开始处理来着生产者和消费者的请求,而跟随者开始从新首领那里复制消息。
当控制器发现一个broker加入集群时,它会使用broker ID来检查新加入的broker是否包含现有的分区副本。如果有,控制器就把变更通知发送给新加入的broker和其他broker,新broker上的副本开始从首领那里复制消息。
集群成员关系
Kafka 使用Zookeeper来维护集群成员的信息。每个broker都有一个唯一标识符,这个标识符可以在配置文件里指定,也可以自动生成。在broker启动的时候,它通过创建临时节点把自己的ID注册到Zookeeper。
Kafka组件监听Zookeeper的 /brokers/ids 路径(broker在Zookeeper上的注册路径),当有broker加入集群或退出集群时,这些组件就可以获得通知。在broker停机、出现网络分区或长时间垃圾回收停顿时,broker会从Zookeeper上断开连接,此时broker在启动时创建的临时节点会自动从Zookeeper上移除。监听broker列表的Kafka组件会被告知该broker已移除。在关闭broker时,它对应的节点也会消失,不过它的ID会继续存在于其他数据结构中
偏移量OffSet:
offset记录着下一条将要发送给consumer的消息的序号
默认kafka将offset存储在zk里
在一个分区中,消息是有顺序的方式存储着,每个在分区的消费都是一个递增的id,这个就是偏移量offset
偏移量在分区中才是有意义的,在分区之间,offset是没有任何意义的
Test:
1 某个主题,1个分区,2个消费者(A,B)在同一个消费者组,生产者持续有序写入1,2,3,4,5..., 其中一个消费者会获取消息:1 ,2,3,4,5..., 另一个消费者得不到消息。 因此一个消费者消费一个分区的数据。
2 某个主题,2个分区,2个消费者(A,B)在同一个消费者组,生产者持续有序写入1,2,3,4,5...,消费者A持续读取到:1,3,5,7,9...,另一个消费者B持续读取到:2,4,6,8...
因此,对于kafka而言,同一个消费者组的可以看作一个整理,消费一个topic,如果某个主题有多个消费者组,则每个组都能拿到1,2,3,4,5...用于不同的事情消费。而同一个消费者组内的消费者共同消费一份数据,只拿到一份1,2,3,4,5...
Kafka幂等性
所谓幂等性,数学概念就是: f(f(x)) = f(x) 。f函数表示对消息的处理。
比如,银行转账,如果失败,需要重试。不管重试多少次,都要保证最终结果⼀定是⼀致的。
保证在消息重发的时候,消费者不会重复处理。即使在消费者收到重复消息的时候,重复处理,也要保证最终结果的⼀致性。
Kafka幂等性实现
添加唯⼀ID,类似于数据库的主键,⽤于唯⼀标记⼀个消息。
Kafka为了实现幂等性,它在底层设计架构中引⼊了ProducerID SequenceNumber。
ProducerID:在每个新的Producer初始化时,会被分配⼀个唯⼀的ProducerID,这个ProducerID对客户端使用者是不可见的。
SequenceNumber:对于每个ProducerID,Producer发送数据的每个Topic和Partition都对应⼀个从0开始单调递增的SequenceNumber值。
幂等性的详细说明:Kafka的幂等性 - 简书
生产者的分区写入策略
1 轮询策略
若没有指定 Partition 和 Key,就使用轮询策略
2 随机策略(基本不用)
3 按 key 分配策略
若没有指定 Partition,但是指定了 key,就按照 key 的 hash 值选择 Partition
4 自定义分区策略
消息乱序问题
- 轮询策略和随机策略,造成Kafka 中的数据是乱序存储的
- 按 key 分区,一定程度上可以实现数据的有序存储——局部有序,但是又可能会造成数据倾斜
kafka数据有序
Kafka中的消息都是被发布到某个Topic的。一个Topic可以配置多个Partition,Partition是Kafka进行并行操作的基本单位。
对于同一个Partition来说,其中消息必须严格按照生成顺序进行 Append。这保证了每个Partition内部的消息递增有序。但是跨Partition的消息则不保证有序。不同Partition分布在不同的Broker上,彼此之间没有顺序保证。
消费消息时,每个Partition只能被同一个Consumer Group中的一个Consumer消费,这样保证了每个Partition内消息的消费顺序。但不同Partition的消息可能被同一个Group的不同Consumer并行消费,因此无法保证顺序。
如果要跨Partition保证顺序,需要在消费端进行排序,维护消息偏移等元数据,以将不同Partition的消息重新组合有序。
此外,消费者还可以采用分区分配策略,使每个实例只消费一个或几个Partition,来简化排序问题。
所以Kafka本身只能保证每个Partition内的有序性,跨Partition需要消费端协作进行排序。这些机制共同支持消息序列的有序处理。
如何保证数据有序性
Topic配置Partition数为1,这样全局只有一个Partition,数据默认有序。但这制约了Kafka的 scalability。
Producer端对消息打上全局唯一的序号ID,或者使用Kafka自带的分区器按序号对消息Partition。消费时可以按序号排序。
Consumer端采用只订阅单个Partition的方式消费数据,而不是跨Partition订阅,这保证了一个Partition顺序。Consumer端自己维护偏移及排序,跨Partition订阅后MERGE排序。可在DB中存 last offset。
将相关联的消息发送到同一个Partition,不同类型消息分配到不同Partition。减小分区数可减少排序问题。采用可以重置偏移的Kafka消费者模式,以读取历史有序数据。采用Spark Streaming等支持有序接收Kafka数据并处理的框架。
设置为单节点单分区,并开启log compaction。新消息会覆盖key相同的老消息,确保单调递增顺序。调整max.message.bytes以控制批次大小,间接控制顺序粒度
消费者组Rebalance机制
Kafka中的Rebanlance称之为 重平衡 或者 再均衡,是kafka中确保消费者组下所有的消费者如何达成一致,分配订阅的主题的每个分区的机制
触发的时机:
1 消费者组中的消费者的个数发生变化
2 订阅的主题的个数发生改变
3 订阅的主题的分区数发生变化
不良影响:
1 发生Rebalance时,消费者组下的所有消费者都会协调在一起共同参与,kafka使用分配策略尽可能达到最公平的分配
2 Rebanlance过程会对消费者组产生非常严重的影响,Rebalance的过程中所有的消费者都将停止工作,直到Rebalance完成
参考文档: 【Kafka】kafka 重平衡(Rebalance)_kafka rebalance-CSDN博客
消费者的分区分配策略:
1 Range范围分配策略:
Range范围分配策略是Kafka默认的分配策略,它可以确保每个消费者消费的分区数量是均衡的
# 配置消费者的partition.assignment.strategy为org.apache.kafka.clients.consumer.RangeAssignor
props.put("partition.assignment.strategy", "org.apache.kafka.clients.consumer.RangeAssignor");
算法公式:
n = 分区数量 / 消费者数量
m = 分区数量 % 消费者数量
前m个消费者消费n+1个,剩余消费者消费n个
2 RoundRobin轮询策略:
RoundRobinAssignor 轮询策略是将消费组内所有消费者以及消费者所订阅的 所有topic的partition 按照字典序排序(topic和分区的hashcode进行排序),然后通过轮询方式逐个将分区以此分配给每个消费者
#配置消费者的partition.assignment.strategy为org.apache.kafka.clients.consumer.RoundRobinAssignor:
props.put("partition.assignment.strategy", "org.apache.kafka.clients.consumer.RoundRobinAssignor");
3 Stricky粘性分配策略:
从Kafka 0.11.x开始,引入此类分配策略。主要目的:分区分配尽可能均匀
在发生 rebalance 的时候,分区的分配尽可能与上一次分配保持相同。没有发生rebalance 时,Striky粘性分配策略和 RoundRobin 分配策略类似
Kafka副本机制
副本的目的就是冗余备份,当某个Broker上的分区数据丢失时,依然可以保障数据可用。因为在其他的Broker上的副本是可用的
producer的ACKs参数
// 配置ACKs参数,all或者-1是确保消息写入到leader分区、还确保消息写入到对应副本都成功后,接着发送下一条,性能是最差的
props.put("acks", "all");
// 配置ACKs参数1, 生产者会等到leader分区写入成功后,返回成功,接着发送下一条,性能中等
props.put("acks", "1");
// acks = 0:生产者只管写入,不管是否写入成功,可能会数据丢失。性能是最好的
props.put("acks", "0");
高级API 和 低级API
高级API:
优点:
不需要执行管理offset, 直接通过zk管理, 也不需要管理分区、副本, 由kafka统一管理;
消费者会自动根据上一次在zk中保存的offset去接着获取数据;
在zk中, 不同的消费者组, 同一个topic记录不同的offset, 这样不同程序读取同一个topic, 不会受到offset的影响;
缺点:
- 不能控制offset, 例如: 从指定的位置读取数据;
- 不能细化控制分区、副本、zk等;
低级API:
通过使用低级API, 可以自己来控制offset, 想从哪读, 就从哪读; 而且, 可以自己控制连接分区, 对分区自定义负载均衡;
之前offset是自动保存在ZK中, 使用低级API, 可以将offset不一定使用zk存储, 可以自己来存储offset, 例如: 存储文件、Mysql、内存等;
但是低级API比较复杂, 需要执行控制offset连接到那个分区, 并找到分区的leader;
监控工具: kafka-eagle
安装:kakfa从入门到放弃(四): 分区和副本机制、高级与低级API、 kafka-eagle、原理、数据清理、限速-CSDN博客
Kafka原理
在kafka中,每个broker可以以配置多个分区以及多个副本,每个分区都有一个leader以及0个或者多个follower,在创建topic时,kafka会将每个分区的leader均匀地分配在每个broker上。我们正常使用kafka是感觉不到leader的日志数据文件,如果leader出现故障时,follower就会被选举成为leader。
1 kafka 中的leader负责处理读写操作,而follower只负责副本数据的同步
2 如果leader出现故障,其他follower会被重新选举成为leader
3 follower像一个consumer一样,拉取leader对于分区的数据,并保存到日志数据文件中
注意,和zk的区分
zk的leader负责读写,follower可以读取数据
kafka的leader负责读写,但follower不能读写数据,只负责同步。
kafka的一个topic有多个分区leader,一样可以实现负载均衡
AR,ISR,OSR,HW,LEO
AR ( Assigned Replicas ):分区中的所有副本统称为 AR
ISR(On-Sync Replicas):所有与 leader 副本保持一定程度同步的副本(包括 leader 副本在内〕组成 ISR
OSR (Out-of-Sync Replicas ):与 leader 副本同步滞后过多的副本(不包 leader 副本)组成
AR = ISR + OSR,默认情况下,当leader副本发生故障时,只有ISR集合中的副本才有资格被选举为新的leader
HW:HW是 High Watermark 的缩写,俗称高水位,它标识了一个特定的消息偏移量( offset ),消费者只能拉取到这个 offset 之前的消息。
LEO:LEO是 Log End Offset 缩写,它标识当前日志文件中下一条待写入消息 offset,如上图的日志中已经写了0~8号数据,那么offset为9的位置即为当前日志文件的LEO
参考文档: kafka中AR、ISR、OSR以及HW、LEO的区别_kafka leo-CSDN博客
Kafka的ISR收缩机制
ISR(In-Sync Replicas,同步副本) 的伸缩性是指ISR的能力适应负载变化和副本增减的能力。ISR的伸缩性对于Kafka集群的性能和可靠性非常重要。
当Kafka集群的负载增加或减少时,ISR的伸缩性可以通过以下方式来实现:
副本增加:当负载增加时,可以通过增加follower副本来提高ISR的伸缩性。新的follower副本将追赶上leader副本的同步进度,并加入ISR,从而分担负载。
副本减少:当负载减少时,可以通过减少follower副本来提高ISR的伸缩性。不再需要的follower副本将被移出ISR,并停止与leader副本的同步,从而减轻负载。
通过动态调整ISR的大小,Kafka可以根据负载的变化来自动平衡数据分布和副本同步,以提供更好的性能和可靠性。ISR的伸缩性是Kafka集群能够处理大规模数据流的关键因素之一。
参考文档:Kafka的ISR收缩机制_replica.lag.time.max.ms-CSDN博客
【项目实战】Kafka 分区中的AR、ISR、OSR_kafka isr osr-CSDN博客
controller
介绍:
kafak启动时, 会在所有的broker中选择一个controller, controller是高可用的;
leader和follower是针对partition副本的, 而controller是针对broker的;
创建topic, 添加分区, 修改副本数据量之类的任务管理都是由controller完成的;
kafka分区副本keader的选举, 也是有controller决定的;
选举:
在kafka集群启动的时候, 每个broker都会尝试去Zookeeper上注册称为Controller(zk临时节点);
但只有一个竞争成功, 其他的broker会注册该节点的监视器;
一个节点状态发生变化, 就可以进行相应的处理;
controller也是高可用的, 一旦某个broler崩溃, 其他的broker会重新注册为controller;
controller选举partition leader
所有partition的leader选举都由controller决定的
controller会将leader的改变直接通过RPC的方式通知需要为此做出响应的broker
controller读取到当前分区ISR, 只要有一个Replica还幸存,就选择这个作为leader, 否则, 则任意选择一个replica作为leader
如果该partition的所有replica都已经宕机, 则新的leader为-1
为什么不能通过ZK的方式选举partition的leader?
如果业务很多, kafka集群会有很多partiton;
假设某个broker宕机, 就会出现很多个partition都需要重新选举leader;
如果使用zookeeper选举leader, 会给zookeeper带来巨大的压力; 所以, kafka中leader的选举不能使用zk实现;
leader的负载均衡
kafka中引入[preferred-replica]的概念, 即: 优先的replic
在ISR列表中, 第一个replica就是preferred-replica
使用一下脚本可以将preferred-replica设置为leader, 均匀分配每个分区副本的leader
./kafka-leader-election.sh --bootstrap-server node1:9092 --topic 主题 --partition=1 --election-type preferred
如果某个broker crash之后, 就可能会导致副本的leader分布不均匀, 就是一个broker上存一个topic下不同partition的leader副本
kafka事务:
参考文档:Kafka事务「原理剖析」-CSDN博客
kafka生产、消费数据工作流程、kafka的数据存储形式、消息不丢失机制、数据积压
参考: kakfa从入门到放弃(四): 分区和副本机制、高级与低级API、 kafka-eagle、原理、数据清理、限速-CSDN博客
数据丢失: 消费者获取offset,拉取数据,但存储过程失败,又提交了offset,拉取新的数据,这条数据便丢失了
数据重复:消费者获取offse,拉取数据,存储成功,但提交offset提交zk失败,拉取数据仍然是之前的offset,造成数据重复
只消费一次:低级 API ,可以从MYSQL中读取offset, 如果offset写入mysql中失败,可以使用Mysql事务,将写入到Mysql的数据和offset放在一个Mysql事务里,要么全部成功,要么全部失败
参考文档:
kafka面试题:kafka中controller的作用_Kafka最新面试题-CSDN博客
最后,感谢所有大佬做出的资料整理和分享