回顾Kafka

1.是什么?

Kafka是一个分布式、支持分区、多副本的,基于zookeeper协调的分布式消息中间件

2 使用场景

核心的场景、原因有 3 个:解耦、异步、削峰。

具体:

  • 日志收集
  • 消息系统:解耦和生产者和消费者、缓存消息等。
  • 用户活动跟踪:用户的各种活动,如浏览、搜索、点击等活动,发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
  • 运营指标:包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。

3.基本概念术语

名称解释
Broker一个Kafka节点即是一个broker,一个或者多个Broker可以组成一个Kafka集群
TopicKafka根据topic对消息进行归类,发布到Kafka集群的每条消息都需要指定一个topic
Producer消息生产者,向Broker发送消息的客户端
Consumer消息消费者,从Broker读取消息的客户端
ConsumerGroup每个Consumer属于一个特定的Consumer Group,一条消息可以被多个不同的Consumer Group消费,但是一个Consumer Group中只能有一个Consumer能够消费该消息
Partition物理上的概念,一个topic可以分为多个partition,每个partition内部消息是有序的
offsetpartition中的消息的唯一的编号
ControllerKafka集群中会有一个或者多个broker,其中有一个broker会被选举为控制器(Kafka Controller),它负责管理整个集群中所有分区和副本的状态。
leaderleader和follower是针对partition,而controller是针对broker的,leader 负责partition的所有读写请求,其它follewer只接收leader同步来的数据
  • replicas 表示某个partition在哪几个broker上存在备份。不管这个几点是不是”leader“,甚至这个节点挂了,也会列出。
  • isr 是replicas的一个子集,它只列出当前还存活着的,并且已同步备份leader一定程度(时间参数)partition的节点。
  • LEO:每个分区的当前最大offset+1,即下一条待写入消息的offset
  • HW:多个partition中最小的LEO(log-end-offset)即HW

producer通过网络发送消息到Kafka集群,然后consumer来进行消费。

服务端(brokers)和客户端(producer、consumer)之间通信通过TCP协议来完成。

4.术语详解

Topic是Kafka对消息进行分类的一个概念,同类消息发送到同一个Topic下面。

对于每一个Topic,下面可以有多个分区(Partition)日志文件:

0

Partition是有序的message序列每个partition,都对应一个commit log文件

message按顺序添加到一个叫做commit log的文件中。

每个partition中的消息都有一个唯一的编号,称之为offset,用来唯一标示某个分区中的message。 +

kafka一般不会删除消息,不管这些消息有没有被消费。只会根据配置的日志保留时间(log.retention.hours)确认消息多久被删除,默认保留最近一周的日志消息。

kafka中,消费offset由consumer自己来维护;一般情况下我们按照顺序逐条消费commit log中的消息

5.为什么要对Topic下数据进行分区存储?

1、commit log文件会受到所在机器的文件系统大小的限制,分区之后可以将不同的分区放在不同的机器上,相当于对数据做了分布式存储,理论上一个topic可以处理任意数量的数据。

2、为了提高并行度

7. Kafka服务端概念

查看下topic的情况

输入命令: bin/kafka-topics.sh --describe --zookeeper 192.168.65.60:2181 --topic test1 ,

https://note.youdao.com/yws/public/resource/e5863162eca29c2b31e8b59c9707817d/xmlnote/1EA065B2BCE342B99C67487DB06D8E4A/105167

然后会显示几个概念

  • leader的那个broker节点负责partition的所有读写请求。
  • replicas 表示某个partition在哪几个broker上存在备份。不管这个几点是不是”leader“,甚至这个节点挂了,也会列出。
  • isr 是replicas的一个子集,它只列出当前还存活着的,并且已同步备份了该partition的节点。

6.消息生产

kafka生产端可以设置多个参数,来调整不同发送策略
(1)acks=0: 表示producer不需要等待任何broker确认收到消息的回复,就可以继续发送下一条消息。性能最高,但是最容易丢消息。
(2)acks=1: 至少要等待leader已经成功将数据写入本地log,但是不需要等待所有follower是否成功写入。就可以继续发送下一条消息。这种情况下,如果follower没有成功备份数据,而此时leader又挂掉,则消息会丢失。
(3)acks=-1或all: 需要等待 min.insync.replicas(默认为1,推荐配置大于等于2) 这个参数配置的副本个数都成功写入日志,这种策略会保证只要有一个备份存活就不会丢失数据。这是最强的数据保证。一般除非是金融级别,或跟钱打交道的场景才会使用这种配置。

HW与LEO详解

  • LEO:每个分区的当前最大offset+1,即下一条待写入消息的offset
  • HW:多个partition副本中最小的LEO(log-end-offset)即HW

