Kafka从入门到精通

异步通信原理


观察者模式

:::info

观察者模式

  • 观察者模式(Observer),又叫"发布-订阅"模式(**Publish-Subscribe**)。
  • 定义对象间一种"一对多"的依赖关系。每当一个对象(目标对象)改变状态,则所有依赖于它的对象(观察者对象)都会得到通知并自动更新。
    :::

生产者消费者模式

:::info

1、传统模式

  • 生产者直接将消息传递给指定的消费者。
    • 缺点:
      • 耦合性高。当生产者或消费者任意一方发生变化,都需要重写业务逻辑。

2、生产者消费者模式

  • 通过一个容器来解决生产者和消费者的强耦合性关系。
  • 生产者和消费者彼此之间不直接通信,而是通过阻塞队列来进行通信

image.png
:::
:::tips

生产者消费者模式的数据传递流程

  1. 生产者消费者模式。即:N个线程进行生产,同时N个线程进行消费。两种角色通过内存缓冲区进行通信
  2. 生产者负责向缓冲区里面添加(生产)数据。
  3. 消费者负责向缓冲区里面取出(消费)数据。【遵循"先进先出"原则
    :::

MQ消息传递的方式

点对点消息传递

:::tips

点对点消息传递

  • 在点对点消息系统中,消息持久化到一个队列中。此时,将有一个或多个消费者消费队列中的数据。
  • 但是一条数据只能被消费一次
  • 当一个消费者消费了队列中的某条数据后,该数据将从队列中删除。
  • 该模式即使有多个消费者同时消费数据,也能保证数据处理的顺序。

image.png
:::

发布订阅消息传递

:::tips

发布订阅消息传递

  • 在发布订阅消息系统中,消息被持久化到一个Topic中
  • 消费者可以订阅一个或多个Topic,消费者可以消费该Topic中的所有数据。
  • 同一条数据可以被多个消费者消费,数据被消费后,不会立马删除。
  • 在发布订阅消息系统中,消息的生产者称为"发布者",消费者称为"订阅者"。

image.png
image.png

Kafka采取拉取模式(Poll),由自己控制消费速度,消费者可以按照任意的偏移量进行消费。

:::


Kafka

概念

:::tips

官网

