kafka

1.kafka是什么

    消息中间件(消息队列),本质可以理解为是一个队列,实现进程间消息的承载,传递,而且是为大数据场景开发设计的一款中间件。本身就支持分布式和集群,是一款分布式消息发布和订阅系统

2.进程内队列和进程间队列的区别

进程内的队列(queue):

(1)一定是有序的,先进先出

(2)而且不需要考虑跨语言(进程内用的一定是同一个语言)

(3)消息一般不持久化(存在内存)

(4)不需要网络传递(通过内存共享信息)

(5)消息可控制不会重发和重复消费

进程间消息队列(kafka):

(1)可以保证消息的局部有序,如果是单分区,则可以保证全局有序(从发送方的角度考虑)

(2)跨语言->传输层协议需要使用通用协议, 也就是序列化,反序列化需要使用通用协议,比如json,bson,protobuf等

(3)消息做了持久化->存磁盘(可设置超时时间,默认7天)

(4)消息需要网络传递,这也是为啥需要序列化和反序列化的原因

(5)可做到消息不会重发和重复消费

(6)会存在丢消息的问题

3.消息队列使用场景

1.对实时性要求不高的场景(解耦)

2.上下游处理能力不对等的场景(防止下游崩溃,限流(削峰))

4.消息队列获取数据的三种模型

(1)Push模型

服务端主动发送数据给客户端。在服务端收到消息之后立即推送给客户端

优点:实时性好,服务器已有数据就给消费者推送,而且消费者不需要空转轮询队列是否有数据

缺点:

 1):在Broker端需要维护Consumer的状态,不利于Broker去支持大量的Consumer的场景

 2):Consumer的消费速度是不一致的,由Broker进行推送难以处理不同的Consumer的状况

 3):Broker难以处理Consumer无法消费消息的情况(Broker无法确定Consumer的故障是短暂的还是永久的)

(2)Poll模型

由Consumer主动从Broker获取消息

优点:

1)在Broker端不需要维护Consumer的状态

2)可以自己觉定消费速度

缺点:

1)实时性

2)如果消息队列里面大部分时间没有数据,消费者的cpu可能会做无意义的空转

(3)Long-Polling

    长轮询模式,在Poll模型的一个变种,可以防止CPU空转。Consumer主动发起请求到Broker,正常情况下Broker响应消息给Consumer;在没有消息或者其他一些特殊场景下,可以将请求阻塞在服务端延迟返回

优点:

1)在Broker一直有可读消息的情况下,long-polling就等价于执行间隔为0的pull模式(每次收到Pull结果就发起下一次Pull请求)。

2)在Broker没有可读消息的情况下,请求阻塞在了Broker,在产生下一条消息或者请求“超时之前”响应请求给Consumer

5.kafka的结构

(1)数据结构

kafka是一个发布订阅的分布式消息系统,发布和订阅的东西,kafka用主题(topic)来表示

(2)集群结构

我们说了kafka本身是为了大数据,分布式开发的一款中间件,本身支持集群

 (3)集群结构-partitions

    按照(2)的结构,如果把主题的信息都存在服务器broker0里面,大数据场景下必定会因为触发服务器的硬件瓶颈(宽带,cpu,磁盘IO)等。联想mongo,es的数据分片,kafka采用了一个类似的策略,术语叫分区(partitions),创建主题的时候可以选择分区的数量(比如2),就是把topic1里面的消息尽量均分到不同的分区里面

 (4)集群结构-复制因子

  按照(3)的结构存在一个问题,当broker0的机子宕机后,topic1在p0分区的消息会丢失

为了解决这个问题,需要做数据备份。类似mongo的主从部署,kafka引入了个术语,复制因子

,其实就是数据做多少备份(不能超过broker数量),以达到容灾的目的。假设topic1这个主题,需要创建两个分区,复制因子为2(尽量均分算法)

(5)集群结构-复制因子之leader(follow)

当主题的每个分区都有了备份,防止消息被重复消费,意味着同一个分区的多个备份只能有一个作为主分区,其他的都是从分区,也就是有leader 和follow(leader的选举是通过zookeeper来完成得)

规则:分区所在的所有broker里面,borker id最小的分区成为leader分区,复制该分区的读写操作

 

6.kafka消息布局及生产者,消费者

(1)生产者及消息布局(为啥是局部有序,也就是分区有序)

 kafka消息做了持久化->存磁盘(可设置超时时间,默认7天),而且可支持多方的发布订阅,对于同一个主题,可以存着多个订阅者,每个订阅者消费速度,及消费到的消息位置是不一样的,需求记录每一个订阅者消费到的位置。因此kafka对每一个topic的每一个分区的消息做了编号,从0开始,递增+1,术语叫offset(偏移量)

 (2)消费者及订阅群

 什么是订阅群:假设A服务,B服务都订阅了topic1的消息(假设消息是用户id),A服务获取消息给用户做信息推荐,B获取消息是给用户发放激励信息,A和B都需要获取消息,但是获取消息后做的事情是不一样的,那么A,B就是两个消费群

