kafka核心概念介绍
Posted 不吃青椒!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kafka核心概念介绍相关的知识,希望对你有一定的参考价值。
一、认知流式处理平台kafka
二、核心概念认知
-
Broker
- Kafka的服务端程序,可以认为一个mq节点就是一个broker
- broker存储topic的数据
-
Producer生产者
- 创建消息Message,然后发布到MQ中
- 该角色将消息发布到Kafka的topic中
-
Consumer消费者:
- 消费队列里面的消息
-
ConsumerGroup消费者组
-
同个topic, 广播发送给不同的group,一个group中只有一个consumer可以消费此消息
-
Topic
-
每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic,主题的意思
-
Partition分区
- kafka数据存储的基本单元,topic中的数据分割为一个或多个partition,每个topic至少有一个partition,是有序的
- 一个Topic的多个partitions, 被分布在kafka集群中的多个server上
- 消费者数量 <=小于或者等于Partition数量
-
Replication 副本(备胎)
- 同个Partition会有多个副本replication ,多个副本的数据是一样的,当其他broker挂掉后,系统可以主动用副本提供服务
- 默认每个topic的副本都是1(默认是没有副本,节省资源),也可以在创建topic的时候指定
- 如果当前kafka集群只有3个broker节点,则replication-factor最大就是3了,如果创建副本为4,则会报错
-
ReplicationLeader、ReplicationFollower
- Partition有多个副本,但只有一个replicationLeader负责该Partition和生产者消费者交互
- ReplicationFollower只是做一个备份,从replicationLeader进行同步
-
ReplicationManager
- 负责Broker所有分区副本信息,Replication 副本状态切换
-
offset
- 每个consumer实例需要为他消费的partition维护一个记录自己消费到哪里的偏移offset
- kafka把offset保存在消费端的消费者组里
三、特点总结
-
特点总结
-
多订阅者小滴课堂首页
- 一个topic可以有一个或者多个订阅者
- 每个订阅者都要有一个partition,所以订阅者数量要少于等于partition数量
-
高吞吐量、低延迟: 每秒可以处理几十万条消息
-
高并发:几千个客户端同时读写
-
容错性:多副本、多分区,允许集群中节点失败,如果副本数据量为n,则可以n-1个节点失败
-
扩展性强:支持热扩展
-
-
基于消费者组可以实现:
- 基于队列的模型:所有消费者都在同一消费者组里,每条消息只会被一个消费者处理
- 基于发布订阅模型:消费者属于不同的消费者组,假如每个消费者都有自己的消费者组,这样kafka消息就能广播到所有消费者实例上
四、Kafka点对点模型和发布订阅模型讲解
-
JMS规范目前支持两种消息模型
-
点对点(point to point)
- 消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息
- 消息被消费以后,queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。 Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费
-
发布/订阅(publish/subscribe)
- 消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。
- 和点对点方式不同,发布到topic的消息会被所有订阅者消费。
-
五、数据存储流程和log讲解
Partition
-
topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列
-
是以文件夹的形式存储在具体Broker本机上
LEO(LogEndOffset)
-
表示每个partition的log最后一条Message的位置。
-
HW(HighWatermark)
- 表示partition各个replicas数据间同步且一致的offset位置,即表示allreplicas已经commit的位置
- HW之前的数据才是Commit后的,对消费者才可见
- ISR集合里面最小LEO
-
offset:
- 每个partition都由一系列有序的、不可变的消息组成,这些消息被连续的追加到partition中
- partition中的每个消息都有一个连续的序列号叫做offset,用于partition唯一标识一条消息
- 可以认为offset是partition中Message的id
-
Segment:每个partition又由多个segment file组成;
- segment file 由2部分组成,分别为index file和data file(log file),
- 两个文件是一一对应的,后缀”.index”和”.log”分别表示索引文件和数据文件
- 命名规则:partition的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset+1
六、面试必备高级篇-kafka数据文件存储-可靠性保证-ISR核心知识讲解
- Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。
- 通过索引信息可以快速定位message
- producer生产数据,要写入到log文件中,写的过程中一直追加到文件末尾,为顺序写,官网数据表明。同样的磁盘,顺序写能到600M/S,而随机写只有100K/S
- Kafka 采取了分片和索引机制,将每个partition分为多个segment,每个segment对应2个文件 log 和 index
index文件中并没有为每一条message建立索引,采用了稀疏存储的方式每隔一定字节的数据建立一条索引,避免了索引文件占用过多的空间和资源,从而可以将索引文件保留到内存中缺点是没有建立索引的数据在查询的过程中需要小范围内的顺序扫描操作。
- 配置文件 server.properties
# The maximum size of a log segment file. When this size is reached a new log segment will be created. 默认是1G,当log数据文件大于1g后,会创建一个新的log文件(即segment,包括index和log)log.segment.bytes=1073741824
#分段一00000000000000000000.index 00000000000000000000.log#分段二 数字 1234指的是当前文件的最小偏移量offset,即上个文件的最后一个消息的offset+100000000000000001234.index 00000000000000001234.log#分段三00000000000000088888.index 00000000000000088888.log
Kafka数据可靠性保证原理之副本机制Replica
-
背景
- Kafka之间副本数据同步是怎样的?一致性怎么保证,数据怎样保证不丢失呢
-
kafka的副本(replica)
- topic可以设置有N个副本, 副本数最好要小于broker的数量
- 每个分区有1个leader和0到多个follower,我们把多个replica分为Learder replica和follower replica
-
生产者发送数据流程
- 保证producer 发送到指定的 topic, topic 的每个 partition 收到producer 发送的数据后
- 需要向 producer 发送 ack 确认收到,如果producer 收到 ack, 就会进行下一轮的发送否则重新发送数据
-
副本数据同步机制
- 当producer在向partition中写数据时,根据ack机制,默认ack=1,只会向leader中写入数据
- 然后leader中的数据会复制到其他的replica中,follower会周期性的从leader中pull数据,
- 对于数据的读写操作都在leader replica中,follower副本只是当leader副本挂了后才重新选取leader,,,,follower并不向外提供服务,假如还没同步完成,leader副本就宕机了,怎么办?
-
问题点:Partition什么时间发送ack确认机制(要追求高吞吐量,那么就要放弃可靠性)
-
当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别
-
副本数据同步策略 , ack有3个可选值,分别是0, 1,all。
-
ack=0
- producer发送一次就不再发送了,不管是否发送成功
- 发送出去的消息还在半路,或者还没写入磁盘, Partition Leader所在Broker就直接挂了,客户端认为消息发送成功了,此时就会导致这条消息就丢失
-
ack=1(默认)
- 只要Partition Leader接收到消息而且写入【本地磁盘】,就认为成功了,不管他其他的Follower有没有同步过去这条消息了
- 问题:万一Partition Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了
-
ack= all(即-1)
- producer只有收到分区内所有副本的成功写入全部落盘的通知才认为推送消息成功
-
备注:leader会维持一个与其保持同步的replica集合,该集合就是ISR,leader副本也在isr里面
-
问题一:如果在follower同步完成后,broker发送ack之前,leader发生故障,那么会造成数据重复
- 数据发送到leader后 ,部分ISR的副本同步,leader此时挂掉。比如follower1和follower2都有可能变成新的leader, producer端会得到返回异常,producer端会重新发送数据,数据可能会重复
-
问题二:acks=all 就可以代表数据一定不会丢失了吗
- Partition只有一个副本,也就是一个Leader,任何Follower都没有
- 接收完消息后宕机,也会导致数据丢失,acks=all,必须跟ISR列表里至少有2个以上的副本配合使用
- 在设置request.required.acks=-1的同时,也要min.insync.replicas这个参数设定 ISR中的最小副本数是多少,默认值为1,改为 >=2,如果ISR中的副本数少于min.insync.replicas配置的数量时,客户端会返回异常
-
-
Kafka数据可靠性保证原理之ISR机制讲解
-
什么是ISR (in-sync replica set )
- leader会维持一个与其保持同步的replica集合,该集合就是ISR,每一个leader partition都有一个ISR,leader动态维护, 要保证kafka不丢失message,就要保证ISR这组集合存活(至少有一个存活),并且消息commit成功
- Partition leader 保持同步的 Partition Follower 集合, 当 ISR 中的Partition Follower 完成数据的同步之后,就会给 leader 发送 ack
- 如果Partition follower长时间(replica.lag.time.max.ms) 未向leader同步数据,则该Partition Follower将被踢出ISR
- Partition Leader 发生故障之后,就会从 ISR 中选举新的 Partition Leader。
-
OSR (out-of-sync-replica set)
-
与leader副本分区 同步滞后过多的副本集合
-
AR(Assign Replicas)
-
分区中所有副本统称为AR
Kafka的HighWatermark的作用你知道多少
-
背景 broker故障后
- ACK保障了【生产者】的投递可靠性
- partition的多副本保障了【消息存储】的可靠性
- hw的作用是啥?
- 备注:重复消费问题需要消费者自己处理
-
HW作用:保证消费数据的一致性和副本数据的一致性
假设没有HW,消费者消费leader到15,下面消费者应该消费16。
此时leader挂掉,选下面某个follower为leader,此时消费者找新leader消费数据,发现新Leader没有16数据,报错。
HW(High Watermark)是所有副本中最小的LEO。
-
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自己不会截掉),然后从新的leader同步数据
-
七、生产者发送到Broker分区策略和常见配置讲解
-
生产者发送到broker里面的流程是怎样的呢,一个 topic 有多个 partition分区,每个分区又有多个副本
-
如果指定Partition ID,则PR被发送至指定Partition (ProducerRecord)
-
如果未指定Partition ID,但指定了Key, PR会按照hash(key)发送至对应Partition
-
如果未指定Partition ID也没指定Key,PR会按照默认 round-robin轮训模式发送到每个Partition
- 消费者消费partition分区默认是range模式
-
如果同时指定了Partition ID和Key, PR只会发送到指定的Partition (Key不起作用,代码逻辑决定)
-
注意:Partition有多个副本,但只有一个replicationLeader负责该Partition和生产者消费者交互
-
面试-分区策略ProducerRecord
ProducerRecord(简称PR)
- 发送给Kafka Broker的key/value 值对, 封装基础数据信息
-- Topic (名字)-- PartitionID (可选)-- Key(可选)-- Value
key默认是null,大多数应用程序会用到key
-
如果key为空,kafka使用默认的partitioner,使用RoundRobin算法将消息均衡地分布在各个partition上
-
如果key不为空,kafka使用自己实现的hash方法对key进行散列,决定消息该被写到Topic的哪个partition,拥有相同key的消息会被写到同一个partition,实现顺序消息
-
顺序消息######
-
生产者到broker发送流程
- Kafka的客户端发送数据到服务器,不是来一条就发一条,会经过内存缓冲区(默认是16KB),通过KafkaProducer发送出去的消息都是先进入到客户端本地的内存缓冲里,然后把很多消息收集到的Batch里面,再一次性发送到Broker上去的,这样性能才可能题高
-
生产者常见配置
#kafka地址,即broker地址bootstrap.servers#当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别,分别是0, 1,all。acks#请求失败,生产者会自动重试,指定是0次,如果启用重试,则会有重复消息的可能性retries#每个分区未发送消息总字节大小,单位:字节,超过设置的值就会提交数据到服务端,默认值是16KBbatch.size# 默认值就是0,消息是立刻发送的,即便batch.size缓冲空间还没有满,如果想减少请求的数量,可以设置 linger.ms 大于#0,即消息在缓冲区保留的时间,超过设置的值就会被提交到服务端# 通俗解释是,本该早就发出去的消息被迫至少等待了linger.ms时间,相对于这时间内积累了更多消息,批量发送 减少请求#如果batch被填满或者linger.ms达到上限,满足其中一个就会被发送linger.ms# buffer.memory的用来约束Kafka Producer能够使用的内存缓冲的大小的,默认值32MB。# 如果buffer.memory设置的太小,可能导致消息快速的写入内存缓冲里,但Sender线程来不及把消息发送到Kafka服务器# 会造成内存缓冲很快就被写满,而一旦被写满,就会阻塞用户线程,不让继续往Kafka写消息了# buffer.memory要大于batch.size,否则会报申请内存不足的错误,不要超过物理内存,根据实际情况调整buffer.memory# key的序列化器,将用户提供的 key和value对象ProducerRecord 进行序列化处理,key.serializer必须被设置,即使#消息中没有指定key,序列化器必须是一个实现org.apache.kafka.common.serialization.Serializer接口的类,将#key序列化成字节数组。key.serializer value.serializer
八、【面试】Consumer消费者机制和分区策略
-
思路:从面试题角度去讲解原理流程,大家更好接收
-
消费者根据什么模式从broker获取数据的?
-
为什么是pull模式,而不是broker主动push?
-
消费者采用 pull 拉取方式,从broker的partition获取数据
-
pull 模式则可以根据 consumer 的消费能力进行自己调整,不同的消费者性能不一样
- 如果broker没有数据,consumer可以配置 timeout 时间,阻塞等待一段时间之后再返回
-
如果是broker主动push,优点是可以快速处理消息,但是容易造成消费者处理不过来,消息堆积和延迟。
-
-
-
消费者从哪个分区进行消费?
-
一个 topic 有多个 partition,一个消费者组里面有多个消费者,那是怎么分配过
- 一个主题topic可以有多个消费者,因为里面有多个partition分区 ( leader分区)
- 一个partition leader可以由一个消费者组中的一个消费者进行消费
- 一个 topic 有多个 partition,所以有多个partition leader,给多个消费者消费,那分配策略如何?
-
消费者从哪个分区进行消费?两个策略
- 顶层接口
- org.apache.kafka.clients.consumer.internals.AbstractPartitionAssignor
-
round-robin (RoundRobinAssignor非默认策略)轮训
-
【按照消费者组】进行轮训分配,同个消费者组监听不同主题也一样,是把所有的 partition 和所有的 consumer 都列出来, 所以消费者组里面订阅的主题是一样的才行,主题不一样则会出现分配不均问题,例如7个分区,同组内2个消费者
-
topic-p0/topic-p1/topic-p2/topic-p3/topic-p4/topic-p5/topic-p6
-
c-1: topic-p0/topic-p2/topic-p4/topic-p6
-
c-2:topic-p1/topic-p3/topic-p5
-
弊端
- 如果同一消费者组内,所订阅的消息是不相同的,在执行分区分配的时候不是轮询分配,可能会导致分区分配的不均匀
- 有3个消费者C0、C1和C2,他们共订阅了 3 个主题:t0、t1 和 t2
- t0有1个分区(p0),t1有2个分区(p0、p1),t2有3个分区(p0、p1、p2))
- 消费者C0订阅的是主题t0,消费者C1订阅的是主题t0和t1,消费者C2订阅的是主题t0、t1和t2
-
-
range (RangeAssignor默认策略)范围
-
【按照主题】进行分配,如果不平均分配,则第一个消费者会分配比较多分区, 一个消费者监听不同主题也不影响,例如7个分区,同组内2个消费者
-
topic-p0/topic-p1/topic-p2/topic-p3/topic-p4/topic-p5//topic-p6
-
c-1: topic-p0/topic-p1/topic-p2/topic-p3
-
c-2:topic-p4/topic-p5/topic-p6
-
弊端
- 只是针对 1 个 topic 而言,c-1多消费一个分区影响不大
- 如果有 N 多个 topic,那么针对每个 topic,消费者 C-1 都将多消费 1 个分区,topic越多则消费的分区也越多,则性能有所下降
-
九、高可用 面试】Kafka的中的日志数据清理你知道多少
-
Kafka将数据持久化到了硬盘上,为了控制磁盘容量,需要对过去的消息进行清理
-
问题:如果让你去设计这个日志删除策略,你会怎么设计?【原理思想】很重要的体现,下面是kafka答案
- 内部有个定时任务检测删除日志,默认是5分钟 log.retention.check.interval.ms
- 支持配置策略对数据清理
- 根据segment单位进行定期清理
-
启用cleaner
- log.cleaner.enable=true
- log.cleaner.threads = 2 (清理线程数配置)
-
日志删除
- log.cleanup.policy=delete
#清理超过指定时间的消息,默认是168小时,7天,#还有log.retention.ms, log.retention.minutes, log.retention.hours,优先级高到低log.retention.hours=168#超过指定大小后,删除旧的消息,下面是1G的字节数,-1就是没限制log.retention.bytes=1073741824还有基于日志起始位移(log start offset),未来社区还有更多
- 基于【时间删除】 日志说明
配置了7天后删除,那7天如何确定呢?每个日志段文件都维护一个最大时间戳字段,每次日志段写入新的消息时,都会更新该字段一个日志段segment写满了被切分之后,就不再接收任何新的消息,最大时间戳字段的值也将保持不变kafka通过将当前时间与该最大时间戳字段进行比较,从而来判定是否过期
- 基于【大小超过阈值】 删除日志 说明
假设日志段大小是500MB,当前分区共有4个日志段文件,大小分别是500MB,500MB,500MB和10MB10MB那个文件就是active日志段。此时该分区总的日志大小是3*500MB+10MB=1500MB+10MB如果阈值设置为1500MB,那么超出阈值的部分就是10MB,小于日志段大小500MB,故Kafka不会执行任何删除操作,即使总大小已经超过了阈值;如果阈值设置为1000MB,那么超过阈值的部分就是500MB+10MB > 500MB,此时Kafka会删除最老的那个日志段文件注意:超过阈值的部分必须要大于一个日志段的大小
log.retention.bytes和log.retention.minutes任意一个达到要求,都会执行删除
-
日志压缩
- log.cleanup.policy=compact 启用压缩策略
- 按照消息key进行整理,有相同key不同value值,只保留最后一个
十、【面试重点】Kafka的高性能原理分析-ZeroCopy
零拷贝ZeroCopy(SendFile)
-
例子:将一个File读取并发送出去(Linux有两个上下文,内核态,用户态)
-
File文件的经历了4次copy
- 调用read,将文件拷贝到了kernel内核态
- CPU控制 kernel态的数据copy到用户态
- 调用write时,user态下的内容会copy到内核态的socket的buffer中
- 最后将内核态socket buffer的数据copy到网卡设备中传送
-
缺点:增加了上下文切换、浪费了2次无效拷贝(即步骤2和3)
-
-
ZeroCopy:
-
请求kernel直接把disk的data传输给socket,而不是通过应用程序传输。Zero copy大大提高了应用程序的性能,减少不必要的内核缓冲区跟用户缓冲区间的拷贝,从而减少CPU的开销和减少了kernel和user模式的上下文切换,达到性能的提升
-
对应零拷贝技术有mmap及sendfile
- mmap:小文件传输快
- sendfile:大文件传输比mmap快
-
应用:Kafka、Netty、RocketMQ等都采用了零拷贝技术
-
十一、 【重点】Kafka的高性能原理分析归纳总结
kafka高性能
-
存储模型,topic多分区,每个分区多segment段
-
index索引文件查找,利用分段和稀疏索引
-
磁盘顺序写入
-
异步操作少阻塞sender和main线程,批量操作(batch)
-
页缓存Page cache,没利用JVM内存,因为容易GC影响性能
-
零拷贝ZeroCopy(SendFile)
版权注意:一切思路、来源 均来源小滴课堂
以上是关于kafka核心概念介绍的主要内容,如果未能解决你的问题,请参考以下文章