Kafka学习

kafka的介绍

在这里插入图片描述

Kafka是一种消息队列,主要用来处理大量数据状态下的消息队列,一般用来做日志的处理。既然是消息队列,那么Kafka也就拥有消息队列的相应的特性。

百科解释

Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群来提供实时的消息。

使用消息队列的好处

解耦合
	耦合的状态表示当你实现某个功能时,是直接接入当前接口,而利用消息队列,相对应的消息发送到消息队列,即使接口有了问题,也不会直接影响当前功能。
异步处理
异步处理代替之前的同步处理,异步处理不需要走完流程就返回结果,可以将消息发送到消息队列中,然后返回结果,剩下的让其他业务处理接口从消息队列中去消费处理即可。
流量削峰
高流量的时候,使用消息队列作为中间件可以将流量的高峰保存在消息队列中,从而防止了系统的高请求,减轻服务器的请求处理压力。

Kafka消费模式

主要有两种一个一对一,一个一对多。
一对一消费,也即点对点的通信,即一个发送一个接受
一对多消费即一个消息发送到消息队列,消费者根据消息队列的订阅拉取信息消费。	
一对一

在这里插入图片描述

消费生产者发布信息到Queue队列中,通知消费者从队列中拉取信息进行消费
消息被消费之后则删除,Queue支持多个消费者
但对一个消费消息,只有一个消费者可以消费,即一条消息只能被一个消费者消费。

一对多
在这里插入图片描述

发布订阅模式
利用Topic来存储消息。消息生产者将信息发布到Topic中
同时有多个消费者订阅此topic。
消费者可以从中消息信息,注意发布到Topic中的消息会被多个消费者消费
消费者消费数据之后,数据不会被清除
Kafka会默认保留一段时间,然后会删除。

Kafka架构

Producer:消息生产者,向Kafka中发布消息的角色。
Consumer:消息消费者,即从Kafka中拉取消息消费的客户端。Consumer Group:消费者组,消费者组则是一组中存在多个消费者,消费者消费Broker中当前Topic的不同分区中的消息,消费者组之间互不影响,所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。某一个分区中的消息只能够一个消费者组中的一个消费者所消费。Broker:经纪人,一台Kafka服务器就是一个Broker,一个集群由多个Broker组成,一个Broker可以容纳多个Topic。
Topic:主题,可以理解为一个队列,生产者和消费者都是面向一个TopicPartition:分区,为了实现扩展性,一个非常大的Topic可以分布到多个Broker上,一个Topic可以分为多个Partition,每个Partition是一个有序的队列(分区有序,不能保证全局有序)
Replica:副本Replication,为保证集群中某个节点发生故障,节点上的Partition数据不丢失,Kafka可以正常的工作,Kafka提供了副本机制,一个Topic的每个分区有若干个副本,一个Leader和多个Follower
Leader:每个分区多个副本的主角色,生产者发送数据的对象,以及消费者消费数据的对象都是Leader。
Follower:每个分区多个副本的从角色,实时的从Leader中同步数据,保持和Leader数据的同步,Leader发生故障的时候,某个Follower会成为新的Leader。

docker安装方法

//拉取kafka镜像
docker pull wurstmeister/kafka
//拉取zookeeper镜像
docker pull wurstmeister/zookeeper 
/创建启动zookeeper容器
docker run -it --name zookeeper -p 2181:2181 -d wurstmeister/zookeeper:latest
//创建启动kafka容器
docker run -it --name kafka -p 9092:9092 -d -e KAFKA_BROKER_ID=0 -e KAFKA_ZOOKEEPER_CONNECT=192.168.174,128:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.174.128:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 wurstmeister/kafka:latest

这是我的安装笔记,可以参考
kafka安装部署

Kafka知识点

Kafka工作流程
如图:这是一个有三台Kafka机子的集群
在这里插入图片描述

有生产者Producer,Consumer,Broker(kafka服务器)
每个服务器上都有两个Topic队列,一个leader,一个follower,follower存储的是其他服务器的数据,这就保证了数据的安全性,kafka集群假如有一个服务器的Leader宕机,其他服务器的follower有存储他的数据是可以做应急处理的。

