Kafka

Kafka相关概念

异步通信原理

观察者模式

观察者模式又叫发布-订阅模式,定义对象之间一种 一对多的依赖关系,使得每一个对象改变状态,则所有依赖他的对象都会得到通知并自动更新

【例:京东到货通知

生产者消费者模式

  • 传统模式
    • 生产者直接将消息传递给指定的消费者
    • 耦合性特别高,当生产者或者消费者发生变化,都需要重写业务逻辑
  • 生产者消费者模式
    • 通过中间有一个缓存的容器存放消息,生产者在生产消息存放在里面,消费者从里面获取数据消费,通过阻塞队列进行通讯
    • 同时可以有N个线程生产数据,也可以有N多个线程消费数据,两者之间通过缓冲区通信
      • 一般是先进先出的原则1

缓冲区

  • 位于生产者消费者之间,存放生产者消息,提供给消费者消费信息
  • 优点:
    • 可以支持并发,生产者消费者之间没有影响
    • 可以让消费者确认处理完所有内容,避免生产者生产太快,消费者无法消费

数据单元

  • 关联业务
    • 数据单元必须关联对应的业务对象
  • 完整性
    • 传输过程中,要保证数据单元的完整
  • 独立性
    • 就是各个单元之间数据没有依赖性,互不影响
  • 颗粒度
    • 对于数据的颗粒要区分好
    • 如果颗粒太大,会增加单个数据传输时间,对后续消费产生营销
    • 如果颗粒太小。会增加传输次数

消息系统原理

点对点消息传递

  • 基于推送模型的消息系统 【这种方式无法很好地保证消费的处理语义】
  • 可以保证消息队列中数据,可以有多个消费者同时消费这些数据,但是一条数据只能被消费一次,一个消费者消费完毕之后会从队列中删除

发布订阅消息传递

  • Kafka 采取拉取模型(Poll),由自己控制消费速度,消费者可以按照任意的偏移量进行消费。
  • 消费者可以订阅一个或多个topic【主题】,消费者可以消费该topic中所有的数据,同一条数据可以被多个
    消费者消费,数据被消费后不会立马删除

Kafka

什么是kafka

  • 官网:http://kafka.apache.org/
  • Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞
    吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。
  • Kafka 本质上是一个 MQ(Message Queue),使用消息队列的好处?(面试会问)
    • 解耦:允许我们独立的扩展或修改队列两边的处理过程。
    • 可恢复性:即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
    • 缓冲:有助于解决生产消息和消费消息的处理速度不一致的情况。
    • 灵活性&峰值处理能力:不会因为突发的超负荷的请求而完全崩溃,消息队列能够使关键组件顶住突发的访问压力。
    • 异步通信:消息队列允许用户把消息放入队列但不立即处理它。

Kafka架构

  • Broker
    • 每个服务器就是一个Broker
  • Topic 主题
    • 一个虚拟的概念,消息被发布到kafak局群中,都会有一个类别,这个类别被称之为Topic
    • 物理上,不同的topic消息被分开存储
    • 逻辑上一个topic消息虽然保存多个broker上,但用户只需要指定消息的topic即可生产或者消费数据
  • Partition
    • topic是一个虚拟概念,真实是被分割为多个Partition
    • 每个Topic至少有一个Protition,当生产者生产数据的时候,根据分配策略,选择分区,然后将消息追加到制定的分区末尾
    • partition中数据有序,同一个topic下多个partition外部无序,内部有序
    • 如果一个topic被分割为多个partition,消费数据是无法保证数据有序,要求顺序,可以设置topic下只有一个partition
    • 每个消息都有一个自增的编号
      • 用来标识顺序
      • 标识数据偏移量
      • 每个partition都有自己的独立编号
  • leader
    • 每个partition有多个副本,副本中有一个leader,leader负责这些副本数据读写
  • Follower
    • Follower跟随Leader,所有写请求都通过leader路由,然后广播给所有的Follower
    • 如果leader挂掉,会从 follower中选举一个leader
    • 如果follower挂掉,或者同步数据慢【会被leader移除isr对象到osr队列】
  • replication
    • 数据就存放到topic的partition中,为了避免单个partition损坏,会对partition备份,创建副本
  • producer
    • 生产者数据的发布者,改角色将消息发布到kafka的topic中
    • broker接收到生产者数据后,broker将改数据追加到 【当前用于追加数据的】segment文件中
    • 生产者发送的消息,存储到一个partition中,生产者也可以制定数据存储partition
  • consunmer 消费者
    • 消费者可以从broker中读取数据,消费者可以消费多个topic中数据
  • Consumer Group
    • 每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)
    • 将多个消费者集中到一起去处理某一个Topic的数据,可以更快的提高数据的消费能力
    • 整个消费者组共享一组偏移量(防止数据被重复读取),因为一个Topic有多个分区
  • offest 偏移量
    • 可以唯一的标识一条消息
    • 偏移量决定读取数据的位置,不会存在线程不安全的问题,消费者消费数据,根据偏移量决定读取的数据
    • 消息被消费之后,并不被马上删除,这样多个业务就可以重复使用kafka的消息
    • 我们某一个业务也可以通过修改偏移量达到重新读取消息的目的,偏移量由用户控制
      消息最终还是会被删除的,默认生命周期为1周(7*24小时**)**
  • zookeeper
    • kafka 通过 zookeeper 来存储集群的 meta 信息。

