kafka的组件讲解(持续更新)

目录

    • 前言
    • kafka定义
    • 消息队列产品
    • 传统消息队列使用场景
    • 消息队列的两种模式
    • kafka架构图
    • kafka组件
    • broker 经纪人
    • zookeeper 信息注册中心
    • controller 控制节点
    • producer 生产者
    • topic 主题
    • partition 分区
    • replication 副本
    • leader & follower 领导者和追随者
    • consumer 消费者
    • consumer group消费者组
    • offset偏移量
    • topic中的数据partition分配策略
    • kafka生产者的发送原理
    • 生产者如何提高吞吐量
    • kafka的数据检索机制
    • kafka数据的可靠性
    • acks应答参数
    • ISR机制
    • ISR的作用是什么
    • 为什么要设计ISR机制
    • 数据完全可靠性
    • 保证数据既不丢失又不重复
    • 幂等性
    • 事务

前言

环境:centos7.9
官网:https://kafka.apache.org/

kafka定义

传统定义:kafka是Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue)系统,它可以处理消费者在网站中的所有动作流数据。

最新定义:kafka是一个开源的分布式事件流平台,被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用。

发布/订阅:消息的发布者不会直接将消息发送给特定的订阅者,而是将发布的消息分为不同的类型,订阅者只接受感兴趣的消息;

消息队列产品

目前企业中比较常见的消息队列产品主要有kafka、ActiveMQ、RabbitMQ、RocketMQ等;
在大数据场景主要采用kafka作为消息队列,在JaveEE开发中主要采用ActiveMQ、RabbitMQ、RocketMQ

传统消息队列使用场景

传统消息队列使用场景包括:缓冲/消峰、解耦和异步通信。
缓冲/消峰:有助于控制和优化数据流经过系统的速度,解决生产消息与消费消息处理速度不一致的问题;
解耦:允许独立的扩展或修改两边的处理过程,只要保证他们遵循同样的接口约束。
异步通信:允许用户把一个消息放入队列,但不立即处理它,然在需要的时候再去处理他们。

消息队列的两种模式

消息队列的两种模式:点对点模式、发布/订阅模式。
点对点模式:消费者主动拉取数据,然后消费者返回收到信号给消息队列,消息队列便删除该消息。
发布/订阅模式:可以有多个topic主题(浏览、点赞、收藏、评论等),消费者消费数据之后,不删除数据,每个消费者相互独立,都可以消费到数据。

kafka架构图

kafka的组件讲解(持续更新)_第1张图片

kafka组件

kafka组件:broker、zookeeper、producer、producer、partition、replication 、leader 、follower、consumer

broker 经纪人

broker:经纪人,每个kafkaserver称为一个broker,,就是一个node,多个borker组成 KafkaCluster;一个机器上可以部署一个或者多个broker,这多个broker连接到相同的ZooKeeper就组成了kafka集群;

zookeeper 信息注册中心

zookeeper:信息/注册中心,Kafka 集群能够正常⼯作,需要依赖于 zookeeper,zookeeper 帮助 kafka存储和管理集群信息,旧版的kafka必须配合zookeeper使用,但在新版中kafka2.8.0以后已经丢弃zookeeper;

controller 控制节点

controller:集群中的一个broker作为leader身份来负责管理整个集群,如果controller挂掉,借助zookeeper重新选主。

producer 生产者

producer:生产者,就是向kafkabroker发送消息的客户端;

topic 主题

topic:主题,就是一类消息的含义,一个topic中通常放置一类消息。每个topic都有一个或者多个订阅者,也就是消费者consumer,producer将消息推送到topic,由订阅该topic的consumer从topic中拉取消息;

partition 分区

partition:分区,每个topic主题可以有多个分区分担数据的传递,多条路并行,吞吐量大;
topic中的数据被分割为一个或多个partition,每个topic至少有一个partition,当生产者产生数据的时候,根据分配策略(hash取模)选择partition分区,然后将消息追加到指定partition分区的末尾。

replication 副本

replication :副本,每个分区可以设置多个副本,副本之间数据一致。相当于备份,有备胎更可靠;
partition分区可能会损坏,所以得有副本,可以有多个副本。
副本的设置数为N,表示主+备=N个。也就是说设置topic的时候不要设置为 1个partition,1个replicas,这样相当于没有副本,因为副本数包含了分区,如果设置为 2个partition,3个replicas,就表示这个topic有2个分区,每个分区一共有3个,即1个leader,2个follower。
我们将所有的partition分区这样分,有一个leader和多个follower,leader是负责读写数据的,follower只负责备份。