follower节点在Kafka中负责复制和存储其他服务器上的数据,主要基于以下几个原因:

  1. 容错和高可用性:Kafka设计为具有高度容错性和可伸缩性的分布式系统。通过在多个服务器上复制数据,可以确保即使某个节点出现故障,数据仍然可用,并且系统可以继续正常运行。
  2. 数据冗余:通过将数据复制到多个节点,可以提供数据冗余,从而减少数据丢失的风险。如果某个节点发生故障,可以从其他节点获取数据,确保数据的可靠性。
  3. 增加读取吞吐量:通过在多个服务器上存储副本,可以增加对数据的并发读取请求的处理能力。多个follower节点可以同时提供数据,以满足更多的读取请求。
  4. 提高写入吞吐量:Kafka使用分区来分布和处理消息。将分区的副本分散在多个节点上可以提高写入吞吐量。当有新的消息写入时,数据会被同时写入所有副本,从而实现并行写入操作。
    总之,通过在follower节点上存储其他服务器的数据,Kafka能够提供容错性、高可用性、数据冗余以及增加读写吞吐量的优势。、
生产者提供数据到Topic
消费者从Topic获取数据
消费者生产者都是面向Topic操作数据的。

文件存储

Topic是逻辑上的改变,Partition是物理上的概念,每个Partition对应着一个log文件,该log文件中存储的就是producer生产的数据,topic=N*partition;partition=log
Producer生产的数据会被不断的追加到该log文件的末端,且每条数据都有自己的offset,consumer组中的每个consumer,都会实时记录自己消费到了哪个offset,以便出错恢复的时候,可以从上次的位置继续消费。流程:Producer => Topic(Log with offset)=> Consumer.
为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition分为多个segment,每个segment包括:“.index”文件、“.log”文件和.timeindex等文件。
1、index为稀疏索引,大约每往log文件写入4KB数据,会往index文件写入一条索引。
参数log.index.interval.bytes默认4kb
2、index文件中保存到offset为相对offset,这样能确保offset的值所占空间不会过大,
因此能将offset的值控制在固定大小这些文件位于一个文件夹下,该文件夹的命名规则为:topic名称+分区序号
在这里插入图片描述

如果.log文件超出大小,则会产生新的.log文件。如下所示

00000000000000000000.index
00000000000000000000.log
00000000000000170410.index
00000000000000170410.log
00000000000000239430.index
00000000000000239430.log

此时如何快速定位数据,步骤:
.index文件存储的消息的offset+真实的起始偏移量。.log中存放的是真实的数据。
首先通过二分查找.index文件到查找到当前消息具体的偏移,如上图所示,查找为2,发现第二个文件为6,则定位到一个文件中。然后通过第一个.index文件通过seek定位元素的位置3,定位到之后获取起始偏移量+当前文件大小=总的偏移量。获取到总的偏移量之后,直接定位到.log文件即可快速获得当前消息大小

生产者分区策略

分区的原因

方便在集群中扩展:每个partition通过调整以适应它所在的机器,而一个Topic又可以有多个partition组成,因此整个集群可以适应适合的数据可以提高并发:以Partition为单位进行读写。类似于多路。

分区的原则

指明partition(这里的指明是指第几个分区)的情况下,直接将指明的值作为partition的值没有指明partition的情况下,但是存在值key,此时将key的hash值与topic的partition总数进行取余得到partition值值与partition均无的情况下,第一次调用时随机生成一个整数,后面每次调用在这个整数上自增,将这个值与topic可用的partition总数取余得到partition值,即round-robin算法。

生产者ISR

为保证producer发送的数据能够可靠的发送到指定的topic中,topic的每个partition收到producer发送的数据后,都需要向producer发送ackacknowledgement,如果producer收到ack就会进行下一轮的发送,否则重新发送数据。

发送ack的时机

确保有follower与leader同步完成,leader在发送ack,这样可以保证在leader挂掉之后,follower中可以选出新的leader(主要是确保follower中数据不丢失)
主要是要等follower复制完,这样follower就有leader数据了。

follower同步完成多少才发送ack
半数以上的follower同步完成,即可发送ack。
全部的follower同步完成,才可以发送ack。

ISR(同步副本集)

猜想

采用了第二种方案进行同步ack之后,如果leader收到数据,所有的follower开始同步数据,但有一个follower因为某种故障,迟迟不能够与leader进行同步,那么leader就要一直等待下去,直到它同步完成,才可以发送ack,此时需要如何解决这个问题呢?