概念

  • Kafka是一种高吞吐量的分布式发布订阅的消息系统。
  • Kafka本质上是一个消息队列(MQ:**Message Queue**。主要用来处理大量数据下的消息队列,一般用来做日志处理。

消息队列的优点:

一、解耦
  • 允许我们独立扩展或修改队列两边的处理过程
  • 可恢复性。即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
二、异步
  • 异步处理,不需要让流程走完才返回结果。可以将消息发送到消息队列中,然后返回结果,消费者只需要从消息队列中拉取消费处理即可。
三、削峰
  • 缓冲。有助于解决生产消息和消费消息的处理速度不一致的情况。
  • 高流量的时候,使用消息队列作为中间件,可以将流量的高峰保存在消息队列中,从而防止系统的高请求,减轻服务器的请求处理压力。
    :::

优缺点

:::success

优点

1、高吞吐量、低延迟
  • Kafka单机性能TPS**100万/秒**,并且生产和消费的延迟都很低。
2、可扩展性
  • Kafka集群支持热扩展。
3、持久性、可靠性
  • Kafka中的消息被持久化到本地磁盘中,并且支持数据备份,防止数据丢失。
4、容错性
  • Kafka允许集群节点失败。(若副本数量为"N",则允许"N-1"个节点失败)
5、高并发
  • Kafka支持千个客户端同时读写。
6、解耦、异步、削峰
7、顺序保证
  • Kafka可以保证一个Partition内的消息的有序性

缺点

  1. 仅支持同一分区内消息有序,无法实现全局消息有序。
  2. 使用短轮询的方式,实时性取决于轮询的间隔时间。
  3. 由于是批量发送,数据并非真正的实时
  4. 无法弹性扩容。对Partition的读写都在Partition Leader所在的Broker。如果该Broker压力过大,也无法通过新增Broker来解决问题。
  5. 扩展性成本高。集群中新增的Broker只会处理新Topic。如果要分担老Topic-Partition的压力,需要手动迁移Partition,这里会占用大量集群宽带。
  6. 消费者新加入和退出会造成整个消费组"Rebalance"。导致数据重复消费,影响消费速度。
  7. 消费失败,不支持重试。
  8. Partition过多会使得性能显著下降。Zookeeper压力大,Broker上Partition过多,让磁盘顺序写几乎退化成随机写。
    :::

Kafka架构

Producer

Producer

  • 消息生产者,向Kafka中发布消息的角色。

Consumer

Consumer

  • 消息消费者,从Kafka中拉取消息消费的客户端。
  • 消费者可以从Broker中读取数据,消费多个Topic中的数据。

Consumer Group

Consumer Group

  • 消费者组。将多个消费者集中到一起去处理某个Topic的数据,可以更快的提高数据的消费能力
  • 整个消费者组共享一组偏移量(防止数据被重复读取),因为一个Topic有多个Partition。
  • 消费者组,一组中存在多个消费者。消费者消费Broker中当前Topic的不同分区中的消息。
  • 消息者组之间互不影响,所有的消费者都属于某个消费者组。
  • 每个Consumer属于一个特定的Consumer Group
  • 一个分区中的消息,只能由组内的一个消费者所消费。

Broker

:::success

Broker

  • 一台Kafka服务器,就是一个Broker。
  • 一个群集由多个Broker组成,一个Broker可以容纳多个Topic。
    :::

Topic

:::success

Topic

  • 主题。可以理解为一个队列。Topic将消息分类,生产者和消费者都是面向一个Topic。

  • 一个Topic可以分成若干个Partition。

  • 一个Partition物理上由多个Segment组成。

  • **一个Segment文件由两部分组成: ➯ ****LogSegment文件**

    1. **.index**文件:表示Segment的索引文件。**.index**文件中的元数据指向对应的**.log**文件中Message的物理偏移量,默认大小为10M。
      • Partition全局的第一个Segment从0开始,后续每个Segment文件中为上一个Segment文件最后一条消息的Offset值。
      • 数值大小为64位,其中20位数字字符长度,没有数字用"0"填充。
    2. **.log**文件:表示Segment的数据文件。
    3. **.timeindex**文件:时间戳索引。
      :::
      :::success
第一个Segment文件

:::
第一个Segment从0开始
:::tips
00000000000000000000.index
:::
:::warning
00000000000000000000.log
:::
:::success

第二个Segment文件

:::
文件命名以第一个segment的最后一条消息的offset组成
:::tips
00000000000000000512.index
:::
:::warning
00000000000000000512.log
:::
:::success

第三个Segment文件

:::
文件命名以上一个segment的最后一条消息的offset组成
:::tips
00000000000000000913.index
:::
:::warning
00000000000000000913.log
:::
:::success

  • 配置文件中Segment的参数有两个:
    1. **log.segment.bytes**:单个Segment可容纳的最大数据量,默认为**1G**
    2. **log.segment.ms**:Kafka在commit一个未写满的Segment前,所等待的时间,默认为**7天**
      :::
      :::tips
      消息都具有固定的物理结构,包括:Offset(8 Bytes)、消息体的大小(4 Bytes)、crc32(4 Bytes)、magic(1 Byte)、attributes(1 Byte)、key length(4 Bytes)、key(K Bytes)、payload(N Bytes)等等字段,可以确定一条消息的大小,即读取到哪里截止。
      :::

Partition

:::success

Partition

  • 分区。为了实现扩展性,提高并发能力,一个非常大的Topic可以分布到多个Broker上,一个Topic可以分为多个Partition
  • 当生产者产生数据的时候,根据分配策略,选择分区,然后将消息追加到指定的分区的末尾队列中。
    • Partition的分配策略:
      1. 如果指定Partition,则直接使用。
      2. 如果未指定Partition,但是指定了"Key"。通过对"Key"的"Value"进行Hash,先出一个Partition。
      3. 如果Partition和Key都未指定,则使用轮询的方式选出一个Partition。
  • 同一个Topic在不同的分区的数据是不重复的。
  • 每个Partition是一个有序的队列。分区内有序,不能保证全局有序)每条消息都会有一个自增的编号。
    1. 标识顺序。
    2. 用于标识消息的偏移量。
    3. 每个Partition都有自己独立的编号。
  • 每个Partition中的数据使用多个Segment文件存储
  • 如果Topic有多个Partition,消费数据时就不能保证数据的顺序。如果要求严格保证消息的消费顺序的情况下,需要将Partition的数目设置为1
    :::

Replication

:::success

Replication

  • 副本。为了保证集群中某个节点发生故障,节点上的Partition数据不丢失,Kafka可以正常工作。Kafka提供了副本机制,一个Topic的每个分区有若干个副本,一个Leader(1)和Follower(N)
    • Leader:负责写入和读取数据。
    • Follower:只负责备份数据。
  • Kafka默认副本的最大数量是10个,并且副本的数量不能大于Broker的数量
  • **副本数N = 主 + 备**
    :::

Leader

:::success

Leader

  • 每个分区多个副本的主角色,负责写入和读取数据
    :::

Follower

:::success

Follower

  • 每个分区多个副本的从角色,实时的从Leader中同步数据,并且Follower与Leader保持数据同步
  • 如果Leader发生故障,则从Follower中选举出一个新的Leader。
    :::

Offset

:::success

