【分布式学习】消息中间件(MQ)学习:kafka

社区官网

1,kafka

1)概念

Kafka是一种高吞吐量的分布式发布订阅消息系统,是观察者模式的一种实现。
Kafka是一个分布式消息队列。

2)特点

  1. 高性能
    Kafka是一个高吞吐量的消息队列,可支持每秒处理数以百万计的消息,对于大数据处理和实时数据流分析等场景非常适用。
  2. 数据持久化
    Kafka将消息持久化到磁盘上,并支持数据复制和备份,以确保数据不会丢失。
  3. 多副本备份
    Kafka将数据分成多个分区和副本,并将每个分区副本分布在不同的节点上,以确保系统的容错性和可靠性。
  4. 横向扩展能力
    Kafka具有良好的可扩展性,可以通过增加消息生产者、消费者和Kafka集群节点来实现高性能和高可靠性。

3)场景

1>异步消息处理、解耦

解耦生产者和消费者;消息的阻塞不影响主流程进行。

举例:

  1. 消息系统——缓存消息等。
  2. 实时数据分析:
  • 日志采集;
  • 用户活动跟踪
    记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
  • 运营指标
    Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。

2>削峰填谷(缓存)

数据生产者和消费者之间的速度差异大,高并发场景下平衡系统压力。将峰值压力分散到较长时间段内,同时也提高了低谷期资源利用率。

2,架构(发布订阅模型(Pub-Sub))

请添加图片描述
使用Topic 作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过topic传递给所有的订阅者。在广播之后才订阅的用户不能收到历史消息。

1)Producer(生产者)

向Kafka集群(Broker)中一个或多个topic push消息;

  1. 顺序写磁盘:每条消息都被追加(append)到分区(patition)中;
    顺序写磁盘比随机写内存效率要高,保障kafka吞吐率。

2)Consumer(消费者)

  1. 订阅消息
    消费者可以订阅一个或多个主题(topic),并从Broker拉(pull)相同topic的数据消费。
  2. 提交偏移量(Offset)
    将Offset提交回kafka以保证消息的顺序性和一致性。
  3. Consumer Group(消费者组,CG)是逻辑上的一个订阅者。
    1)每个Consumer都有一个Consumer Group;
    可指定group name,若不指定属于默认的group。
    2)同一Consumer Group,只能有一个Consumer消费partition的消息;
    广播:每个consumer有一个独立的Consumer Group;
    单播:所有的consumer同一个Consumer Group。
    在生产环境中,consumer数量 = 分区数(parition数量)

3)Broker(Kafka实例)

每个节点的kafka实例都是一个代理(Broker)、Kafka实例。
多个 Kafka Broker 组成一个 Kafka Cluster。

1> Controller

角色类似于其他分布式系统Master的角色,负责管理分区状态、broker状态、集群元数据。

2>topic(主题)

承载消息的逻辑容器,本质就是一个目录,而topic是由一些Partition Logs(分区日志)组成。

  1. topic包含一个或多个分区(partition)==》保证了高可用、高吞吐量;
    对应 server.properties 中的num.partitions=3配置;
    生产者循环发送数据给不同的partion,==》保证server负载均衡。
  2. 同一个topic的不同partition存储在不同的broker上;

3>Parition(分区、消息队列):高吞吐量的核心设计。

一个有序不变的消息队列,每个patition物理上对应一个文件夹(存储该patition的所有消息和索引文件)。

  1. 同一个topic的不同partion分布在不同broker上。==》高可用
  2. 消费顺序:
    同一个partition中有序消费;
    但一个topic的整体(多个partition间)消费无序。
  3. 副本(replication)
    每个partition有若干个副本(replication):1个Leader和若干个Follower。server.properties 配置中的 default.replication.factor=N
    Leader负责一切对分区的读写;
    Follower负责同步Leader数据;Leader故障时,Follower通过选举成为新的Leader。
    每个broker都会成为某些分区的leader和follower,因此集群负载是均衡的。
  4. 分区策略&原则:指定了patition,直接使用;未指定按分区策略分区。
    可以通过在生产者配置中设置 partitioner.class 参数来指定使用哪种分区策略。
    1)DefaultPartitioner(默认分区策略)
    根据消息的 key 值进行哈希计算,然后将哈希值与当前 Topic 的 partition 数量取模得出目标分区索引。如果消息的 key 为 null,则使用轮询的方式依次将消息发送到所有分区。
    2)RoundRobinPartitioner(轮询分区策略)
    将消息依次分配到每个 partition。
    3)StickyPartitioner(黏性分区策略)
    将同一个 key 的消息发送到同一个分区,以保证同一个 key 的消息在同一个分区中。如果消息的 key 为 null,则使用类似于 DefaultPartitioner 的方式(即哈希计算)将消息发送到不同的分区中。
    4)自定义分区器
    过滤脏数据,将数据中包含某个特殊字符的发往指定分区。可以实现 org.apache.kafka.clients.producer.Partitioner 接口,并在 partitioner.class 参数中设置自定义分区策略的类名