kafka存储结构

  • 一个topic在物理上分为多个【也可以是一个】partition
  • 一个partition分成多个Segment, 一个partition物理上有多个segment组成
    • segment有两个参数
      • log.segment.bytes:单个segment可容纳的最大数据量,默认为1GB
        log.segment.ms:Kafka在commit一个未写满的segment前,所等待的时间(默认为7天)
  • segment下有两部分组成【.index和.log】文件
    • segment【就是.index和.log两个文件】下第一个segment从0开始,后续每个segment文件名为上一个segment最后一条消息的offest偏移量
      • .index 是存储索引 【使用的是稀疏索引 (不是稠密索引)
      • .log 是存储信息
    • 数值大小为64位,20位数字字符长度,没有数字用0填充

生产者数据安全

数据分区

  • 分区原因
    • 方便在集群中扩展,每个 Partition 可以通过调整以适应它所在的机器,
    • 一个 Topic 又可以有多个 Partition 组成,因此可以以 Partition 为单位读写了。
    • 可以提高并发,因此可以以 Partition 为单位读写了。
  • 分区原则
    • 将 Producer 发送的数据封装成一个 ProducerRecord 对象。对象包含:
      • topic:string 类型,NotNull。
      • partition:int 类型,可选。
      • timestamp:long 类型,可选。
      • key:string 类型,可选。
      • value:string 类型,可选。
      • headers:array 类型,Nullable。

ACK机制

  • 为了保证数据安全,可靠的发布到制定的topic
  • topic在每个partition接收到数据后,向Producer【生产者数据的发布者】发送ACK确认
  • 如果 Producer 收到 ACK,就会进行下一轮的发送,否则重新发送数据
  • ACK确认机制的三种等级
    • ack = 0 等级【安全性低,效率快】
      • 这意味着 Producer 无需等待来自 Leader的确认而继续发送下一批消息。
    • ack = 1 等级 【安全性中等,效率中等】
      • 这意味着 Producer 需要等待 在ISR中的leader 发送 ACK确认,才能发送下一批消息
    • ack = -1 等级 【安全性高,效率低】
      • Producer 需要等待 ISR 中的所有 Follower 都确认接收到数据后,才能发送下一批消息

AR【ISR OSR】

  • ISR【就是在partion中 follower 和leader关系度(数据内容)高的一些broker服务器】
    • 超过10秒钟没有同步数据,follower就会被移除leader的 ISR队列
      • replica.lag.time.max.ms=10000
    • 主副节点差4000条数据 , follower就会被移除leader的 ISR队列
      • rerplica.lag.max.messages=4000
  • OSR【就是被移除ISR队列中的broker服务器】

故障处理

