+ [六、关于kafka数据可靠性的保证](#kafka_203)
+ - [6.1 副本数据同步策略](#61__209)
- [6.2 ISR集合](#62_ISR_216)
- [6.3 ACK应答机制](#63_ACK_222)
- [6.4 故障处理细节](#64__238)
+ [七、关于Kafak高可用性](#Kafak_253)
+ - [7.1 Leader 选举机制](#71_Leader__255)
+ [Reference](#Reference_286)
一、前言
自上次师兄遭受了面试官 Kafka 的暴击追问后,回来发奋图强,企图“吊打面试官”,奈何还是面试官套路深啊,最近的面试,又被问到知识盲点了!让我们一起来看看,可怜的师兄又遇到了哪些让人头秃的问题 {{{(>_<)}}} !
二、面试题
- 关于消息队列(基础)
常用的消息队列有哪些 ?
为何使用消息队列 ?
Kafka与传统的消息队列服务有什么不同?
- 关于Kafak存储机制与读写流程
Kafka的读写流程
Kafka的文件结构 broker存储数据有哪些?
Kafka怎么保证partition的偏移量?
follower参加读写吗? Kafka为什么只让leader进行读写?如果让follower也可以读写,会怎么样?
- 关于Kafak数据可靠性的保证
Kafak是怎么实现对offset的索引
ack设为1的时候,producer生产数据时候,leader接受到数据,返回ack之后,leader宕机了,那么数据是否就丢失了?
ack配置成-1是不是数据一定会进磁盘?是不是不管怎么是设置ack还是有概率丢失消息?
- 关于Kafak高可用性
简要描述Kafak数据高可用的原理是什么
一个topic三个broker一个leader,leader所在的broker挂了,选举原则是什么?
Kafka api low-level与high-level有什么区别,使用low-level api需要处理哪些细节?
以上,便是和师兄聊到了一些他踩坑的面试题和一些同类型的面试题,我进行了整理。说实话,如果不深入的了解Kafak,我想小伙伴们在面试时多半是要踩雷的,当然也包括我!(ノへ ̄、) 所以,为了避免被面试官疯狂吊打,我们还做好充分准备,不求”翻身做主“,但求旗鼓相当,那样Offer轻松到手岂不妙哉!
三、我的回答思路
还是和上一篇博客一样 师兄大厂面试遇到面试官的 Kafka 暴击三连问,快面哭了!,我个人建议,大家最好先搭建一个技术栈完整的知识框架,这样在面试时就能做到无懈可击啦!下面几篇基础博客,我想会对大家有所帮助 ! 🚢
Kafka |
---|
【Kafka】(一)kafka 简介与设计、实现分析 |
【Kafka】(十)Kafka 如何实现高吞吐量 |
【Kafka】(十一)Kafka 的备份机制 |
【Kafka】(十三)broker 副本与 ISR 设计 |
【Kafka】(十四)Kafka 架构深入 |
四、关于消息队列
4.1 Kafka创建背景
Kafka是一个消息系统,原本开发自LinkedIn,用作LinkedIn的活动流(Activity Stream)和运营数据处理管道(Pipeline)的基础。现在它已被多家不同类型的公司作为多种类型的数据管道和消息系统使用。
活动流数据是几乎所有站点在对其网站使用情况做报表时都要用到的数据中最常规的部分。这种数据通常的处理方式是先把各种活动以日志的形式写入某种文件,然后周期性地对这些文件进行统计分析。近年来,活动和运营数据处理已经成为了网站软件产品特性中一个至关重要的组成部分,这就需要一套稍微更加复杂的基础设施对其提供支持,Kafka也就应运而生。
4.2 为何使用消息队列
- 解耦
在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。 - 冗余
有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的“插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。 - 扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。 - 灵活性 & 峰值处理能力
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。 - 可恢复性
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。 - 顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。Kafka保证一个Partition内的消息的有序性。 - 缓冲
在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行———写入队列的处理会尽可能的快速。该缓冲有助于控制和优化数据流经过系统的速度。 - 异步通信
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
4.3 和常用消息队列的对比
- RabbitMQ
RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正因如此,它非常重量级,更适合于企业级的开发。同时实现了Broker构架,这意味着消息在发送给客户端时先在中心队列排队。对路由,负载均衡或者数据持久化都有很好的支持。 - Redis
Redis是一个基于Key-Value对的NoSQL数据库,开发维护很活跃。虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于Redis。 - ZeroMQ
ZeroMQ号称最快的消息队列系统,尤其针对大吞吐量的需求场景。ZMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架,技术上的复杂度是对这MQ能够应用成功的挑战。ZeroMQ具有一个独特的非中间件的模式,你不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演这个服务器角色。你只需要简单的引用ZeroMQ程序库,可以使用NuGet安装,然后你就可以愉快的在应用程序之间发送消息了。但是ZeroMQ仅提供非持久性的队列,也就是说如果宕机,数据将会丢失。其中,Twitter的Storm 0.9.0以前的版本中默认使用ZeroMQ作为数据流的传输(Storm从0.9版本开始同时支持ZeroMQ和Netty作为传输模块)。 - ActiveMQ
ActiveMQ是Apache下的一个子项目。 类似于ZeroMQ,它能够以代理人和点对点的技术实现队列。同时类似于RabbitMQ,它少量代码就可以高效地实现高级应用场景。 - Kafka/Jafka
Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,而Jafka是在Kafka之上孵化而来的,即Kafka的一个升级版。具有以下特性:快速持久化,可以在O(1)的系统开销下进行消息持久化;高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡;支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。
4.4 总结
关于消息队列更深入的一些知识,大家可以看这里------关于消息队列的使用 。关于 Kafka 和传统消息队列有何不同,在上一篇博客中已经做出解答,这里我就不再赘述。一般情况下,Kafka应用在大数据日志处理或对实时性(少量延迟),可靠性(少量丢数据)要求稍低的场景使用。
五、关于Kafka存储机制与读写流程
5.1 Kafka存储机制
在Kafka 架构深入已经讲明了这个问题,但这张图的结构更易于理解,如下。
- Broker:消息中间件处理结点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群。
- Topic:一类消息,例如page view日志、click日志等都可以以topic的形式存在,Kafka集群能够同时负责多个topic的分发。
- Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列。
- Segment:partition物理上由多个segment组成。
Kafka用topic对消息进行归类,每一个topic可以分为多个分区,分区中的消息不重复,每个分区又有很多个segment(段),segment是在磁盘上就是一对文件,包含index和log文件,两种文件名相同,后缀不同。
每个topic的第一个segment的两种文件都是00000000000000000000.index和00000000000000000000.log,后来新产生的文件名都以上一个segment中最后一条消息的offset(偏移量)结尾,不足20个字符的用0填充。
Tip:Kafka数据被消费后虽然不会被立即删除,但不可能一直不删除,Kafka根据两个设置定时检测做删除操作:
- 基于时间:log.retention.hours=168
- 基于大小:log.retention.bytes=1073741824
满足任何一个都会删除之前的segment,记住不是删除某一个消息,删除的最小单位是segment。
以上面的Segment文件为例,展示出Segment:00000000000000170410的index文件和log文件的对应的关系,如下图:
如上图,index索引文件存储大量的元数据,log数据文件存储大量的消息,索引文件中的元数据指向对应数据文件中message的物理偏移地址。
- 如何根据索引文件元数据定位数据位置?
如:index索引文件元数据[3,348],在log数据文件中表示第3个消息,在全局partition中表示170410+3=170413个消息,该条消息在相应log文件中的物理偏移地址为348。- 那么如何从partition中通过offset查找message呢?
如:读取offset=170418的消息,查找segment文件,其中,
α. 00000000000000000000.index为最开始的文件,
β. 00000000000000170410.index(start offset=170410+1=170411),
γ. 00000000000000239430.index(start offset=239430+1=239431),
因此,定位offset=170418在00000000000000170410.index索引文件中。其他后续文件可以依次类推,以偏移量命名并排列这些文件,然后根据二分查找法就可以快速定位到具体文件位置。其次,根据00000000000000170410.index文件中的[8,1325]定位到00000000000000170410.log文件中的1325的位置进行读取。- 那么怎么知道何时读完本条消息,否则就读到下一条消息的内容了?
因为消息都具有固定的物理结构,包括:offset(8 Bytes)、消息体的大小(4 Bytes)、crc32(4 Bytes)、magic(1 Byte)、attributes(1 Byte)、key length(4 Bytes)、key(K Bytes)、payload(N Bytes)等等字段,可以确定一条消息的大小,即读取到哪里截止。
5.2 读写流程
写流程:
1.连接ZK集群,从ZK中拿到对应topic的partition信息和partition的Leader的相关信息
2.连接到对应Leader对应的broker
3.将消息发送到partition的Leader上
4.其他Follower从Leader上复制数据
5.依次返回ACK
6.直到所有ISR中的数据写完成,才完成提交,整个写过程结束
因为是描述写流程,没有将replica与ZK的心跳通讯表达出来,心跳通讯就是为了保证kafka高可用。一旦Leader挂了,或者Follower同步超时或者同步过慢,都会通过心跳将信息报告给ZK,由ZK做Leader选举或者将Follower从ISR中移动到OSR中。
读流程:
1.连接ZK集群,从ZK中拿到对应topic的partition信息和partition的Leader的相关信息
2.连接到对应Leader对应的broker
3.consumer将自己保存的offset发送给Leader
4.Leader根据offset等信息定位到segment(索引文件和日志文件)
5.根据索引文件中的内容,定位到日志文件中该偏移量对应的开始位置读取相应长度的数据并返回给consumer
5.3 Kafka数据一致性
数据一致性:Kafka是保存副本 leader读写,follower只备份;而 zookeeper是 leader读写,follower负责读 。
看到一位博主对 Kafka和Zookeeper 数据一致性 分析的很详细,大家可以学习下,这里我参考了关于Kafka的部分。
Kafka,只有leader 负责读写,follower只负责备份!!!,如果leader宕机的话,Kafaka动态维护了一个同步状态的副本的集合(a set of in-sync replicas),简称ISR,ISR中有f+1个节点,就可以允许在f个节点down掉的情况下不会丢失消息并正常提供服。ISR的成员是动态的,如果一个节点被淘汰了,当它重新达到“同步中”的状态时,他可以重新加入ISR。因此如果leader宕了,直接从ISR中选择一个follower就行。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-kU0Bp99Y-1714333317531)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!