4>offset(偏移量)

偏移量是一个单调递增的整数,它是 Kafka 为每个partition中的消息分配的唯一标识。在每个topic对应的partition中,消息会按照写入的顺序依次排列,每个消息都会被赋予一个连续的偏移量,以此来标记该消息在分区中的位置。

1>作用

  1. 消息定位:
    消费者可以通过指定偏移量来精确地从分区中读取特定位置的消息。
    比如,消费者可以从某个特定的偏移量开始消费,也可以从最新的偏移量开始,或者从最早的偏移量开始,这为消息的消费提供了极大的灵活性。
  2. 消息消费进度跟踪:消费者会记录自己已经消费到的偏移量,以此来标记消费进度。
    当消费者重启或者重新分配分区时,就能够从之前记录的偏移量处继续消费,避免消息的重复消费或者遗漏消费。
  3. 分区消息管理
    Kafka 会根据偏移量来管理分区内的消息存储。例如,当达到一定的条件(如消息的保留时间、磁盘空间限制等)时,Kafka 会删除旧的消息,而偏移量可以帮助确定哪些消息是可以被删除的(复杂度为O(1))。
    有两种策略可以删除旧数据:
    1)基于时间:log.retention.hours=168
    2)基于大小:log.retention.bytes=1073741824

2>存储

  • 格式:kafka的存储文件都是按照offset.kafka来命名;
    用offset做名字的好处是方便查找。例如查询位于2049的位置,只要找到2048.kafka的文件即可。the first offset是00000000000.kafka
  • 位置:
    旧版本(Kafka 0.9 之前):消费者的偏移量信息存储在 zk中。
    新版本(Kafka 0.9 及以后):消费者的偏移量信息存储在 Kafka 内部的一个特殊主题 __consumer_offsets 中。
    将偏移量存储在 Kafka 自身中,利用了 Kafka 高吞吐量的特性,大大提高了偏移量读写的性能。

5>数据清理

3,原理

1)kafka高性能原理

1>消息发送

  1. 批量发送;
    将多个消息打包成一个批次发送,减少了网络传输和磁盘写入的次数。
  2. 消息压缩
    提高io效率。
  3. 异步发送;
  4. 并行发送;
    数据分布在不同的分区(Partitions)中,生产者可以并行发送数据。

2>消息存储

  1. 零拷贝读写数据
    直接从网卡读写数据。在内核中读取文件并发送,不需要用户态和内核态的切换。
  2. 磁盘顺序写入
    同partition有序,批量顺序写入磁盘,节省了磁盘寻址时间、减少写入次数。
    同时partition分为多个segment存储,方便删除(直接删除segment)。
    数据存储在磁盘,保证数据的可靠性、提高数据堆积能力。
  3. 页缓存(pageCache)
    每次访问数据时,将数据加载到页存(而不是jvm的堆内存),如果生产消费速度相同,数据会直接通过pageCache交互数据,不需要经过磁盘IO。
  4. 稀疏索引
    kafka存储消息用分段的日志文件,每个分段都有索引文件,这个文件每隔一定数量的消息才创建一个索引点。
    这样的稀疏索引减小了索引体积,提高了加载效率。
    数据结构:Bitmap Index(位图索引),存储偏移量是否有数据。
  5. 分区和副本
    数据分散到多个节点进行处理,从而实现了分布式的高可用性和负载均衡。

3>消息消费

  1. 消费组
    实现了消息的负载均衡和容错处理。
  2. 并行消费
    不同消费者独立消费不同的分区,并行消费。
  3. 批量拉取
    可以一次拉取多个消息进行消费。减少网络消耗。

2)如何保证消息不丢失?

消息发送过程:

  1. Producer发送消息给broker;
  2. broker同步消息并持久化数据;
  3. consumer从broker消费(pull)