什么是消费者:假设目前A服务目前开启了一个线程(t1)去获取topic1的消息并做处理,这个t1就是具体消费信息干事的人,这个t1可以理解为消费者。当A服务嫌弃一个线程消费太慢的时候,开了5个线程去消费,这五个线程就是五个消费者

服务A开启了5个现在消费《==》订阅群A里面有5个消费者

 kafka如何实现订阅者的概念:消费者组,也就是每个消费者可以添加一个消费者组标识,相同组标识的消费者视为同一个订阅者的不同消费者

(3)偏移量存放地方

每个消费者(订阅者)需要知道自己消费到哪里了(也就是offset),需要有一个地方记录偏移量,这个偏移量可以存着哪里?

 1)kafka服务端

    如果存在kafka服务端,消费者每次消费都需要询问一次kafka服务端,而且kafka消息发送给了消费者,也不代表消息者确实把消息消费完了(消费者所在的服务器宕机)

 2)消费者

    消息存放在消费者,消费者服务全崩溃了怎么办,消费者服务重启的时候怎么知道自己消费的偏移量

综上所述,kafka在服务器端,和消费者端都存储了偏移量,消费者消费的时候已自身的消费偏移量为准,在一定的周期(每隔1s)上报kafka自己的消费进度,kafka也会存储一份消费者的消费偏移量

(4)消费者如何消费

(1)可以指定分区消费,存在弊端,消费者挂了,这个分区的数据就没人消费了

(2)也可以利用kafka和订阅者自动协调消费,当分区数发生变化,或者订阅者的某个消费者挂了,自动reblance,也就是消费者级别的重负载均衡

方案(2)各种消费者消费场景

 1)假设主题t1现在有三个分区,订阅者A只有一个消费者

2)假设主题t1现在有三个分区,订阅者A只有2个消费者

 看起来是分配不均匀的,因为有一个customer1需要消费两个分区,一个消费者只能消费一个分区

能不能是下面这种方式:

   

 就是两个消费者都消费一个半分区,但是因为kafka的设计导致这种分配方式有问题,我们都知道每个消费者都会保存自己消费的分区的偏移量,当一个组的两个消费者同时消费一个分区的时候,必然存在重复消费

3)假设主题t1现在有三个分区,订阅者A只有3个消费者

 4)假设主题t1现在有三个分区,订阅者A有4个消费者

 (5)分区分配策略(分区如何分配给指定的消费者消费)

  1)Range(默认,订阅了多个主题的场景会导致前面的消费者过载)

RangeAssignor(范围分区)
假设n = 一个topic分区数/消费者数量
m= 一个topic分区数%消费者数量
那么前m个消费者每个分配n+l个分区,后面的(消费者数量-m)个消费者每个分配n个分区

假设我们有10个分区,3个消费者,排完序的分区将会是0, 1, 2, 3, 4, 5, 6, 7, 8, 9;消费者线程排完序将
会是C1-0, C2-0, C3-0。然后将partitions的个数除于消费者线程的总数来决定每个消费者线程消费几个
分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。在我们的例子里面,我们有10个分
区,3个消费者线程, 10 / 3 = 3,而且除不尽,那么消费者线程 C1-0 将会多消费一个分区
的结果看起来是这样的:
C1-0 将消费 0, 1, 2, 3 分区
C2-0 将消费 4, 5, 6 分区
C3-0 将消费 7, 8, 9 分区

2)RoundRobin

RoundRobinAssignor(轮询分区)

轮询分区策略是把所有topic的partition和所有consumer线程都列出来,然后按照hashcode进行排序。最后通
过轮询算法分配partition给消费线程。如果所有consumer实例的订阅是相同的,那么partition会均匀
分布。
在我们的例子里面,假如按照 hashCode 排序完的topic-partitions组依次为T1-5, T1-3, T1-0, T1-8, T1-2, T1-1, T1-4, T1-7, T1-6, T1-9,我们的消费者线程排序为C1-0, C1-1, C2-0, C2-1,最后分区分配的结果
为:
C1-0 将消费 T1-5, T1-2, T1-6 分区;
C1-1 将消费 T1-3, T1-1, T1-9 分区;
C2-0 将消费 T1-0, T1-4 分区;
C2-1 将消费 T1-8, T1-7 分区;
使用轮询分区策略必须满足两个条件
1. 每个主题的消费者实例具有相同数量的流
2. 每个消费者订阅的主题必须是相同的