Offset

  • 偏移量。消费才消费的位置信息,可以监控数据消费到什么位置。当消费者发生故障再次重新恢复时,可以从消费位置继续消费。
  • 偏移量决定读取数据的位置,不会有线程安全问题。消费者通过偏移量来决定下次读取的消息。
  • 消息被消费之后,并不会被马上删除。这样多个业务就可以重复使用Kafka的消息。
  • 消息最终还是会被删除的。默认删除的时间是**7天**(7*24小时)。
    :::

Zookeeper

:::success

Zookeeper

  1. Kafka集群能够正常工作,需要依赖于Zookeeper,Zookeeper帮助Kafka存储和管理集群信息
  2. 帮助选举。
    :::

Kafka数据存储


Kafka数据分区的目的

:::tips

分区的原因?

  1. 方便在集群中扩展。每个Partition可以通过调整以适应它所在的机器。
  2. **提高并发的读写效率。**一个Topic可以由多个Partition组成,可以将Partition作为读写单位,并发读写,提高效率。
    :::

:::info

分区原则:

  • 将Partition发送的数据封装成一个**ProducerRecord**对象。
    • **ProducerRecord**对象包含:
      • topic:String类型,NotNull。
      • partition:int类型。
      • timestamp:long类型。
      • key:String类型。
      • value:String类型。
      • headers:Array类型。
        :::

生产者数据安全

ACK机制

:::info

ACK机制原理

  1. 为了保证Producer发送的数据,能可靠的发送到指定的Topic
  2. 要求**Topic**的每个**Partition**收到**Producer**发送的数据后,都需要向**Producer**发送**ACK**确认收到。
  3. 如果Producer收到ACK消息后,就会进行下一轮的发送。否则,就会重新发送数据。
    :::

关键词

AR

:::warning

  • **Assigned Replicas**,用来标识副本的全集。
  • **AR = ISR + OSR**
    :::

ISR

:::warning

  • **In-Sync Replicas**,加入同步队列的副本。
  • **ISR = Leader + 没有落后太多的副本****落后 < 4000条**
  1. **Leader**维护了一个动态的**In-Sync Replicas**集合ISRLeader保持同步的Follower集合)
  2. **ISR**集合中的**Follower**完成数据的同步之后,**Leader**就会给**Follower**发送**ACK**
  3. 如果**Follower**长时间未向**Leader**同步数据,则该**Follower**将被踢出**ISR**集合。判断标准:
    1. 超过10秒钟没有同步数据。
      • replica.lag.time.max.ms=10000
    2. 副节点与主节点相差超过4000条数据。
      • rerplica.lag.max.messages=4000
  4. **Leader**发生故障后,就会从**ISR**中选举出新的**Leader**
    • Kafka采用一种降级措施来处理:
      • 选举第一个恢复的节点作为**Leader**提供服务,以新的数据为基准,这个措施被称为**Leader**选举
        :::

OSR

:::warning

  • **Out-Sync Replicas**,离开同步队列的副本。
    :::

ACK应答机制(可靠性级别)

:::info
Kafka提供了三种可靠性级别,通过设置acks参数的值,用户可以根据可靠性和延迟的要求进行权衡。
**request.required.acks**参数表示的是生产者生产消息时,写入到副本的严格程度,决定了生产者如何在性能和可靠性之间做取舍。
:::
05-生产者安全上篇.jpg

**acks=1**【默认】

:::warning

  • 表示数据发送到Kafka后,需要经过Leader成功接收到数据并得到确认后,才算发送成功。
  • 弊端:
    • 如果Follower同步成功之前,Leader故障,将会丢失数据。
      :::

**acks=0**

:::warning

  • 表示Producer将数据发送出去了就不管了,无需等待来自Broker的确认而继续发送下一条消息。
  • 这种情况下数据传输效率最高,但是数据的可靠性最低
  • 弊端:
    • 当Broker宕机时,有可能丢失数据。
      :::

**acks=-1**

:::warning

  • 表示Producer需要等待ISR中所有的Follower都确认接收到数据后,才算发送完成。
  • 这种情况下,数据绝对不会丢失,可靠性最高,但是性能最低
  • 弊端:
    • 当Broker发送ACK时,如果Leader发生故障,则会造成数据重复
      :::

Kafka故障处理

image.png

关键词

LEO

:::warning

  • **Log End Offset**,当前节点的最后偏移量。每个副本最大的Offset。
    :::

HW

:::warning

  • **HightWatermark**,高水位线。消费者能看到的最大Offset,**ISR**队列中最小的**LEO**
    :::

Leader故障

  1. Leader发生故障后,会从ISR中选出一个新的Leader
  2. 为了保证多个副本之间数据的一致性,其余的Follower会先将各自的**log**文件,高于HW的部分截取掉,然后从新的Leader中同步数据
  • 这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复