目前kafka默认消息交付保证at least once,消息不丢但是会重复传递,要做好接口的幂等性校验。

1>producer解决方式

  1. 设置ack(消息回复确认数量),ack配置越高,越可靠、吞吐量越低;重试次数retries>1;
ack取值 说明
0 发送出去不接受确认信息,消息丢失无感知
1 只要leader回复确认信息即可
all或者-1 代表kafka集群必须全部回复确认信息
  1. unclean.leader.election.enable=false 不允许选举OSR作为leader。
    由于OSR (Out-of-Sync Replied,滞后过多的副本)本身就数据不全,如果leader rash后,ISR (In Sync Replicas,与leader保持一定程度同步的副本)中没有follower,就会从OSR中选举leader。

AR (Assigned Replicas,分区中的副本)

AR = ISR + OSR:正常情况下,所有的follower副本都应该与leader 副本保持 一定程度的同步,即AR=ISR,OSR集合为空。

  1. 设置min.insync.replicas > 1
    副本指定必须确认写操作成功的最小副本数量,值越大越可靠;相当于ISR副本的数量。
    如果不能满足生产者会直接抛异常。只有ack=-1或者all时这个参数才生效。
  2. 失败的offset单独记录
    放入db或者缓存,异常恢复后可单独处理恢复。

2>consumer解决方式

  1. 先处理消息再commit。
    不容易丢数据,但是可能导致数据重复消费问题。==》保持接口的幂等性可以处理此类问题。
  2. 保存offset,成功后才更新偏移量。

3>broker的刷盘去解决问题

  1. 提高刷盘频率
    数据发送到broker后是先保存在缓存中,后面再刷硬盘里。

3)如何避免重复消费?

比起丢数据,重复消费数据问题更小。客户端在接受kafka数据时注意建立幂等机制。

4)pull方式消费消息的优缺点

consumer采用pull(拉)模式从broker中读取数据。

1>优点

  1. 控制消费速率;
    相比起来,push模式很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。从而导致消息堆积引起网络堵塞和消费者拒绝服务。
  2. 可以批量拉取,也可以单条拉取。
  3. 可以设置不同的提交方式,实现不同的传输语义。
    三种方式:至少一次、最多一次、精准一次。

2>缺点

  1. 如果kafka没有数据,导致consumer空循环,消耗资源。
    解决方式:
    通过参数配置,consumer拉取数据为空或者没有达到一定数量时进行阻塞。==》等待数据量到了指定的字节数,以确保大的传输大小。

5)ZK作用

kafka前期版本用来管理kafka集群、数据存储。
kafka2.8开始引入KRaft协议,逐渐减少对zk的依赖;4.0版本不再支持zk模式。

有一些信息存在zookeeper中
1.记录服务器节点运行的状态
2.记录leader相关信息

1>zk模式kafka:push模式

  1. 每个broker都可以做controller角色,谁先在zk注册谁就是controller 节点。
    controller 会在zk建立一个临时节点。
  2. 其它broker节点watch /controller znode节点,如果掉线旧重新注册。
  3. controller节点会从zk中拉取当前集群所有的元数据信息,然后推送给集群里面所有的kafka 分区,分区会自动存储数据到磁盘,并异步传输到消费者。
    可能会导致大量无效或重复的消息。
    zk节点说明:
节点 功能 原理
/brokers/ids 注册broker,保存broker信息:物理地址、版本、启动时间 在zk中创建临时节点,broker会发心跳给zk
/brokers/topics 注册topic,保存topic信息。
每个topic节点下包含一个partitions节点;
每个partitions节点下由保存了一个state节点;
state保存着当前leader分区和ISR的brokerID,同时维护ISR列表。
zk中创建的临时节点
/consumers/[group_id]/owners/[topic]/[broker_id-partition_id] 维护消费者和分区的注册关系,保存消费者组消费的是哪个partition zk中临时节点。如果消费者有挂掉,zk进行剔除并重新分区。
/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id] 分区消息的消费进度offset

2>KRaft模式:pull模式

把集群中节点进行划分,有controller 和 broker 两种角色。

  1. controller 角色节点
    内部组成一个由KRaft 协议(Kafka基于Raft 协议改造过的协议)构成的逻辑集群,统筹管理集群里面的状态信息。
    一般为奇数台。
  2. broker角色节点
    从controller 节点同步拉取集群状态信息到本地进行重放,从而完成整个集群的统一管理。
    可以从1-N 扩展。
  3. offset
    消费者维护,表示已经消费的消息序号,当消费者拉取消息时,kafka会返回未消费的消息。避免发送大量无效或重复的消息,减少资源的浪费。