脏leader选举,可以通过选择ack确认机制解决

  • LEO:每个副本最大的 Offset

  • HW:消费者能见到的最大的 Offset,ISR 队列中最小的 LEO

  • Leader 发生故障后,就会从 ISR 中选举出新的 Leader

    • Leader 发生故障后,会从 ISR 【可以配置从OSR中选leader】中选出一个新的 Leader,之后,为保证多个副本之间的数据一致性,其余的 Follower 会先将各自的 log 文件高于 HW 的部分截掉,然后从新的 Leader 同步数据。
    • 注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复
  • Follower 故障:

    • Follower 发生故障后会被临时踢出 ISR 集合,待该 Follower 恢复后,Follower 会 读取本地磁盘记录的上次的 HW,并将 log 文件高于 HW 的部分截取掉,从 HW 开始向 Leader 进行同步数据操作。
    • 等该 Follower 的 LEO 大于等于该 Partition 的 HW,即Follower 追上 Leader 后 ,就可以重新加入 ISR 了

消费者数据安全

消费数据方式

如果Consumer采用push(推送)的方式,那么Broker推送速率是固定的,但是每个Consumer消费速率不同,broker推送的速率很难适应所有的Consumer

  • Consumer(消费者) 采用 Pull(拉取)模式从 Broker 中读取数据。
    • 每个consumer根据自己消费速率,去Broker消费数据信息
    • 为了避免consumer和Broker之间一直通讯拉取数据的资源消耗
      • 在consumer和broker之间建立的长链接,在长链接时,如果Broker有数据就马上获取数据进行消费,如果没有数据,就一直等待一会,当时长超过timeout参数后在返回空数据

分区分配策略

kafak分区分配的策略 可以分为三种【RangeAssignor(默认), RoundRobinAssignor,StickyAssignor(0.11.x版后引入) 】

StickyAssignor策略比另外两者分配策略而言显得更加的优异,这个策略的代码实现也是异常复杂,如果大家在一个 group 里面,不同的 Consumer 订阅不同的 topic, 那么设置Sticky分配策略还是很有必要的

分区分配的时机
  • 同一个 Consumer Group 内新增消费者
  • 消费者离开当前所属的Consumer Group,包括shuts down 或 crashes
  • 订阅的主题新增分区
三种分配策略
  • RangeAssignor

    • RangeAssignor策略对应的partition.assignment.strategy参数值org.apache.kafka.clients.consumer.RangeAssignor

      计算方式

      1. n=根据主题中分区数/订阅的消费者数
      2. m=根据主题中分区数%订阅的消费者数
      3. 订阅该主题的前m个消费者分配(n+1)个去消费

  • RoundRobinAssignor

    • RoundRobinAssignor策略对应的partition.assignment.strategy参数值为:org.apache.kafka.clients.consumer.RoundRobinAssignor

      计算方式:

      1. 根据订阅相同的Topic的消费者
      2. 将相同的topic中所有分区进行轮询的方式进行分配
        在这里插入图片描述
  • SitckyAssignor

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

在这里插入图片描述

  • 假设此时消费者C1脱离了消费组,那么消费组就会执行再平衡操作,进而消费分区会重新分配

在这里插入图片描述

OffSet偏移量

生产端的OffSet

  • 每条消息都有一个offset值来表示它在分区中的位置。每次写入都是追加到文件的末尾

消费端Offest

  • 消费者在消费数据的时候会,维护一个offset,表示消费到分区的消息
  • offset记录的是下次消费的位置,如果是8,本次就消费8数据,然后offset记录为9
  • offset维护位置

    • Kafka 0.9 版本之前,Consumer 默认将 Offset 保存在 Zookeeper 中,
    • 从 0.9 版本开始,Consumer 默认将 Offset 保存在 Kafka 一个内置的 Topic 中,该 Topic 为__consumer_offsets
      • 消费者的offset值在consumer_offset这个topic中,具体在这个topic中的那个分区,是根据消费者所在的消费者组groupid决定的【groupid对50取余】
  • offset提交方式 【相关的参数设置是enable.auto.commit】

    • 参数默认为true,表示每5秒拉取分区中最大的消息位移进行提交
    • 参数设置为false时,需要手动提交offset
  • offset提交的同步(commitSync)异步(commitAsync)

    • 同步提交会根据poll方法拉取最新位移进行提交,只要没有发生不可恢复的错误,它就会阻塞消费线程直至提交完成,这种方式效率比较底,但是数据不会发生重复消费
      • 异步提交执行时不会阻塞消费线程,但有可能出现先提交的位移失败了而后提交的位移成功了,就会出现数据重复消费,对此,可以设置递增的序号维护异步的提交顺序【或者rebalance之前使用同步提交】
  • offset定期清理

    • offsets.retention.check.interval.ms:
      • offset定期检查数据过期周期
    • offsets.retention.minutes:
      • offset保留时长超过offsets.retention.minutes时间且offset没有改变时,消费者提交的offset会被清理掉
      • 再次消费时会按auto.offset.reset配置去消费。此时,会有数据丢失或者重复,可通过重置offset来解决