Follower故障

  1. Follower发生故障后,会被临时踢出**ISR**集合。
  2. 待该Follower恢复后,Follower会先读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW处开始,向Leader进行数据同步操作
  3. 等该Follower的LEO大于或等于该Partition的HW时(即:Follower向Leader同步完成后),就可以重新加入**ISR**队列中

Exactly Once

Exactly Once只有一次

  • **At Least Once + 幂等性 = Exactly Once**
    • 启用幂等性,需要设置Producer的参数:**enable.idompotence=true**
      1. 开启幂等性的Producer在初始化时,会被分配一个**PID**,发往同一个Partition的消息会附带Sequence Number
      2. 而Borker端会对<PID, Partition, SeqNumber>做缓存,当具有相同主键的消息提交时,Broker只会持久化一条。
      3. 但是PID重启后就会变化,同时不同的Partition也具有不同主键,所以幂等性无法保证跨分区会话的**Exactly Once**
  • Producer不论向Server发送多少重复数据,Server端都只会持久化一条

At Least Once至少一次

  • **ACK = -1**
  • 可以保证数据不丢失,但是不能保证数据不重复

At Most Once最多一次

  • **ACK = 0**
  • 可以保证数据不重复,但是不能保证数据不丢失

消费者数据安全

消费方式

:::info

  1. Consumer采用**Pull****(拉取)**模式从Broker中读取数据。
    • 原因?
      • Consumer采用Push(推送)模式,Broker给Consumer推送消息的速率是由Broker决定的,很难适应消费速率不同的消费者。
      • Pull模式则可以根据Consumer的消费能力以适当的速率消费消息。
    • Pull模式的缺点:
      • Pull模式不足之处是,如果Kafka没有数据,消费者可能会陷入循环中,一直返回空数据
      • 消费者从Broker主动拉取数据,需要维护一个长轮询,消费者在消费数据时会传入一个时长参数**timeout**。如果当前没有数据可供消费,Consumer会等待timeout时间之后再返回。
        :::

分区分配策略

:::tips
将分区的所有权从一个消费者移到另一个消费者称为重新平衡(rebalance)。

分区分配的时机:

  1. 新增消费者。
  2. 减少消费者。(宕机、故障、下线…)
  3. 订阅的主题,新增Partition。

Kafka有三种分配策略:

  1. RangeAssignor,默认方式。
  2. RoundRobinAssignor,轮询的方式。
  3. StickyAssignor,粘性。
    :::

RangeAssignor【默认】

:::warning

  • Range方式是按照主题来分的,不会产生轮询方式消费混乱的问题。
  • 原理:
    • **Topic的分区数 / 订阅此Topic的消费者数量**,进行平均分配,以保证分区尽可能均匀地分配给所有的消费者。
    • 如果不够平均分配(不能整除),按照字典序靠前的消费者会被多分配一个分区

image.png

  • 缺陷:
    • 可以明显的看到这样的分配并不均匀,如果将类似的情形扩大,有可能会出现部分消费者过载的情况。
    • 如果同一个消费组内的消费者所订阅的Topic 是不相同的,那么在执行分区分配的时候就不是完全的平均分配,有可能会导致分区分配的不均匀。
    • 如果某个消费者没有订阅消费组内的某个Topic,那么在分配分区的时候此消费者将分配不到这个Topic的任何分区。
      :::

RoundRobinAssignor

:::warning

  • RoundRobinAssignor,原理是将消费组内所有消费者以及消费者所订阅的所有Topic的Partition按照字典序排序,然后通过轮询方式将所有分区作为一个整体进行**Hash**排序,消费者方式逐个将分区分配给每个消费者
  • 消费者组内分配分区个数最大差别为**1**。是按照组来分的,可以解决多个消费者消费数据不均衡的问题。

  • 缺陷:
    • 当消费者组内订阅不同主题时,可能造成消费混乱。
      :::

StickyAssignor

:::warning
粘性分配策略的目的:

  1. 分区的分配要尽可能的均匀。
  2. 分区的分配尽可能的与上次分配的保持相同。
  3. 当两者发生冲突时,第一个目标优先于第二个目标。


:::


Offset的维护

生产端的Offset

:::warning

:::

消费端的Offset

:::warning

Offset的作用

  • 由于Consumer在消费过程中可能会出现断电、宕机等故障,Consumer恢复后,需要从故障前的位置继续消费
  • 所以Consumer需要实时记录自己消费到了哪个Offset,以便故障恢复后继续消费。

Kafka0.9版本

  • ,Consumer默认将**Offset**保存在**Zookeeper**
  • ,Consumer默认将**Offset**保存在**Kafka**一个内置的**Topic**中,该**Topic****__consumer_offsets**
    :::
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A115EE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值