新版本数据的存储:

数据 存储位置
offset 存放在一个专门的topic中的partition里

3>Kafka 不依赖zk的优点:

  1. 支持更多的分区、更高的性能
    Kafka 集群规模不再受限制,Zookeeper 模式下单集群在百万topic 级别下会遇到性能瓶颈,主要是受限于跟ZK 交互。
  2. 更快速地切换controller,提高集群重启恢复速度。
    以前要从Zookeeper 拉数据,如果partitions 总量很大,这个恢复过程会很长。
  3. 可以避免Controller缓存的元数据和zk存储的数据不一致带来的一系列问题。
  4. 更少的依赖,简化Kafka 部署
    无需其他组件即可提供服务

6)rebalance机制(重平衡机制)

使用kafka的消息量很大的情况下,容易出现rebalance。rebalance期间partition的读写阻塞,降低rebalance次数,能提高性能。

1>概念

消费者组下的消费者与topic下的partition重新匹配的过程。
目的:实现消费者的负载均衡和高可用性。

2>场景

  1. 增加或删除broker
    需要重新调整消费者和partition的分配。
  2. 增加或删除consumer
  3. consumer消费超时(可能挂了)
    对应的partition没法消费,需要重新调整。
    ==》设置消费超时阈值
  4. group订阅的topic数目变化。
    ==》业务低峰期做topic\partition的变化操作。
  5. gourp订阅的分区数变化。
    ==》同3

3>触发条件

  1. 消费者组成员数量发生变化;
  2. 订阅主题数量发生变化;
  3. 订阅主题的分区数发生变化。

4>步骤

  1. 暂停消费
    确保不会出现消息丢失或者重复消费。
  2. 计算分区分配方案
    根据consumer group、consumer、topic的partition数量,计算每个consumer应该分配的partition,实现分区负载均衡。
  3. 通知消费者
    一旦分区分配方案确定,发送每个消费者可消费的分区列表,邀请他们加入消费组。
  4. 重新分配分区
    设置broker分区方案:重新分配topic的partition给各个消费者。
  5. 恢复消费

5>coordinator机制

针对场景1和2,是由coordinator(协调者)进行rebalance的。
coordinator一般是leader节点所在的broker,通过心跳监测consumer是否超时。具体步骤:

  1. coordinator心跳监测出有异常,心跳通知所有consumer进行rebalance;
  2. consumer请求coordinator加入消费组,coordinator选举产生leader consumer(不是主从的概念,而是有更多的责任)。
  3. leader consumer从coordinator获取所有的可用consumer,发送syncGroup(consumer和partition的分配信息)给到coordinator
  4. coordinator通过心跳机制分发syncGroup给所有的consumer。

针对场景3和4,由于topic和partition的变更broker无法感知,coordinator也就无法感知。由leader consumer监控topic变化,通知coordinator进行rebalance。

rebalance导致的重复消费问题:
consumer1宕掉之后,消费了一半的消息没有提交offset;rebalance之后进行了二次消费。此时consumer1恢复后进行了重复消费。
解决方案:
每次rebalance时标记Generation,rebalance成功后+1,consumer1再次提交offset时发现Generation值不同,则拒绝提交。

7)生产者原理(异步发送)

整个生产者客户端由两个线程协调工作,分别为主线程和Sender线程。
请添加图片描述

1>主线程

由KafkaProducer创建消息,然后会依次经过拦截器、序列化器、分区器,然后缓存到RecordAccumulator。

2>Sender线程

负责从RecordAccumulator中获取消息,然后发送给Kafka集群。

3>RecordAccumulator(消息累加器)

  1. 缓存消息
    RecordAccumulator主要用来缓存消息,以便sender线程能批量发送。这个缓存通过客户端参数buffer.memory来配置大小,默认为32MB。
  2. 双端队列(Deque)
    主线程过来的消息会被追加<分区,Deque<ProducerBatch>>中(对应分区号)。
    每一个partition在一个broker上存储,可以把海量数据切割成一块一块数据存储在多台broker上。合理控制分区的任务,可以实现负载均衡的效果。同时提高并行度:生产者可以以分区为单位发送数据,消费者可以以分区为单位消费数据。
    双端队列满了之后数据怎么处理&#x
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值