checkpoint的offset

  • Kafka每一个数据根目录都会包含最基本的N个检查点文件和meta.properties文件

  • 在创建topic的时候,如果当前broker中不止配置了一个data目录,那么会挑选分区数量最少的那个data目录来完成本次创建任务

  • 各个checkpoint作用如下

    • recovery-point-offset-checkpoint:
      • 表示已经刷写到磁盘的offset信息,对应LEO信息。kafka中会有一个定时任务负责将所有分区的LEO刷写到恢复点文件recovery-point-offset-checkpoint中,定时周期由broker端参数log.flush.offset.checkpoint.interval.ms配置,默认值60000,即60s。Kafka在启动时会检查文件的完整性,如果没有.kafka_cleanshutdown这个文件,就会进入一个recover逻辑,recover就是从此文件中的offset开始。
    • replication-offset-checkpoint:
      • 用来存储每个replica的HW,表示已经被commited的offset信息。失败的follower开始恢复时,会首先将自己的日志截断到上次的checkpointed时刻的HW,然后向leader拉取消息。kafka有一个定时任务负责将所有分区的HW刷写到复制点文件replication-offset-checkpoint中,定时周期由broker端参数replica.high.watermark.checkpoint.interval.ms配置,默认值5000,即5s。
    • log-start-offset-checkpoint:
      • 对应logStartOffset,用来标识日志的起始偏移量。kafka中有一个定时任务负责将所有分区的logStartOffset刷写到起始点文件log-start-offset-checkpoint中,定时周期有broker端参数log.flush.start.offset.checkpoint.interval.ms配置,默认值60000,即60s。
    • cleaner-offset-checkpoint:
      • 存了每个log的最后清理offset

Consumer重置offset

在kafak某些数据在消费后,需要再次消费的【或者需要消费指定偏移量数据的时候】,就需要重置offset

  • 更新Offset由三个维度决定:Topic的作用域、重置策略、执行方案

  • Topic的作用域
    Ø --all-topics:为consumer group下所有topic的所有分区调整位移)
    Ø --topic t1 --topic t2:为指定的若干个topic的所有分区调整位移
    Ø --topic t1:0,1,2:为指定的topic分区调整位移

  • 重置策略
    Ø --to-earliest:把位移调整到分区当前最小位移
    Ø --to-latest:把位移调整到分区当前最新位移
    Ø --to-current:把位移调整到分区当前位移
    Ø --to-offset : 把位移调整到指定位移处
    Ø --shift-by N: 把位移调整到当前位移 + N处,注意N可以是负数,表示向前移动
    Ø --to-datetime :把位移调整到大于给定时间的最早位移处,datetime格式是yyyy-MM-
    ddTHH:mm:ss.xxx,比如2017-08-04T00:00:00.000
    Ø --by-duration :把位移调整到距离当前时间指定间隔的位移处,duration格式是
    PnDTnHnMnS,比如PT0H5M0S
    Ø --from-file :从CSV文件中读取调整策略

  • 确定执行方案
    Ø 什么参数都不加:只是打印出位移调整方案,不具体执行
    Ø --execute:执行真正的位移调整
    Ø --export:把位移调整方案按照CSV格式打印,方便用户成csv文件,供后续直接使用

  • 常用示例

    Ø 更新到当前group最初的offset位置
    bin/kafka-consumer-groups.sh --bootstrap-server IP:Port --group test-group --reset-offsets –
    all-topics --to-earliest --execute
    Ø 更新到指定的offset位置
    bin/kafka-consumer-groups.sh --bootstrap-server IP:Port --group test-group --reset-offsets –
    all-topics --to-offset 500000 --execute
    Ø 更新到当前offset位置(解决offset的异常)
    bin/kafka-consumer-groups.sh --bootstrap-server IP:Port --group test-group --reset-offsets –
    all-topics --to-current --execute
    Ø offset位置按设置的值进行位移
    bin/kafka-consumer-groups.sh --bootstrap-server IP:Port --group test-group --reset-offsets –
    all-topics --shift-by -100000 --execute
    Ø offset设置到指定时刻开始
    bin/kafka-consumer-groups.sh --bootstrap-server IP:Port --group test-group --reset-offsets –
    all-topics --to-datetime 2017-08-04T14:30:00.000