leader & follower 领导者和追随者

leader & follower:领导者和追随者,也可以叫做主从,上面的这些分区的副本里有1个身份为leader,其他的为follower。leader处理partition的所有读写请求。follower副本不能读,其仅有一个功能,那就是从leader副本拉取消息,尽量让自己跟leader副本的内容一致。consumer只会从leader 中读取数据,当leader 挂掉会有新的follower重新选举为leader。follower会跟leader保持数据一致,当leader挂掉,则从followerer中选举一个作为新的leader,当follower挂掉或卡主或同步数据太慢,leader会把这个follower从“in sync replicsa ”(ISR)列表中删除重新创建一个follower。

consumer 消费者

consumer:即消费者,就是从kafkabroker获取消息的消费者;

consumer group消费者组

每个consumer属于一个特定的consumer group,将多个消费者集中到一起去处理某一个topic数据,可以更快速的提高消费能力,整个消费者组共享一组偏移量以防止数据被重复度,因为一个topic有多个分区。

offset偏移量

可以唯一的标识一条信息;topic的每一消息都会有一个自增的编号,用于标识顺序和标识消息的偏移量。
偏移量决定读取数据的位置,不会有线程安全的问题,消费者通过偏移量来决定下次读取的消息;
消息被消费之后,并不会马上删除,这样多个业务就可以重复读取kafka中的消息;
某一个偏移量可以通过修改偏移量达到重新读取消息的目的,偏移量由用户控制;
消息最终还是会被删除,默认的时间为1周(7*24小时);
kafka的存储文件都是按照offset.kafka来命名的,用offset做名字是为了方便查找,例如你想找1024的位置,只要找到1024.kafka的文件即可,默认第一个kafka储存文件为00000000000000000000.kafka.
消费者会监控数据消费到什么位置,当消费者挂掉再重新恢复的时候,可以从消费位置继续消费。

topic中的数据partition分配策略

首先这是在编程的时候设置的,编写productor时的ProducerRecord类的构造函数可以定义partition分配策略,如下:

1、指定了partition,则直接使用;
2、未指定partition但指定了key,通过对key的value进行hash选出一个partition;
3、partition和key都未指定,则通过轮询选出一个partition。

kafka生产者的发送原理

在生产者消息发送过程中,涉及到了2个线程,main线程和sender线程,在main线程中创建了一个双端队列RecordAccumulator,main线程将消息发送给RecordAccumulator,sender线程不断从RecordAccumulator拉取消息发送到kafkabroker中。
RecordAccumulator有2个重要的参数:batch.size、linger.ms.
batch.size:批次大小,表示当数据积累到batch.size设置的大小之后,sender才会取出数据发送给broker,默认batch.size是16k;
linger.ms:等待时间,表示如果数据迟迟达不到batch.size设置的大小,sender等待linger.ms设置的时间到了之后就会取数据发送,单位是ms,默认值是0ms,表示没有延时。生产中可以视情况设置为5ms-100ms.
compression.type:压缩snappy
RecordAccumulator默认的缓冲区大小为32m,可以修改为64m.

生产者如何提高吞吐量

可以调整batch.size批次大小、linger.ms等待时间、compression.type 压缩snappy、RecordAccumulator修改为64m

kafka的数据检索机制

topic是逻辑上的概念,而partition是物理上的概念,每个partition对应于一个log文件,该log文件中存储的就是producer生产的数据。Producer生产的数据会被不断追加到该log文件末端,且每条数据都有自己的offset。消费者组中的每个消费者,都会实时记录自己消费到了哪个offset,以便出错恢复时,从上次的位置继续消费。

生产者生产的消息会不断追加到log文件末尾,为防止log文件过大导致数据定位效率低下,kafka采取了分片和索引机制,将每个partition分为多个segment文件。每个segment对应两个文件:“.index文件”和".log"文件。这些文件位于一个文件夹下,该文件夹的命名规则为:topic名称+分区序号,例如,first这个topic有三个分区,则其对应的文件夹为first-0,first-1,first-2,在这目录里面都会有“.index文件”和".log"文件。