解决

leader中维护了一个动态的ISR(in-sync replica set),即与leader保持同步的follower集合,当ISR中的follower完成数据的同步之后,给leader发送ack,如果follower长时间没有向leader同步数据,则该follower将从ISR中被踢出,该之间阈值由replica.lag.time.max.ms参数设定。当leader发生故障之后,会从ISR中选举出新的leader。
(相当于给所有的follower创建了一个集合一样,有ISR统一管理,一旦有follower出了问题,那么超出既定的时间阈值那么会将其移除集合中,保证后续leader接受新数据。)

kafka生产者的ack机制

Kafka的ack机制:指的是producer的消息发送确认机制 通过request.required.acks参数来设置
这直接影响到Kafka集群的吞吐量和消息可靠性。而吞吐量和可靠性就像硬币的两面,两者不可兼得,只能平衡。

1(默认):

producer在ISR中的leader已成功收到数据并得到确认。(leader写完即代表接收成功)
最低的延迟,但是最弱的持久性。
如果leader刚刚接收到消息,follwer还没来得及同步过去,结果leader所在的broker宕机了,此时也会导致这条消息丢失。

0:

producer无需等待来自broker的确认而继续发送下一批消息。(只管发 不管leader是否接收到)
这种情况下数据传输效率最高,但是数据可靠性确是最低的。
可能你发送出去的消息还在半路,leader所在broker就直接挂了,但是你的客户端还是认为消息发送成功,此时就会导致这条消息丢失。
在这里插入图片描述

-1(all):

producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成
持久性最好,延时性最差,可靠性最高。
但是当ISR中只有leader时 这样就变成了acks=1的情况。也会丢失数据。
但是如果在follower同步完成后,broker发送ack之前,如果leader发生故障,会造成数据重复。(这里的数据重复是因为没有收到,所以继续重发导致的数据重复)
在这里插入图片描述

数据一致性的问题

在这里插入图片描述

LEO(Log End Offset):每个副本最后的一个offsetHW(High Watermark):高水位,指代消费者能见到的最大的offset,ISR队列中最小的LEO。

follower故障和leader故障

follower故障:

follower发生故障后会被临时提出ISR,等待该follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向leader进行同步,等待该follower的LEO大于等于该partition的HW,即follower追上leader之后,就可以重新加入ISR了。

leader故障:

leader发生故障之后,会从ISR中选出一个新的leader,为了保证多个副本之间的数据的一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader中同步数据。这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复

ExactlyOnce

将服务器的ACK级别设置为-1(all),可以保证producer到Server之间不会丢失数据,即At Least Once至少一次语义。将服务器ACK级别设置为0,可以保证生产者每条消息只会被发送一次,即At Most Once至多一次。
At Least Once可以保证数据不丢失,但是不能保证数据不重复,而At Most Once可以保证数据不重复,但是不能保证数据不丢失,对于重要的数据,则要求数据不重复也不丢失,即Exactly Once即精确的一次。
在0.11版本的Kafka之前,只能保证数据不丢失,在下游对数据的重复进行去重操作,多余多个下游应用的情况,则分别进行全局去重,对性能有很大影响。
0.11版本的kafka,引入了一项重大特性:幂等性,幂等性指代Producer不论向Server发送了多少次重复数据,Server端都只会持久化一条数据。幂等性结合At Least Once语义就构成了Kafka的Exactly Once语义。
启用幂等性,即在Producer的参数中设置enable.idempotence=true即可,Kafka的幂等性实现实际是将之前的去重操作放在了数据上游来做,开启幂等性的Producer在初始化的时候会被分配一个PID,发往同一个Partition的消息会附带Sequence Number,而Broker端会对<PID,Partition,SeqNumber>做缓存,当具有相同主键的消息的时候,Broker只会持久化一条。
但PID在重启之后会发生变化,同时不同的Partition也具有不同的主键,所以幂等性无法保证跨分区跨会话的Exactly Once。

消费者分区策略

consumer采用pull拉的方式来从broker中读取数据。

