Kafka初识

Kafka初识,第1张

Kafka初识 Kafka初识 kafka简介

消息队列模型

消息队列模型通常有两种:

  1. 点对点模式:也就是消息只能被一个消费者消费,消费完后消息删除
  2. 发布订阅模式:相当于广播模式,消息可以被所有消费者消费

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的选举方法主要如下:

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。

kafka特点 分区选择方式
  1. 轮询,按照顺序消息依次发送到不同的分区
  2. 随机,随机发送到某个分区

如果消息指定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丢失

Consumer消费消息有下面几个步骤:

  • 接收消息
  • 处理消息
  • 反馈“处理完毕”(commited)

Consumer的提交方式主要分为两种:

  • 自动提交offset,Automatic Offset Committing
  • 手动提交offset,Manual Offset Control

Consumer自动提交的机制是根据一定的时间间隔,将收到的消息进行commit。commit过程和消费消息的过程是异步的。也就是说,可能存在消费未成功,但是commit消息已经提交的情况,此时消息就丢失了。

解决思路:将自动提交改为手动提交,从而可以保证在所有消费逻辑执行完后才写入新的消息。

参考资料

Kafka史上最详细原理总结

面试官:Kafka 会不会丢消息?怎么处理的?

《我想进大厂》之kafka夺命连环11问

kafka为什么要放弃Zookeeper?

[大白话+13张图解kafka](

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5677565.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存