kafak事务

Kafka幂等性

幂等性解释:幂等,就是指多接口的多次调用所产生的结果和只调用一次是一致的。没有幂等性的情况下就会重复发送数据

  • 引入了两个概念 partition ID 【分区id】和Sequence number 【数据版本】

  • 概念:

    • 一个数据通过key值就可以知道,这个数据应该被发送到那个partition分区中

    • 数据生产者:记录数据被发送的partition 的id

    ​ 并且每个partition发送的数据都会有一个sequence number自增的版本号

    • broker端会在内存中为每一对维护一个序列号

    判断流程:

    • 如果发送的sequence number = broker维护的sequece number +1 表示正常,可以接收写入

    • 如果发送的sequence number < broker维护的sequece number +1 那么说明消息被重复写入,broker可以直接将其丢弃

    • 如果发送的sequence number > broker维护的sequece number +1 那么说明中间有数据尚未写入,出现了乱序,暗示可能有消息丢失,这个异常是一个严重的异常

  • 开启方式
    Properties.put(“enable.idempotence”,true);

Kafka事务

  • Kafka事务性主要是为了解决幂等性无法跨Partition运作的问题,事务性提供了多个Partition写入的原子性

  • 即写入多个Partition要么全部成功,要么全部失败,不会出现部分成功部分失败这种情况。

  • Flink正是基于Kafka的事务性,实现了端到端的Exactly Once语义

  • Kafka 的事务处理,主要是允许应用可以把消费和生产的 batch 处理(涉及多个 Partition)在一个原子单元内完成,操作要么全部完成、要么全部失败。为了实现这种机制,我们需要应用能提供一个唯一 id,即使故障恢复后也不会改变,这个 id 就是 TransactionnalId(也叫 txn.id,后面会详细讲述),txn.id 可以跟内部的 PID 1:1 分配,它们不同的是 txn.id 是用户提供的,而 PID 是Producer 内部自动生成的(并且故障恢复后这个 PID 会变化),有了 txn.id 这个机制,就可以实现多 partition、跨会话的 EOS 语义。

    • 当用户使用 Kafka 的事务性时,Kafka 可以做到的保证:
      1. 跨会话的幂等性写入:即使中间故障,恢复后依然可以保持幂等性;
      2. 跨会话的事务恢复:如果一个应用实例挂了,启动的下一个实例依然可以保证上一个事务完成(commit 或者 abort);
      3. 跨多个 Topic-Partition 的幂等性写入,Kafka 可以保证跨多个 Topic-Partition 的数据要么全部写入成功,要么全部失败,不会出现中间状态。
    • Consumer 端很难保证一个已经 commit 的事务的所有 msg 都会被消费,有以下几个原因:
      1. 对于 compacted topic,在一个事务中写入的数据可能会被新的值覆盖;
      2. 一个事务内的数据,可能会跨多个 log segment,如果旧的 segmeng 数据由于过期而被清除,那么这个事务的一部分数据就无法被消费到了;
      3. Consumer 在消费时可以通过 seek 机制,随机从一个位置开始消费,这也会导致一个事务内的部分数据无法消费;
      4. Consumer 可能没有订阅这个事务涉及的全部 Partition
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值