我们的,topic被划分为多个partition,partition还可以细分为segment,一个partition物理上由多个segment组成。

segment有2个参数:

log.segment.bytes:单个segment可容纳的最大数据量,默认为1G
log.segment.ms:kafka在提交一个未写满的segment之前,等待多少时间,默认为7天;

segment文件由两部分组成,分别为.index .log 文件,index文件表示索引文件,log表示数据文件;
partition全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值。
数值大小为64位,20位数据字符长度,没有则属于0填充:

第一个segment
00000000000000000000.index
00000000000000000000.log
第四个segment
00000000000000170410.index
00000000000000170410.log
第三个segment
00000000000000239430.index
00000000000000239430.log

kafka数据的可靠性

在生产者发送消息给broker之后,如何保证数据的可靠性呢,这涉及到acks应答参数的设置,如何:

At last one:消息绝不会丢,但可能会重复传输(至少一次,ack=all+分区副本大于等于2+ISR应答最小副本数大于等于2)
At most once:消息可能会丢,但绝不会重复传输(最多一次,ack=0)
Exactly once:每条消息肯定会被传输一次且仅传输一次(精确一次,需要幂等性+At last one至少一次相结合,对于一些比较重要的业务场景,如金钱相关,要保证数据既不能丢失也不能重复)

acks应答参数

首先这个acks参数,是在生产者producer客户端里设置的,

Producers向broker发送消息的时候可以选择是否需要等到broker响应:

