Kafka原理

Kafka是一个开源的分布式事件流平台,作为消息队列,提供解耦、可恢复性及缓冲等功能。其架构包括Producer、Consumer、Consumer Group和Broker。Kafka的工作流程涉及消息的发布和订阅,以及Producer发送消息到Partition的可靠性保证,如通过ISR机制和不同ack级别防止数据丢失。文件存储机制采用分片和索引,提高查询效率。Producer发送消息采用异步方式,分区策略包括粘性分区器。Kafka通过幂等性和事务特性实现数据可靠性,消费者采用pull模式,通过offset维护消费位置,支持手动和自动提交。
摘要由CSDN通过智能技术生成

Kafka

一.概述

1.定义

  • Kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue)
  • Kafka是一个开源的分布式事件流平台

2.消息队列

  • 应用:
    1. 同步处理
    2. 异步处理
  • 优点:
    • 解耦
    • 可恢复性
    • 缓冲
    • 峰值处理
    • 异步通信
  • 消息队列两种模式:
    1. 点对点模式
      • 消费者主动拉取数据,并在收到后清除。故一个消息仅能被消费一次
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GCBcKJsf-1625981231681)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210706194226978.png)]
    2. 发布/订阅模式
      • 消息生产者将消息发布到topic中,消费者订阅消费该消息。
      • 发布到topic的消息会被所有消费者订阅消费。消费后不清除消息。
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7FI0f8Ed-1625981231682)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210706194403990.png)]

3.Kafka基础架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qKk4nr3G-1625981231683)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210706194926673.png)]

  • Producer

    生产者,向kafka broker中发送消息的客户端

  • Consumer

    消费者,向kafka broker中拉取消息的客户端

  • Consumer Group(CG)

    • 消费者组,由多个Consumer组成。

    • 消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;(防止出现数据重复)

    • 消费者组之间互不影响、所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。

  • Broker

    一台kafka服务器就是一个broker。一个kafka集群由多个broker组成,一个broker可以容纳多个topic

  • Topic

    可以理解为一个队列,成产者和消费者面向的都是一个topic

  • Partition

    一个topic可以分布到多个broker上,即一个topic可以分为多个Partition,每个Partition是一个有序的队列

  • Replica

    副本,为保证不发展单点故障问题,kafka提供了副本机制,可以设置每个topic的每个分区有若干的副本。副本由一个leader和多个follower

    • leader

      副本的"主",生产者和消费者处理的对象都是leader

    • follower

      副本中的"从",实时同步leader。在leader故障时,保障数据安全,从多个follower中选择一个成为新年的leader

二.kafka架构深入

1.kafka工作流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CzdqjdQV-1625981231685)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210706203901091.png)]

  • kafaka中消息是以topic进行分类的,成产者成产的消息和消费者消费的消息,都是面向topic的
  • 一个topic下的每个partition(分区)对消息都维护了两个offset,一个记录生产者发送消息位置,即消息数量。另一个消费者消费到那一条消息。
  • Topic是逻辑上的概念,partition是物理的概念,每个partition对应一个log文件,log文件中存储的就是producer生产的数据。partition生产的数据不断追加到log文件的末端,同时每条数据都有一个offset。消费者组中每个消费者,通过offset记录自己消费到哪一个数据,以便出错后再次恢复时回到上次消费的位置,即实现断点续传功能。

2.kafka文件存储机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I45gS64M-1625981231686)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210706204833637.png)]

  • 生产者生产的消息(数据)存在在一个由topic+分区号命名的文件夹中。其数据不断追加到文件夹中的log文件中的末尾。
  • 为了防止log文件过大导致数据查找效率过低。kafka采用分片索引的机制。通过将将每个partition分为多个sagment。每个sagment对应有log和index两个文件。每个index和log文件命名为一个sagment的offset。如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMLYrGKz-1625981231687)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210706213019602.png)]

  • 通过文件名即offset可以算出消息输入哪一个具体sagment。再通过index文件中存储的索引信息,对应log中物理偏移地址。
  • index采用数组的数据结构,提高查询速率。

3.Producer发送消息的流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-98yoWJ2K-1625981231687)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210707012354761.png)]

  • Producer采用异步发送的方式发送消息。发送过程中使用main线程和Sender两个线程,以及一个线程共享变量RecordAccumulator。main线程将消息发送给线程共享变量,Senser线程不断从线程共享变量中拉取数据到Kafka Broker。
  • main线程需经过拦截器Interceptor,序列化器Serializer以及分区器Partition。其中拦截器用来过滤数据,序列化器将数据转为为byte数组提高传输效率,最后通过分区器将数据分区发送到线程共享变量RecordAccumulator中,最后再由sender线程拉取数据并发送到topic中。
  • Sender线程拉取数据时机由两个参数决定:
    1. batch.size:批处理大小,当线程共享变量达到batch.size大小时,sender才会发送出数据
    2. linger.ms:等待时间。即数据没有达到batch.size,但超过linger.ms时间时。sender也会开启发送