push推的模式很难适应消费速率不同的消费者,因为消息发送率是由broker决定的,它的目标是尽可能以最快的速度传递消息,但是这样容易造成consumer来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而pull方式则可以让consumer根据自己的消费处理能力以适当的速度消费消息。

pull模式不足在于如果Kafka中没有数据,消费者可能会陷入循环之中 (因为消费者类似监听状态获取数据消费的),一直返回空数据,针对这一点,Kafka的消费者在消费数据时会传入一个时长参数timeout,如果当前没有数据可供消费,consumer会等待一段时间之后再返回,时长为timeout
一个consumer group中有多个consumer,一个topic有多个partition,所以必然会涉及到partition的分配问题,即确定那个partition由那个consumer消费的问题。

Round-Robin

主要采用轮询的方式分配所有的分区,该策略主要实现的步骤:
假设存在三个topic:t0/t1/t2,分别拥有1/2/3个分区,共有6个分区,分别为t0-0/t1-0/t1-1/t2-0/t2-1/t2-2,这里假设我们有三个Consumer,C0、C1、C2,订阅情况为C0:t0,C1:t0、t1,C2:t0/t1/t2。
此时round-robin采取的分配方式,则是按照分区的字典对分区和消费者进行排序,然后对分区进行循环遍历,遇到自己订阅的则消费,否则向下轮询下一个消费者。即按照分区轮询消费者,继而消息被消费。

在这里插入图片描述

第一次C0消费了to,则C1就要消费t1-1,C2消费t2-0
第二次,c0 c1订阅的都被消费完了,t2只能被c2消费,所有c2在消费三次。

c0t1-0
c1t1-1
c2t1-2,t2-0,t2-1,t2-2

分区在循环遍历消费者,自己被当前消费者订阅,则消息与消费者共同向下(消息被消费),否则消费者向下消息继续遍历(消息没有被消费)。轮询的方式会导致每个Consumer所承载的分区数量不一致,从而导致各个Consumer压力不均。上面的C2因为订阅的比较多,导致承受的压力也相对较大。

Range

Range的重分配策略,首先计算各个Consumer将会承载的分区数量,然后将指定数量的分区分配给该Consumer。假设存在两个Consumer,C0和C1,两个Topic,t0和t1,这两个Topic分别都有三个分区,那么总共的分区有6个,t0-0,t0-1,t0-2,t1-0,t1-1,t1-2。分配方式如下:
range按照topic一次进行分配,即消费者遍历topic,t0,含有三个分区,同时有两个订阅了该topic的消费者,将这些分区和消费者按照字典序排列。按照平均分配的方式计算每个Consumer会得到多少个分区,如果没有除尽,多出来的分区则按照字典序挨个分配给消费者。按照此方式以此分配每一个topic给订阅的消费者,最后完成topic分区的分配。
如图
在这里插入图片描述

假设消费者数量为N,主题分区数量为M,则有当前主题分配数量 = M%N==0? M/N +1 : M/N ;
个人理解就是
先进行计算求出平均数,每个消费者要消费几个,再将多个那个分给第一个消费者。
主题里边有三个分区,那么每个消费者至少消费一个,第一个要多消费一个。所以分配的时候直接分配c0消费t0-0和t0-1。
但是这种数据量过大的时候,会导致第一个消费者多消费大量信息。
缺点:容易产生数据倾斜,如果是针对少量的topic而言C0多消费一个分区的数据影响不大,但是针对成百上千个topic那么C0就要多消费成百上千的分区数。

Sticky

粘性分配器有两个目的。首先,它保证分配尽可能平衡,它有两个目的:
● 分配给消费者的topic partition个数最多相差1个;或者
● 主题分区比其他消费者少 2+ 的每个消费者无法将这些主题分区中的任何一个转移到它。
其次,当发生重新分配时,它尽可能多地保留现有分配。当主题分区从一个消费者移动到另一个消费者时,这有助于节省一些开销处理。
重新开始它可以通过将分区尽可能均匀地分布在消费者身上来工作。尽管这听起来与循环分配器的工作方式相似,但下面的第二个示例表明事实并非如此。在重新分配期间,它将以这样一种方式执行重新分配,即在新分配中

  1. 主题分区仍然尽可能均匀地分布
  2. 主题分区尽可能地保留在其先前分配的消费者中。
    当然,上面的第一个目标优先于第二个目标。
    例 1.假设有 3 个消费者C0, C1, C2, 4 个主题t0, t1, t2, t3, , 每个主题有 2 个分区,从而产生分区t0p0, t0p1, t1p0, t1p1, t2p0, t2p1, t3p0, t3p1。每个消费者都订阅了所有三个主题。具有粘性和循环分配器的分配将是:
