【重难点整理】通过kafka的全过程叙述kafka的原理、特性及常见问题

一、kafka的实现原理

1、逻辑结构

2、组成

生产者:生产消息,来自服务、客户端、端口……

消息本身:消息主体

topic主题:对消息的分类,例如数仓不同层中的不同类型数据(订单、用户……);自带__consumer_offsets的topic,以k-v形式保存CG-topic-partition下的位移

partition分区:Topic 的分区(同一topic由多个分区组成,每个分区的内容不同,怎么划分???),表现形式为一个文件夹,用作kafka负载,提高其吞吐量

Replication:表示分区的副本,即follower节点,用于leader宕机时进行选主;副本数量<=集群中节点个数<=10

Cluster集群:

broker节点:Kafka 实例,表示一台机器,broker0、broker1、broker2表示节点编号

Consumer Group消费者组:(一个消费者组消费一个topic)同一个消费者组的消费者可以消费同一个 Topic 的不同分区的数据,用于提高吞吐量;同一个分区的数据只能被消费者组中的某一个消费者消费

消费者:(一个消费者消费一个分区)消息的出口,例如一个服务、一个数据库、hdfs、kafka……(怎么分配partition到消费者:range和roundroubin?)

offset偏移量:消费者提交offset表示消息读取的位置,自带__consumer_offsets的topic,以k-v形式保存CG-topic-partition下的位移

zookeeper:保存集群的元信息,保证kafka的高可用性

3、发送消息

集群中返回leader

将消息以push模式发给leader

消息被追加到指定分区(顺序写),保证同一分区内的数据顺序有序

如何确定消息发送到topic的哪个分区?
1、指定partition
2、未指定partition但指定了key,对数据的key进行哈希选出partition
3、既未指定partition也未指定key,则以轮训方式确定partition

另外:如果指定的topic不存在,那么会自动创建1分区1副本的topic

leader收到消息后发送ack给生产者,保证可靠发送【默认ack=?】

如何保证消息发送时不丢失/如何保证消息被可靠发送?-ack机制
生产者向队列中写入数据时确定kafka是否接收到数据,参数值为0,1,all
0表示无需等待集群返回,不确保消息发送成功
1表示只需要leader应答存盘,就可以发送下一条
all表示leader应答+followers同步完成,才会发送下一条数据

leader将消息持久化

followers从leader上pull消息进行同步

follower持久化消息后向leader发送ack

4、数据落盘

kafka将数据存盘,单独划分一块区域,进行顺序写(比随机写拥有更高的效率)

partition以文件夹形式存储,对partition进行分段存储:partition/segment/(最小的offset.index,log,timeindex )

利用分段+索引的方式解决查找效率的问题

使用log文件存储message,消息的组成?
消息主要包含Offset(8字节,确定消息在partition中的位置)、消息大小(4字节byte)、消息体(被压缩后的实际数据)、压缩类型

旧消息会进行删除

旧消息删除策略/消息保存多久?
基于时间,默认配置是 168 小时(7 天)。
基于大小,默认配置是 1073741824。
读取的复杂度是O(1),因此,删除文件不会提高kafka的性能

5、消费数据

 消费者点对点拉取pull数据

一个消费者组消费同一个topic

一个组内的消费者消费不同的partition【一个消费者能消费多个partition,但是一个partition不能被多个消费者消费】(建议消费者数目=分区数)

消费者利用Segment+Offset在leader所在的partition中共同查找消息(二分找segment、打开index文件、稀疏索引确定其相对偏移量、顺序查找确定其位置)

消费者如何记录读取的偏移量?
早期使用zk,每隔一段时间就需要上报一次,容易导致重复消费且性能较差
新版本使用__consumer_offsets这个topic维护消费者消费某个分区的偏移量

二、kafka如何保证可靠消费

1、手动提交offset

enable.auto.commit设置为false,如果自动提交可能会未被消费就提交,从而导致消息丢失

2、降低重复消费的概率

开启自动提交并设置auto.commit.interval.ms时长

默认值是每5秒钟提交一次

设置的时间短一点,频繁提交会增加额外的开销,但也会降低重复处理消息的概率

3、配置auto.offset.reset

当请求的偏移量不存在时,配置auto.offset.reset

使用earliest会产生重复数据,但可以避免数据丢失

使用latest,减少重复消费,但可能会丢失数据

4、依靠at-least once+kafka的幂等性,借助第三方系统

使用键值对数据库存储唯一key,消息作为value

三、kafka如何保证exactly once

1、at-least once+幂等性实现

2、自身实现

exactly-once定义为: 不管在处理的时候是否有错误发生,计算的结果(包括所有所改变的状态)都一样。

(1)消息生产者提交数据到broker,开启幂等性,即修改配置文件:enable.idempotence=true 同时要求 ack=all 且 retries>1
(2)broker进行消息处理,将模式“消息读入->消息处理->结果写出”作为事务操作

默认情况下kafka的事务是关闭的,通过配置文件开启,需要
transactional.id=“unique-id”, 要求enable.idempotence=true.

开启事务后,配置启动exactly-once:processing.guarantee="exactly-once ", 默认是最少一次。

(3)消费者消费数据,只读取已经标记为“成功提交”的数据,避免消费到脏数据

配置为isolation.level=“read_committed”。默认是read_uncommitted

 

posted @ 2022-03-02 10:51  哥们要飞  阅读(126)  评论(0编辑  收藏  举报