4.kafka生产者的分区策略

  • 分区原因:

    1. 方便在集群中扩展
    2. 提高并发,以partition为单位进行读写
  • 分区规则:

    1. 指明partition

      按照指明的partition传输数据

    2. 没有指明partition,但有key值

      将key值与topic的partition数量取余得到partition值

    3. 没有指明partition值,也没哟具体key值

      • 默认采用高Sticky Partition(粘性分区器)的方式分区
      • 粘性分区器规则:随机分配一个分区,并尽可能一直使用此分区。知道超过batch.size或已完成,下次数据进入的分区号将再次随机分配。

5.Kafka消息可靠性保证(无丢失,无重复)

1.生产者(producer)发送数据到topic-partition时可靠性保证
  • 再producer向topic-partition中发送数据时,每个topic-partition收到数据后都向producer发送ack(acknowledgement确认收到),producer收到ack后,将进行下一轮数据发送,否则重新发送数据。

  • 发送ack的时机:

    • 为减少副本冗余,在保障数据可靠情况下使用最少的副本数量。Kafka使用副本follower全部同步leader后再发送ack的方式。但是带来一个问题,即存在一个follower出现故障或同步速率过慢,将会导致长时间无法完成同步工作,kafka将无法返回ack。导致整个系统运行速度过慢甚至无法继续运行。故kafka引入了一个动态消息同步队列ISR机制。

    • ISR

      leader中维护一个ISR队列,队列中为保持和leader同步的follower集合。

      当ISR中全部follower同步完成后,leader再向producer发送ack。如果存在follower出现故障或同步速率过慢的情况。当在规定时间(由参数***replica.lag.time.max.ms***设置,默认为10s)无法完成同步的follower,leader将把它踢出ISR。从而不影响发送速度。当leader出现故障时,会在ISR队列中选举新的leader。

    • ack应答级别

      kafka提供了三种可靠性级别

      1. ack = 0

        partition中的leader在接收到producer发送的消息后,存入内存中,返回ack。此时消息数据还没有存入磁盘中落盘。follower也没有开始同步数据。若发生leader故障,则会导致数据丢失。producer收到ack则会继续发送新消息。即消息只发送一次(at most once)

      2. ack = 1

        partition中leader在数据落盘后,即从内存写入磁盘中后,返回ack。此时follower还未完成消息同步。若此时leader发生故障,则会导致数据丢失。

      3. ack = -1(all)

        等partition的leader和follower全部落盘(ISR队列模式)后在返回ack。但存在小概率在全部落盘后,leader发送ack前,leader故障。未完成ack发送,但消息已经落盘。producer没有收到ack则会再次发送该消息,造成数据重复。

2.leader和follower故障处理的方式

LEO:每个副本offset即副本长度

HW:消费者能看到的最大offset,即ISR队列中最小的LEO(同步队列副本最小同步到长度)

  • follower故障

    故障的follower被踢出ISR,待follower恢复以后,读取本地磁盘,获取上次记录的HW。将LEO高于HW的部分截取,从HW部分向leader开始同步。等follower的LEO大于等于现在partition的HW,即以追上当前leader最新ack响应进度,就可以再次加入ISR了。

  • leader故障

    leader发生故障后,将在ISR队列中选举一个新的leader。为保障副本之间数据一致,其余follower将各自高于HW部分截取,然后从新的leader同步数据。选举的方式是选择最稳定的那个follower,即长时间未脱离ISR的副本。

3.解决数据重复问题Exactly Once
  • ack=-1 (all)时,可以保证producer到server之间不丢数据。称之为At least once 至少一次。

  • ack = 0 时,每个消息只发送一次,称之为At most Once 最多一次。

    At more Once(ack = 0)无法保障数据不丢失,At least Once(ack = -1)可以保证数据不丢失,但是无法保障数据不重复。若想保证数据既不丢失也不重复,从而引出Exactly Once(精准一次性)。

  • Exactly Once:(精准一次)

    At least Once + 幂等性 = Exactly Once

    (即把ack设置为-1,producer的参数enable.idempotence设置为true,默认就是true)

    **幂等性:**无论多少次重复动作,只会操作一次。即partition重复发送数据也只会持久化一条数据。

    ​ 实现方式:producer初始化分配一个PID,发送同一个消息附带一个Sequence Number。

    在Broker端存储一个<PID, Partition, SeqNumber>做缓存。提交相同主键消息时,通过缓存识别为相同数据,Broker只持久化一次。

    ​ 但是一旦重启producer,PID改变,无法识别是否同一条消息,故幂等性无法保证跨分区,跨会话的Exactly Once。