● C0: [t0p0, t1p1, t3p0]
● C1: [t0p1, t2p0, t3p1]
● C2: [t1p0, t2p1]

现在,让我们假设C1被删除并且重新分配即将发生。
循环分配器将产生:

● C0: [t0p0, t1p0, t2p0, t3p0]
● C2: [t0p1, t1p1, t2p1, t3p1]

而粘性分配器会导致:

● C0 [t0p0, t1p1, t3p0, t2p0]
● C2 [t1p0, t2p1, t0p1, t3p1]

保留所有以前的分配(与循环分配器不同)
示例 2.有 3 个消费者C0、C1、C2和 3 个主题t0、t1、t2,分别具有 1、2 和 3 个分区。因此,分区为t0p0、t1p0、t1p1、t2p0、 t2p1、t2p2。C0已订阅t0;C1已订阅 t0, t1; 并C2订阅了t0, t1, t2。循环分配器将提出以下分配:

● C0 [t0p0]
● C1 [t1p0]
● C2 [t1p1, t2p0, t2p1, t2p2]

这不像粘性分配器建议的分配那样平衡:

● C0 [t0p0]
● C1 [t1p0, t1p1]
● C2 [t2p0, t2p1, t2p2]

现在如果消费者C0被移除,这两个分配器将产生以下分配。
循环(保留 3 个分区分配):

● C1 [t0p0, t1p1]
● C2 [t1p0, t2p0, t2p1, t2p2]

粘性(保留 5 个分区分配):

● C1 [t1p0, t1p1, t0p0]
● C2 [t2p0, t2p1, t2p2]

消费者offset存储

由于Consumer在消费过程中可能会出现断电宕机等故障,Consumer恢复以后,需要从故障前的位置继续消费,所以Consumer需要实时记录自己消费到了那个offset,以便故障恢复后继续消费。
在这里插入图片描述

Kafka0.9版本之前,consumer默认将offset保存在zookeeper中,从0.9版本之后,consumer默认将offset保存在kafka一个内置的topic中,该topic为__consumer_offsets
利用__consumer_offsets读取数据

./kafka-console-consumer.sh --topic __consumer_offsets --bootstrap-server 192.168.233.129:19092,192.168.233.129:19093,192.168.233.129:19094  --formatter "kafka.coordinator.group.GroupMetadataManager\$OffsetsMessageFormatter" --consumer.config ../config/consumer.properties --from-beginning

kafka高效读写

页缓存技术 + 磁盘顺序写

首先Kafka每次接收到数据都会往磁盘上去写,如下图所示。
在这里插入图片描述

这样设计性能是比较差的。
但是实际上Kafka在这里有极为优秀和出色的设计,就是为了保证数据写入性能,首先Kafka是基于操作系统的页缓存来实现文件写入的。
操作系统本身有一层缓存,叫做page cache,是在内存里的缓存,我们也可以称之为os cache,意思就是操作系统自己管理的缓存。
你在写入磁盘文件的时候,可以直接写入这个os cache里,也就是仅仅写入内存中,接下来由操作系统自己决定什么时候把os cache里的数据真的刷入磁盘文件中。
仅仅这一个步骤,就可以将磁盘文件写性能提升很多了,因为其实这里相当于是在写内存,不是在写磁盘。
在这里插入图片描述