新写入的消息,consumer不能立刻消费,leader会等待该消息被所有ISR中的replicas同步后更新HW,此时消息才能被consumer消费。

当producer生产消息至broker后,ISR以及HW和LEO的流转过程:
在这里插入图片描述

7.消息消费

7.1 消费示意图

0

上图说明:由2个broker组成的kafka集群,某个主题总共有4个partition(P0-P3),分别位于不同的broker上。这个集群由2个Consumer Group消费, A有2个consumer instances ,B有4个。

通常一个topic会有几个consumer group,每个consumer group都是一个逻辑上的订阅者( logical subscriber )。每个consumer group由多个consumer instance组成,从而达到可扩展和容灾的功能。

7.2 消费顺序

一个partition同一个时刻在一个consumer group中只能有一个consumer instance在消费,从而保证消费顺序。消费者数量大于分区数,将会有消费者分不到消费的机会。

7.3 offset记录机制

consumer定期将自己消费分区的offset提交给kafka内部topic:__consumer_offsets

提交时,key是consumerGroupId+topic+分区号,value就是当前offset的值。

__consumer_offsets默认给其分配50个分区,抗并发,kafka会定期清理topic里的消息,最后就保留最新的那条数据

10.Rebalance机制

消费组里的消费者数量有变化或消费的分区数有变化,kafka重新分配消费者与消费分区关系的过程。

10.1 触发rebalance情况:

1.消费组里的consumer增加或减少了
2.动态给topic增加了分区
3.消费组订阅了更多的topic

rebalance过程中,对kafka的TPS会有影响,如果节点较多,重平衡可能会耗时极多,所以应尽量避免在系统高峰期的重平衡发生。

10.2 Rebalance分区分配策略

策略:range、round-robin、sticky。默认情况为range分配策略。

range策略就是按照分区序号排序

round-robin策略就是轮询分配,比如分区0、3、6、9给一个consumer,分区1、4、7给一个consumer,分区2、5、8给一个consumer

sticky与round-robin类似,但在rebalance的时候,需要保证如下两个原则。
1)分区的分配要尽可能均匀。
2)分区的分配尽可能与上次分配的保持相同。

10.3 Rebalance过程(个人方便理解)

1.在kafka的broker集群里选个负责人(仅是消费组维度的)
2.kafka负责人 选择消费组里哪个实例是消费组负责人

两方负责人选好后,正式开始:

3.消费组负责人负责制定新的分区方案,并同步给kafka负责人
4.由kafka负责人同步给所有消费组的消费者,rebalance完成

疑问:

1.kafka负责人怎么选举出来的?

consumer消费的offset要提交到__consumer_offsets的某个分区,那这个分区leader对应的broker就当Rebalance时的kafka负责人

2.消费组负责人怎么选举出来的?

第一个和kafka负责人连上的消费实例就是

8.Kafka核心总控制器Controller

8.1概念

Kafka集群会有一个或者多个broker,其中有一个broker会被选举为控制器(Kafka Controller),它负责管理整个集群中所有分区和副本的状态。

1.当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。
2.当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。
3.当使用kafka-topics.sh脚本为某个topic增加分区数量时,同样还是由控制器负责让新分区被其他节点感知到。

Controller选举机制

正常时候:

每个broker尝试在zookeeper上创建一个 /controller 临时节点,zookeeper保证有且仅有一个broker能创建成功,这个broker就会成为集群的总控器controller。

宕机时候:

当这个controller角色的broker宕机了,此时zookeeper临时节点会消失,集群里其他broker会一直监听这个临时节点,发现临时节点消失了,就竞争再次创建临时节点

9.Partition副本选举Leader机制

controller感知到分区leader所在的broker挂了(controller监听了很多zk节点可以感知到broker存活),controller会从ISR列表里挑第一个broker作为leader

10.Kafka文件存储

日志分段存储

一个分区的消息数据对应一个文件夹,以topic名称+分区号命名。

文件夹下有三类文件,xx.index、xx.log、xx.timeindex,如下:

00000000000000000000.index(offset索引)
如果要按消息offset找消息,会先在这个文件里快速定位,再去log文件里找具体消息

00000000000000000000.log(存offset和消息体本身)
消息存储文件,主要存offset和消息体

00000000000000000000.timeindex(时间索引)
如果需要按照时间来定位消息的offset,会先在这个文件里查找

消息分段(segment)存储,每个段的消息都存储在不一样的log文件里,这种特性方便old segment file快速被删除,

规定一个段位的 log 文件最大为 1G,做这个限制目的是方便把 log 文件加载到内存操作

11.kafka事务