3)Stricky

StrickyAssignor(粘性分区策略)

① 分区的分配要尽可能的均匀;
② 分区的分配尽可能的与上次分配的保持相同。

当两者发生冲突时,第一个目标优先于第二个目标。

优点:减少系统资源的损耗以及其它异常情况的发生(因为消费者是保存了偏移量的等信息的)

假设消费组有3个消费者:C0,C1,C2,它们分别订阅了4个Topic(t0,t1,t2,t3),并且每个主题有两个分
区(p0,p1),也就是说,整个消费组订阅了8个分区:tOpO 、 tOpl 、 tlpO 、 tlpl 、 t2p0 、
t2pl 、t3p0 、 t3pl
那么最终的分配场景结果为
CO: tOpO、tlpl 、 t3p0
Cl: tOpl、t2p0 、 t3pl
C2: tlpO、t2pl
这种分配方式有点类似于轮询策略,但实际上并不是,因为假设这个时候,C1这个消费者挂了,就势必会造成
重新分区(reblance),如果是轮询,那么结果应该是
CO: tOpO、tlpO、t2p0、t3p0
C2: tOpl、tlpl、t2pl、t3pl
然后,strickyAssignor它是一种粘滞策略,所以它会满足`分区的分配尽可能和上次分配保持相同`,所以分配结果应该是
消费者CO: tOpO、tlpl 、 t3p0、t2p0
消费者C2: tlpO、t2pl、tOpl、t3pl
也就是说,C0和C2保留了上一次是的分配结果,并且把原来C1的分区分配给了C0和C2。 这种策略的好处是
使得分区发生变化时,由于分区的“粘性,减少了不必要的分区移动

7.生产者生产消息确认机制

(1)为啥需要生产者的消息确认机制

    防止丢消息,当kafka的分区leader节点收到消息后,消息会同步到所有的follow节点,如果kafka leader分区收到消息后就给生产者回复确认,如果消息来不及同步到follow节点,leader挂了,那么这个休息就丢失了

(2)如何选择消息确认机制

    kafka提供了多种方式的消息确认机制。总结起来就是两种

    1):降低吞吐量,当消息都同步到所有follow节点才确认,如果消息的价值比较高,不允许丢          失(如果一个follow网络不好,大大降低了吞吐量)

   2):leader收到了马上回复,消息不重要的场景  

   3):折中,一半收到了马上回复

8.消费者的消息确认机制

  之前说了,为了防止消费者重复消费,kafka会在服务器端保存消费者消费的偏移量,这个偏移量实际上是(消费者确认自己收到了的消息,并且回复kafka的偏移量)

(1)如何选择消息确认机制

   定期发送确认信号(间隔时间可以设置,比如1s)

(2)缺点

  存在重复消费的嫌疑,如果消费者消费了某个信息但是还没提交,消费者崩溃了,就会触发重复消费

9. kafka分区分配Reblance

实际上kafka的reblance是kafka帮助消费组leader,在消费组leader计算后完成的统一分配策略

每个kafka的broker都会启动一个服务

Group Coordinator(消费组协调服务)

(1) kafka如何存储订阅者者偏移量信息和元数据

   之前说过kafka会把订阅者消费的主题的偏移量也会在服务器端保存一份,信息会保存在一个内部主题__consumer_offsets里面(默认50个分区,1个复制因子)

(2)消费者组的偏移量落点分区计算方式

Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount)

(3)broker如何均分不同的消费者组

   由(2)可知,消费者组的偏移量和元数据信息会落点到__consumer_offsets的某个分区里面,比如34,34分区的leader所在的broker就是这个消费者组的协调服务的broker

(4)大约流程

zookerper watcher 触发发现需要做reblance-> kafka在消费者组里选择一个leader->leader根据配置的策略分配最新的分区分配方案-> 上传协调者->协调者下发给所有的消费者

10.kafka进阶之数据存储方式

(1)主题布局

主题+分区(主题是个逻辑概念,分区是物理上的概念)

三个broker,ftopic 2分区2复制因子在各个broker的分布

2 * 2 = 4,应该是有4份数据 

broker0,id = 0

broker1: id =1

 broker2: id =2

(2)分区如何做leader选举

分区0在 breoker0,id=0 和broker1, id=1, 那么id比较小的的broker的所拥有的分区成为leader分区

(2)数据布局

每个分区文件的数据布局:

类似mysql的MyISAM存储引擎,做了索引,而且将索引文件和数据文件分开了

索引文件内容:(稀疏索引)

和mysql的MyISAM索引结构的区别:

MyISAM:b+数

kafka:稀疏索引(log.index.interval.bytes 指定,默认值为 4096),类似跳跃表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值