接着另外一个就是kafka写数据的时候,非常关键的一点,他是以磁盘顺序写的方式来写的。也就是说,仅仅将数据追加到文件的末尾,不是在文件的随机位置来修改数据。
普通的机械磁盘如果你要是随机写的话,确实性能极差,也就是随便找到文件的某个位置来写数据。
但是如果你是追加文件末尾按照顺序的方式来写数据的话,那么这种磁盘顺序写的性能基本上可以跟写内存的性能本身也是差不多的。
Kafka在写数据的时候,一方面基于了os层面的page cache来写数据,所以性能很高,本质就是在写内存罢了。
另外一个,他是采用磁盘顺序写的方式,所以即使数据刷入磁盘的时候,性能也是极高的,也跟写内存是差不多的。
基于上面两点,kafka就实现了写入数据的超高性能。
那么大家想想,假如说kafka写入一条数据要耗费1毫秒的时间,那么是不是每秒就是可以写入1000条数据?
但是假如kafka的性能极高,写入一条数据仅仅耗费0.01毫秒呢?那么每秒是不是就可以写入10万条数?
所以要保证每秒写入几万甚至几十万条数据的核心点,就是尽最大可能提升每条数据写入的性能,这样就可以在单位时间内写入更多的数据量,提升吞吐量。

零拷贝技术

大家应该都知道,从Kafka里我们经常要消费数据,那么消费的时候实际上就是要从kafka的磁盘文件里读取某条数据然后发送给下游的消费者,如下图所示。
在这里插入图片描述

那么这里如果频繁的从磁盘读数据然后发给消费者,性能瓶颈在哪里呢
假设要是kafka什么优化都不做,就是很简单的从磁盘读数据发送给下游的消费者,那么大概过程如下所示:先看看要读的数据在不在os cache里,如果不在的话就从磁盘文件里读取数据后放入os cache。
接着从操作系统的os cache里拷贝数据到应用程序进程的缓存里,再从应用程序进程的缓存里拷贝数据到操作系统层面的Socket缓存里,最后从Socket缓存里提取数据后发送到网卡,最后发送出去给下游消费。
整个过程,如下图所示:
在这里插入图片描述

一次是从操作系统的cache里拷贝到应用进程的缓存里,接着又从应用程序缓存里拷贝回操作系统的Socket缓存里。
而且为了进行这两次拷贝,中间还发生了好几次上下文切换,一会儿是应用程序在执行,一会儿上下文切换到操作系统来执行。
所以这种方式来读取数据是比较消耗性能的。
Kafka为了解决这个问题,在读数据的时候是引入零拷贝技术。
也就是说,直接让操作系统的cache中的数据发送到网卡后传输给下游的消费者,中间跳过了两次拷贝数据的步骤,Socket缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到Socket缓存。
在这里插入图片描述

通过零拷贝技术,就不需要把os cache里的数据拷贝到应用缓存,再从应用缓存拷贝到Socket缓存了,两次拷贝都省略了,所以叫做零拷贝。
对Socket缓存仅仅就是拷贝数据的描述符过去,然后数据就直接从os cache中发送到网卡上去了,这个过程大大的提升了数据消费时读取文件数据的性能。
在从磁盘读数据的时候,会先看看os cache内存中是否有,如果有的话,其实读数据都是直接读内存的。
如果kafka集群经过良好的调优,大家会发现大量的数据都是直接写入os cache中,然后读数据的时候也是从os cache中读。
相当于是Kafka完全基于内存提供数据的写和读了,所以这个整体性能会极其的高。

Kafka中zookeeper的作用

Kafka集群中有一个broker会被选举为Controller,负责管理集群broker的上下线、所有topic的分区副本分配和leader的选举等工作。Controller的工作管理是依赖于zookeeper的。

Partition的Leader的选举过程

在这里插入图片描述

Kafka事务

kafka从0.11版本开始引入了事务支持,事务可以保证Kafka在Exactly Once语义的基础上,生产和消费可以跨分区的会话,要么全部成功,要么全部失败。

Producer事务

为了按跨分区跨会话的事务,需要引入一个全局唯一的Transaction ID,并将Producer获得的PID(可以理解为Producer ID)和Transaction ID进行绑定,这样当Producer重启之后就可以通过正在进行的Transaction ID获得原来的PID。
为了管理Transaction,Kafka引入了一个新的组件Transaction Coordinator,Producer就是通过有和Transaction Coordinator交互获得Transaction ID对应的任务状态,Transaction Coordinator还负责将事务信息写入内部的一个Topic中,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可以恢复,从而继续进行。

Consumer事务

对于Consumer而言,事务的保证相比Producer相对较弱,尤其是无法保证Commit的信息被精确消费,这是由于Consumer可以通过offset访问任意信息,而且不同的Segment File声明周期不同,同一事务的消息可能会出现重启后被删除的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值