acks=0:表示producer不需要等待来自broker是否确认消息接收成功就继续发送下一个(消息可靠性差,效率高)
acks=1:表示producer需要等待在ISR中的leader已成功收到的数据楼盘后并得到确认后再发送下一条消息(可靠性中等,效率中等)
acks=all:producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成(可靠性最高,效率最低)
acks=-1:等价于acks=all。
(在3.x版本,acks参数默认是acks=1

那么,如何选择使用哪个acks参数值?

在生产环境中acks=0很少使用;
acks=1一般用于传输普通日志,运行个别丢失数据的业务场景;
acks=all或acks=-1一般用于金钱相关的数据,即对数据可靠性要求比较高的插件。

ack参数实际上有三种常见的值可以设置,分别是:0、1 和 all。
第一种选择是把acks参数设置为0,意思就是producer只要把消息发送出去,不管那条数据有没有在leader上落到磁盘,就不等待broker回应,直接就认为这个消息发送成功了,producer就会继续发送下一个消息;
如果你采用这种设置的话,那么你必须注意的一点是,可能你发送出去的消息还在半路。结果呢,Partition Leader所在Broker就直接挂了,然后结果你的客户端还认为消息发送成功了,此时就会导致这条消息就丢失了。

第二种选择是设置 acks = 1,意思就是说只要Partition Leader接收到消息而且写入本地磁盘了,就认为成功了,不管他其他的Follower有没有同步过去这条消息了。
这种设置其实是kafka默认的设置。
但是这里有一个问题,万一Partition Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了,此时也会导致这条消息丢失,因为人家客户端已经认为发送成功了。

最后一种情况,就是设置acks=all,这个意思就是说,Partition Leader接收到消息之后,还必须要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。
如果说Partition Leader刚接收到了消息,但是结果Follower没有收到消息,此时Leader宕机了,那么客户端会感知到这个消息没发送成功,他会重试再次发送消息过去。
此时可能Partition 2的Follower变成Leader了,此时ISR列表里只有最新的这个Follower转变成的Leader了,那么只要这个新的Leader接收消息就算成功了。

acks=all 就可以代表数据一定不会丢失了吗?
当然不是,如果你的Partition只有一个副本,也就是一个Leader,任何Follower都没有,你认为acks=all有用吗?
当然没用了,因为ISR里就一个Leader,他接收完消息后宕机,也会导致数据丢失。
所以说,这个acks=all,必须跟ISR列表里至少有2个以上的副本配合使用,起码是有一个Leader和一个Follower才可以。
这样才能保证说写一条数据过去,一定是2个以上的副本都收到了才算是成功,此时任何一个副本宕机,不会导致数据丢失。

ISR机制

ISR是什么?
首先,ISR的全称叫做: In-Sync Replicas (同步副本集),我们可以理解为和leader保持同步的所有副本的集合。

一个分区的所有副本集合叫做AR( Assigned Repllicas )
与leader-replica未能保持同步的副本集叫做OSR( Out-Sync Relipcas )
因此我们就能得到这么一个表示:AR = ISR + OSR,翻译一下就是一个分区的副本集分为同步集合和非同步集合两部分。

那么我们可以假设一个场景,一个分区的AR集合为【0,1,2,3,4,5】,其中leader是0
其中【1,2,3】作为follower和leader的数据保持同步,而【4,5】未能和leader保持同步,
那么此时,ISR=【0,1,2,3】,OSR=【4,5】
如果此时副本4追上了leader,也就是和leader保持到了同步
那么此时,ISR=【0,1,2,3,4】,OSR=【5】

从上面的场景我们就可以明白,ISR动态维护了一个和leader副本保持同步副本集合,ISR中的副本全部都和leader的数据保持同步。

ISR的作用是什么

我们思考一下,我们知道了与leader保持同步的副本集后,可以做到哪些事情?
1、当我们生产消息的时候,到底要写入多少副本才能算成功呢?
2、当leader挂了之后,我们应该选择哪个follower来成为新的leader呢?
那么对应的,通过ISR,我们知晓了哪些follower与leader保持着同步,
那么我们就可以在写入消息的时候,设置写入处于ISR中所有的副本才算成功,
那么我们在进行leader切换的时候,就可以从ISR中选择对应的follower成为新的leader。
这就是ISR的作用:是通过副本机制实现消息高可靠,服务高可用时,不可缺少的一环;这也是为什么讲到副本不得不提到ISR的原因。

为什么要设计ISR机制

在一些中间件中,都有副本的概念,在不同的场景下写入数据时,要求写入副本的个数也不尽相同。
例如zk中要求写入的节点个数大于一半才算成功,或者有些要求高可靠性的场景,规定写入所有副本才能算成功。
而kafka的ISR可以允许生产消息时,根据自己的业务场景自行配置想要达到的效果:

我们在考虑生产消息时,ISR机制可以友好的让使用者根据自己的业务需求去设置参数,去选择自己想要达到什么程度的可靠性,而不是只提供一种可靠性选择。

补充:我们的ISR是动态伸缩的,可能出现follower全部都挂了,ISR中只剩下leader,那么此时设置acks=all就等价于acks=1了
这样就会对高可靠性要求的场景产生危险,那么kafka提供了参数:min.insync.replicas
这个参数可以配置最少ISR中需要多少个副本,才能继续提供写服务。如果设置为2,一旦ISR中的个数小于2,那么就不再提供写服务,牺牲一定的可用性,来保障这种高可靠的场景需求。
最后,ISR机制的存在是kafka为了平衡可靠性和可用性,不指定提供高可靠或者高可用的服务,而是将决定权交给了使用者,让使用者通过参数来控制,到底要实现什么程度的高可靠与高可用。

数据完全可靠性

上面我们讲了acks参数和ISR机制,acks=all表示,producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成(可靠性最高,效率最低),
acks=all 就可以代表数据一定不会丢失了吗?
当然不是,如果你的topic的partition为1,即只有一个副本,也就是一个leader,任何follower都没有,你认为acks=all有用吗?
当然没用了,因为ISR里就一个Leader,他接收完消息后宕机,也会导致数据丢失。
所以,要做到数据完全可靠不丢失,必须满足下面的条件:

数据完全可靠性条件=acks设置为all+分区的副本数大于等于2+ISR里应答的最小副本数量大于等于2

保证数据既不丢失又不重复

保证数据不丢失满足:数据完全可靠性条件=acks设置为all+分区的副本数大于等于2+ISR里应答的最小副本数量大于等于2,但是仍有可能broker手动重复的数据,
kafka0.11版本以后,引入了一项重大的特性,幂等性和事务。

幂等性

幂等性:指无论producer生产者发送多少次重复数据,broker只会持久化一条,保证了数据的不重复。
重复数据判端标准:具有pid,partition,seqnumber 相同主键的消息提交时,broker只会持久化一条,其中pid是kafka每次重启都会分配一个新的,partition表示分区号, sequence number是单调自增的,所以幂等性只能保证的是在单分区会话内不重复。

开启参数enable.idempotence=true,默认就是true。

事务

开启事务必须先开启幂等性。

你可能感兴趣的:(kafka,消息队列,kafka,分布式)