Kafka的事务不同于Rocketmq,Rocketmq是保障本地事务(比如数据库)与mq消息发送的事务一致性,Kafka的事务主要是保障一次发送多条消息的事务一致性(要么同时成功要么同时失败)

比如,kafka需要对一个topic里的消息做不同的流式计算处理,处理完分别发到不同的topic里,这些topic分别被不同的下游系统消费(比如hbase,redis,es等),这种我们肯定希望系统发送到多个topic的数据保持事务一致性。Kafka要实现类似Rocketmq的分布式事务需要额外开发功能

12.kafka高性能的原因

1.磁盘顺序读写:

kafka消息不能修改以及不会从文件中间删除保证了磁盘顺序读,kafka的消息写入文件都是追加在文件末尾,不会写入文件中的某个位置(随机写)保证了磁盘顺序写。
在这里插入图片描述
磁盘结构上面这样,如果顺序写就不用频繁切换磁头位置,写完接着写就行

mysql因为经常需要随机删/修改数据等,造成数据必然不是连续,就会需要找位置然后才能读写,这样就是随机写

2.数据传输的零拷贝

数据传输零拷贝原理:
在这里插入图片描述
正常步骤:磁盘=》内核读取缓冲区=》用户缓冲区=》socket缓冲区=》网卡
零拷贝步骤:内核读取缓冲区=》网卡,即读取到内核后 直接操作内核缓冲区输出到网卡,同时这样也少了上下文切换+复制开销

3.读写数据的批量batch处理以及压缩传输

13.项目&线上问题

线上环境规划(可结合笔者链路追踪项目,基本差不多)

在这里插入图片描述

1 消息丢失

消息发送端:

(1)acks=0: 表示producer不需要等待任何broker确认收到消息的回复,就可以继续发送下一条消息。性能最高,但是最容易丢消息。

(2)acks=1: 这种情况下,如果follower没有成功备份数据,而此时leader又挂掉,则消息会丢失。

(3)acks=-1或all: 最强的数据保证。一般除非是金融级别,才会使用这种配置。当然如果min.insync.replicas配置的是1则也可能丢消息,跟acks=1情况类似。

消息消费端:

原因:还没处理完,就自动提交offset了,但是此时你consumer直接宕机了,未处理完的数据丢失了,下次也消费不到了。
解决方案:手动提交

2 重复消费

消息发送端:

配置了重试机制,比如网络抖动时间过长导致发送端发送超时,实际broker可能已经接收到消息,但发送方会重新发送消息

消息消费端:

如果消费这边配置的是自动提交,刚拉取了一批数据处理了一部分,但还没来得及提交,服务挂了,下次重启又会拉取相同的一批数据重复处理

解决方案:

一般消费端都是要做消费幂等处理的

3 消息乱序

原因:

如 发送了1,2,3条消息,第一条超时了,后面两条发送成功,再重试发送第1条消息,这时消息在broker端的顺序就是2,3,1了

是否一定要配置重试要根据业务情况而定

解决方案

1.从发送端开始,将所有有序消息发送到同一个分区,然后用一个消费者去消费,但是这种性能比较低

2.可以在消费者端接收到消息后将需要保证顺序消费的几条消费发到内存队列(可以搞多个),开启一个线程顺序处理同一批就位的内存队列消息

4 消息积压

第一种
原因:

线上有时因为发送方发送消息速度过快,或者消费方处理消息过慢,可能会导致broker积压大量未消费消息。

解决方案:

可以修改消费端程序,让其将收到的消息快速转发到其他topic(可以设置很多分区),然后再启动多个消费者同时消费新主题的不同分区。

因为1比1后单纯加消费者是没用的,而且会造成rebalance

第二种
原因:

程序有bug,导致消费者一直消费不成功,导致broker积压大量未消费消息

解决方案

可以将消费不成功的消息转发到其它队列里去(类似死信队列),后面再慢慢分析死信队列里的消息处理问题。

5、延时队列

场景

1)订单系统: 30 分钟之内没有支付成功,那么这个订单将进行异常处理,
2)订单完成1小时后通知用户进行评价。

实现思路:

1.把消息按照不同的延迟时间段发送到指定的队列
(topic_1s,topic_5s,topic_10s,…topic_2h),

2.定时器进行轮训消费这些topic,查看消息是否到期,如果到期就把这个消息发送到具体业务处理的topic中

队列中消息越靠前的到期时间越早,具体来说就是定时器在一次消费过程中,对消息的发送时间做判断,看下是否延迟到对应时间了,如果到了就转发,如果还没到这一次定时任务就可以提前结束了。

6、消息回溯

可以用consumer的offsetsForTimes、seek等方法指定从某个offset偏移的消息开始消费

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值