4.Producer事务
  • 在0.11版本中,produce引入事务特性。实现了跨分区跨会话的方式。即使服务重启,也能实现。

6.Kafka消费者consumer

  1. 消费方式
    • Consumer采用pull(拉)的模式从broker中读取数据。

      若采用push(推)模式,很难适应消费不同速率的消费者。消息发送速率由broker决定。很容易造成Consumer来不及处理的情况,形成网路拥塞。因此采用pull模式。

    • 但是pull模式也存在不足:若kafka中没有数据,消费者会一直pull拉取数据,一直返回空数据。因此,kafka通过向消费者传递一个长参数timeout,若没有数据供消费者消费。Consumer等待timeout所设置时间后再返回。

  2. 分区分配策略

    一个Consumer group中存在多个Consumer,一个topic中存在多个partition。一个partition只能由Consumer group组中一个成员消费,因此kafka需要对组中Consumer分配partition。kafka设置了三种分配策略:RoundRobin,Range和Sticky。以下对三种策略进行介绍:

    1. RoundRobin

      image-20210710232459378
      • 分区按照排序依次分配给Consumer group组中每个消费者,轮询分配。
    2. Range(默认的分配方式)

      image-20210710232952079
      • (partition总数/Consumer数量),按顺序将partition一次性分配完成,多余分配给第一个Consumer。
      • 一旦一个Consumer发生故障,再次计算新的(partition总数/Consumer数量)的值,重新分配,但是会造成同一个分区前后处理的partition发生变化。
    3. Sticky

      • StickyAssignor策略,kafka从0.11.x版本开始使用这种策略。首先会尽力均衡分配partition到个个consumer。在同一组内消费者出现故障时候,会保持原来每个消费者消费的分区不变。将故障消费者处理分区均衡分给其他组内消费者消费。
  3. offset维护

    由于Consumer存在故障宕机等可能,所以需要Consumer消费具有断点续传的功能。故Consumer会记录一个offset标记自己消费的位置,以便恢复后继续上次消费。

  4. 自动提交offset

    kafka提供了自动提交offset功能。通过以下两个参数设置:

    • enable.auto.commit:是否开启自动提交offset功能
    • auto.commit.interval.ms:自动提交offset的时间间隔
  5. 重置offset
    • auto.offset.reset = earliest | latest | none |

      当Kafka没有初始偏移量(第一次消费)或者服务器在offset(被删除)后处理方式:

      • earlist:自动将offset设置为最早偏移量(从头开始消费即from begging)
      • latest(默认):自动将offset设置为最新偏移量(从当前开始消费)
      • none:找不到offset后则抛出异常
  6. 手动提交offset
    • 自动提交offset方式虽然方便,但是其基于时间提交。kafka无法知道消费者是否消费完成数据,因此存在数据丢失但是offset已经提交的情况。所以为了保障数据不丢失,需要将offset设置为手动提交模式。

    • 手动提交分为:commitSync(同步提交),commitAsync(异步提交)两种。

      相同点:本次pull拉取的一批数据最高偏移量提交

      不通点:同步提交会阻塞线程,等提交成功后再继续。若提交失败则自动重试。

      ​ 异步提交不等待,可能存在提交失败。

    • 无论同步还是异步提交offset,都不能完全保证数据不丢不重。先提交后消费,可能造成数据丢失。先消费后提交可能造成数据重复。想要实现数据不重不丢,需要实现kafka消费端将消费过程和提交offset过程做原子绑定,才能实现。

  7. Kafka高效读写数据
    • 顺序读写磁盘

      producer写入log文件中采用一直追加到文件末端的顺序写方式。对于磁盘而言,顺序写的速度远远超过随机读写的速度。主要在于省去了大量磁头寻址的时间。

    • 零拷贝技术

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mqWohBTl-1625981231688)(C:\Users\Jzs\AppData\Roaming\Typora\typora-user-images\image-20210711122306460.png)]

      • kafka不同于常见JavaIO程序。在数据读写时,直接通过操作系统层的page cache写入写出。实现高速读写。

过程做原子绑定,才能实现。

  1. Kafka高效读写数据
    • 顺序读写磁盘

      producer写入log文件中采用一直追加到文件末端的顺序写方式。对于磁盘而言,顺序写的速度远远超过随机读写的速度。主要在于省去了大量磁头寻址的时间。

    • 零拷贝技术

      [外链图片转存中…(img-mqWohBTl-1625981231688)]

      • kafka不同于常见JavaIO程序。在数据读写时,直接通过操作系统层的page cache写入写出。实现高速读写。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值