消息队列模型
消息队列模型通常有两种:
- 点对点模式:也就是消息只能被一个消费者消费,消费完后消息删除
- 发布订阅模式:相当于广播模式,消息可以被所有消费者消费
kafka通过Consumer Group对消费者分组,同时支持了这两个模型。
如果说所有消费者都属于一个Group,消息只能被同一个Group内的一个消费者消费,那就是点对点模式。如果每个消费者都是一个单独的Group,那么就是发布订阅模式。
三大特点:
1.高吞吐量:可以满足每秒百万级别消息的生产和消费。
2.持久性:有一套完善的消息存储机制,确保数据高效安全且持久化。
3.分布式:基于分布式的扩展;Kafka的数据都会复制到几台服务器上,当某台故障失效时,生产者和消费者转而使用其它的Kafka。
kafka整体架构图offset:偏移量,分区中的每一条消息都会根据时间先后顺序有一个递增的序号,这个序号就是offset偏移量
Producer:生产者,即消息生产方。
Consumer:消费者,即消息的消费方。
Consumer Group:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,主要是为了提高kafka的吞吐量!
KafkaCluster:Kafka集群,通常由多个Broker组成,每个Broker即是一个kafka实例,由于Kafka本身容错需要依赖于Zookeeper的选举算法,因此Broker通常至少需要三个。
Topic:即当前消息的主题,消息的生产方和消费方约定好的一个消费标识,从而避免错误消费。对于每个topic,会在不同的broker上保存备份,避免因为某个实例挂掉而损失所有的消息。每个topic都会以/brokers/topics/[topic_name]的形式记录在Zookeeper
Partition:分区是通过对Topic进行划分得到,这样使得一个消费者组内的多个消费者可以并行消费,从而增大吞吐量。每个分区是一个有序的,不可变的消息序列,新的消息不断追加到这个日志上。并且分区会给每个消息记录分配一个顺序ID号 – 偏移量, 从而唯一地标识该分区中的每个记录。
Zookeeper:分布式集群的管理中心,用来实时检测kafka整个集群的状态。(近来kafka已经要开始抛弃Zk了。)kafka借助于Zk的选举方法主要如下:
kafka特点 分区选择方式Kakfa Broker Leader的选举:Kakfa Broker集群受Zookeeper管理。所有的Broker节点一起去Zookeeper上注册一个临时节点,因为只有一个Kafka Broker会注册成功,其他的都会失败,所以这个成功注册的临时节点会成为Kafka Broker Controller,其他的Kafka broker叫Kafka Broker follower。(这个过程叫Controller在ZooKeeper注册Watch)。
Controller会监听其他的Kafka Broker的所有信息,如果这个kafka broker controller宕机了,在zookeeper上的临时节点会消失,此时所有的kafka broker又会一起去Zookeeper上注册一个临时节点。
一旦有一个broker宕机了,这个kafka broker controller会读取该宕机broker上所有的partition在zookeeper上的状态,并选取ISR列表中的一个replica作为partition leader(如果该partition的所有的replica都宕机了,则将新的leader设置为-1,等待ISR中的任一个Replica“活”过来,并且选它作为Leader;或选择第一个“活”过来的Replica(不一定是ISR中的)作为Leader),这个broker宕机的事情,kafka controller也会通知zookeeper,zookeeper就会通知其他的kafka broker。
- 轮询,按照顺序消息依次发送到不同的分区
- 随机,随机发送到某个分区
如果消息指定key,会根据消息的key进行hash,然后对partition分区数量取模,决定落在哪个分区上,所以,对于相同key的消息来说,总是会发送到同一个分区上,也是我们常说的消息分区有序性。
kafka应答机制kafka本身实现了一套应答机制,用于保证相应的信息内容不丢失,在生产者向队列写入数据的时候可以设置参数来确定是否确认kafka接收到数据,这个参数可设置的值为0、1、all。
ack = 0 :意味着当前的生产者只要发送消息了,即可进行下一条消息的发送。
ack = 1 :意味着需要等待对应Leader发送确认数据保存下来的ack后,才可以进行下一条消息的发送。
ack = -1 / all :则意味着等待所有ISR列表中的follower返回结果后,再返回ack。
磁盘顺序写入ISR:ISR是Broker维护的一个“可靠的follower列表”,in-sync Replica列表,broker的配置包含一个参数:min.insync.replicas。
该参数表示ISR中最少的副本数。如果不设置该值,ISR中的follower列表可能为空。此时相当于acks=1。
*** 作系统每次从磁盘读写数据的时候,需要先寻址,再进行数据读写,如果是机械硬盘,寻址就需要较长的时间。
kafka的设计中,数据其实是存储在磁盘上面,一般来说,会把数据存储在内存上面性能才会好。但kafka用的是顺序写,追加数据是追加到末尾,磁盘顺序写的性能极高,在磁盘个数一定,转数达到一定的情况下,基本和内存速度一致
零拷贝一般数据写入的大致流程为生产者生产数据,发送到kafka集群后,由kafka写入到内存中,并按照一定的时间间隔同步到磁盘中,而在消费的时候需要逐层从磁盘、内存和kafka、socket cache中进行相应的数据拷贝,并最终提供给消费者消费。
kafka为了加快速度,利用了Linux的sendFile技术(NIO),省去了进程切换和一次数据拷贝,让性能变得更好。
Kafka消息丢失kafka可能的消息丢失主要有三种情况:Broker丢失、Producer丢失、Consumer丢失。
Broker丢失broker丢失主要是由于kafka本身的机制引起的,主要的原因是,kafka为了更高的并发效率,会将部分的数据存储在内存中,按照一定的时间间隔进行批量刷盘。因此如果在保存期间,服务实例挂了,那么相应的数据信息就会丢失。
这种情况本身也是由于linux保存机制导致的。将数据存储到linux中时,会先存储到页缓存(Page cache)中,按照时间或者其他条件进行刷盘(从page cache到file),或者通过fsync命令强制刷盘。
刷盘的具体条件有三个:
- 主动调用sync或fsync函数
- 可用内存低于阀值
- dirty data时间达到阀值。dirty是pagecache的一个标识位,当有数据写入到pageCache时,pagecache被标注为dirty,数据刷盘以后,dirty标志清除。
理论上,要让单个broker完全不丢失数据是无法实现的。只能通过调整刷盘的时间减少丢失的可能性。为了解决该问题,kafka通过producer和broker协同处理单个broker丢失参数的情况。一旦producer发现broker消息丢失,即可自动进行retry。除非retry次数超过阀值(可配置),消息才会丢失。此时需要生产者客户端手动处理该情况。而具体的实现机制就是借助kafka的应答机制。
Producer丢失Producer丢失消息,发生在生产者客户端。为了提升效率,减少IO,producer在发送数据时可以将多个请求进行合并后发送。被合并的请求缓存在本地buffer中,以便producer可以将请求打包成“块”或者按照时间间隔,将buffer中的数据发出。通过buffer我们可以将生产者改造为异步的方式,这可以提升发送效率。
但是,一旦producer被非法的停止了,那么buffer中的数据将丢失,broker将无法收到该部分数据。
或者,当Producer客户端内存不够时,如果采取的策略是丢弃消息(另一种策略是block阻塞),消息也会被丢失。
解决思路:
- 异步改为同步。或者service产生消息时,使用阻塞的线程池,并且线程数有一定上限。整体思路是控制消息产生速度。
- 扩大Buffer的容量配置。这种方式可以缓解该情况的出现,但不能杜绝。
- service不直接将消息发送到buffer,而是将消息写到本地的磁盘中(数据库或者文件),由另一个线程进行消息发送。相当于是在buffer和service之间又加了一层空间更加富裕的缓冲层。
Consumer消费消息有下面几个步骤:
- 接收消息
- 处理消息
- 反馈“处理完毕”(commited)
Consumer的提交方式主要分为两种:
- 自动提交offset,Automatic Offset Committing
- 手动提交offset,Manual Offset Control
Consumer自动提交的机制是根据一定的时间间隔,将收到的消息进行commit。commit过程和消费消息的过程是异步的。也就是说,可能存在消费未成功,但是commit消息已经提交的情况,此时消息就丢失了。
解决思路:将自动提交改为手动提交,从而可以保证在所有消费逻辑执行完后才写入新的消息。
参考资料Kafka史上最详细原理总结
面试官:Kafka 会不会丢消息?怎么处理的?
《我想进大厂》之kafka夺命连环11问
kafka为什么要放弃Zookeeper?
[大白话+13张图解kafka](
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)