消息队列知识体系总结(Kafka/RocketMQ)
2022-06-14 23:02:03 0 举报
AI智能生成
消息队列知识体系总结(Kafka/RocketMQ)
作者其他创作
大纲/内容
消息队列概述
应用场景
服务解耦
解耦前
解耦后
子主题
异步处理
流量控制
没有使用MQ前
子主题
使用MQ之后
核心概念
消息策略
at most once
可能丢失 不会重复
log 位置信息
at least once
可能重复 不会丢失
log 消息处理结果
exactly once
不丢失 不重复,只发一次
上面两个都存且存到同一个位置上
技术要点
网络通信:如何实现高性能的异步网络传输
使用 Netty 来实现异步网络通信
使用 NIO 来实现异步网络通信
子主题
序列化反序列化:如何通过网络传输结构化的数据?
要想使用网络框架的 API 来传输结构化的数据,
必须得先实现结构化的数据与字节流之间的双向转换。
必须得先实现结构化的数据与字节流之间的双向转换。
序列化考虑因素
1. 序列化后的数据最好是易于人类阅读的;
2. 实现的复杂度是否足够低;
3. 序列化和反序列化的速度越快越好;
4. 序列化后的信息密度越大越好,也就是说,同样的一个结构化数据,序列化之后占用的
存储空间越小越好
2. 实现的复杂度是否足够低;
3. 序列化和反序列化的速度越快越好;
4. 序列化后的信息密度越大越好,也就是说,同样的一个结构化数据,序列化之后占用的
存储空间越小越好
解决方法
Google 的 Protobuf、Kryo、Hessian
JSON、XML 这些标准的数据格式
传输协议:应用程序之间对话的语言
内存管理:如何避免内存溢出和频繁的垃圾回收?
数据压缩:时间换空间的游戏
选型分析
RabbitMQ
RabbitMQ对消息堆积的支持不好,在大量消息堆积时出现性能急剧下降的问题
RabbitMQ 使用 Erlang是比较小众的语言
RocketMQ
Kafka
Kafka最早是由LinkedIn开发,后成为Apache的顶级项目
Kafka的最开始设计的目的是处理海量日志
kafka使用Scala和Java语言开发
由于是异步批量的设计,所以在同步首发消息的响应时延比较高
在kafka的broker中都有这样先攒一批在发送一批的处理
在kafka的broker中都有这样先攒一批在发送一批的处理
kafka使用了批量与异步的思想,异步性能在所有的消息队列中是最强的
ActiveMQ
是最老牌的开源消息队列
Kafka
核心概念
主题(Topic)
在 Kafka 中,发布订阅的对象
可以为每个业务、每个应用甚至是每类数据都创建专属的主题
主题,是写入kafka的基础单元,是一个逻辑概念,实际写入的是partition,一个topic包含多个partition
每条消息属于且仅属于一个Topic
发送和订阅消息都必须指定topic
分区(Partitioning)
Kafka 中的分区机制指的是将每个主题划分成多个分区(Partition)
topic的组成单元,可以水平扩容,是kafka高吞吐量的保障
消息持久化时,每条消息都是根据一定的分区规则路由到对应的partition中,并append到log文件的尾部
在同一个partition中消息是顺序写入且有序的,但不同partiton之间不能保证消息的有序性
个数最好与服务器个数相当
多个大小相等的segment file (段)组成了一个partition
备份机制(Replication)
partition可以有指定数据的副本,备份的思想很简单,就是把相同的数据拷贝到多台机器上,
而这些相同的数据拷贝在 Kafka 中被称为副本(Replica)主从模式,producer和consumer只与leader交互follower从leader复制
而这些相同的数据拷贝在 Kafka 中被称为副本(Replica)主从模式,producer和consumer只与leader交互follower从leader复制
副本分类
副本(Replica)
领导者副本(Leader Replica)
对外提供服务,这里的对外指的是与
客户端程序进行交互
客户端程序进行交互
追随者副本(Follower Replica)
只是被动地追随领导者副本而已,
不能与外界进行交互
不能与外界进行交互
ISR
in-sync replica,已同步的副本
Kafka会在Zookeeper上针对每个Topic维护一个ISR,持有partition的已同步的副本信息,
如果某个分区的Leader不可用,Kafka就会从ISR集合中选择一个副本作为新的Leader。
如果某个分区的Leader不可用,Kafka就会从ISR集合中选择一个副本作为新的Leader。
副本
定义
副本从属于分区
副本相关概念
Leader副本
Follower副本
ISR
LEO
HW
失效副本
处于同步失效或功能失效(比如副本处于非存活状态)
的副本统称为失效副本
的副本统称为失效副本
判断标准
replica.lag.time.max.ms
replica.lag.max.messages
副本失效原因
follower 副本进程卡住,在一段时间内根本没有向 leader
副本发起同步请求,比如频繁的 Full GC
副本发起同步请求,比如频繁的 Full GC
follower 副本进程同步过慢,在一段时间内都无法追赶上 leader 副本,
比如 I/O 开销过大。
比如 I/O 开销过大。
setment file
每个partition 就相当于一个巨型的文件 里面由多个大小相等的segment file小文件组成,
但是每个segment file 的消息数量并不一定相等,
但是每个segment file 的消息数量并不一定相等,
组成
.index 索引文件
包含若干索引条目,每个条目表示数据文件中一条message的索引
.log 数据文件
offset
位移
partition中的每个消息都有一个连续的序号,用于partition唯一标识一条消息。
Offset记录着下一条将要发送给Consumer的消息的序号。
Offset从语义上来看拥有两种:Current Offset和Committed Offset。
Offset记录着下一条将要发送给Consumer的消息的序号。
Offset从语义上来看拥有两种:Current Offset和Committed Offset。
current offset
Current Offset保存在Consumer中,它表示Consumer希望收到的下一条消息的序号。
它仅仅在poll()方法中使用。例如,Consumer第一次调用poll()方法后收到了20条消息,那么Current Offset就被设置为20。
这样Consumer下一次调用poll()方法时,Kafka就知道应该从序号为21的消息开始读取。这样就能够保证每次Consumer poll消息时,
都能够收到不重复的消息。
它仅仅在poll()方法中使用。例如,Consumer第一次调用poll()方法后收到了20条消息,那么Current Offset就被设置为20。
这样Consumer下一次调用poll()方法时,Kafka就知道应该从序号为21的消息开始读取。这样就能够保证每次Consumer poll消息时,
都能够收到不重复的消息。
Committed Offset
已提交位移,保存在Broker上,表示Consumer已经确认消费过的消息的序号,举个例子,
Consumer通过poll() 方法收到20条消息后,此时Current Offset就是20,经过一系列的逻辑处理后,
并没有调用consumer.commitAsync()或consumer.commitSync()来提交Committed Offset,那么此时Committed Offset依旧是0。
Consumer通过poll() 方法收到20条消息后,此时Current Offset就是20,经过一系列的逻辑处理后,
并没有调用consumer.commitAsync()或consumer.commitSync()来提交Committed Offset,那么此时Committed Offset依旧是0。
生产者(Producer)
向主题发布消息的客户端应用程序称为生产者
生产者程序通常持续不断地
向一个或多个主题发送消息
向一个或多个主题发送消息
消费者(Consumer)
订阅这些主题消息的客户端应用程序就被称为消费者
消费者也能够同时订阅多个主题的消息
消费者组(Consumer Group)
Kafka 提供的可扩展且具有容错性的消费者机制
可以有一个或多个 Consumer
同一个 GroupId
消息只能被同组内一个 Consumer 消费
Coordinator 协调者
Broker
负责存储消息的服务端进程
Broker 负责接收和处理客户端发送过来的请求
对消息进行持久化
消息队列模型
队列模型
消息是顺序进入,顺序消费
队列中的每一条消息只能被一个消费者消费
队列中的每一条消息只能被一个消费者消费
发布订阅模型
架构图
高可用机制
服务高可用
集群高可用
数据高可用
本地存储,主从复制,多副本拷贝
同步双写
异步复制
消息处理高可用
消息可靠投递(producer)
采用发送确认机制
消息可靠消费(consumer)
采用消费确认机制
消息可靠存储(broker)
同步刷盘,持久化消息
同步多写:多副本策略+同步刷盘持久化消息
broker对写入消息的payload做完整性校验
消息堆积能力
高性能机制
性能标准
延迟毫秒级别
吞吐(单机万到百万TPS)
消息高性能投递(producer)
异步发送
批量发送
Producer 端可以在内存中合并多条消息后, 以一次请求的方式发
送了批量的消息给 broker,从而大大减少 broker 存储消息的 IO 操作次数。
送了批量的消息给 broker,从而大大减少 broker 存储消息的 IO 操作次数。
但也一定程度上影响
了消息的实时性,相当于以时延代价,换取更好的吞吐量。
了消息的实时性,相当于以时延代价,换取更好的吞吐量。
负载均衡(producer)
由于消息 topic 由多个 partition 组成, 且 partition 会均衡分布到不同 broker 上,
因此,为了有效利用 broker 集群的性能,提高消息的吞吐量,
因此,为了有效利用 broker 集群的性能,提高消息的吞吐量,
producer 可以通过随机或者 hash 等方式,将消
息平均发送到多个 partition 上,以实现负载均衡。
息平均发送到多个 partition 上,以实现负载均衡。
压缩( GZIP 或 Snappy)
Producer 端可以通过 GZIP 或 Snappy 格式对消息集合进行压缩。 Producer 端进行压缩之后,在
Consumer 端需进行解压。压缩的好处就是减少传输的数据量,减轻对网络传输的压力,在对大
数据处理上,瓶颈往往体现在网络上而不是 CPU(压缩和解压会耗掉部分 CPU 资源)
Consumer 端需进行解压。压缩的好处就是减少传输的数据量,减轻对网络传输的压力,在对大
数据处理上,瓶颈往往体现在网络上而不是 CPU(压缩和解压会耗掉部分 CPU 资源)
消息高性能存储(broker)
多分区(Partition/Queue)策略,并行读写
持久化
Page Cahce
顺序IO
Kafka 的 producer 生产数据,要写入到 log 文件中,写的过程是一直追加到文件末端,为顺序写。
官网有数据表明,同样的磁盘,顺序写能到 600M/s,而随机写只有 100K/s。
这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间。
官网有数据表明,同样的磁盘,顺序写能到 600M/s,而随机写只有 100K/s。
这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间。
异步刷盘
消息读取
消息日志分段存储
每个分区的offset日志对应的目录就是Topic-Partition,不同的分区可能存储在不同的服务器上
每个分区里面就是很多个LogSegmentFile,也就是日志段文件
每个分区的数据会被分成多个段,放在多个文件里,每个文件还有自己的索引文件
限定了每个日志段(LogSegmentFile)的大小为1G,存满了就新建另一个日志段
限定了每个日志段(LogSegmentFile)的大小为1G,存满了就新建另一个日志段
00000000000000000000.index
00000000000000000000.log
00000000000000000000.timeindex
00000000000000000000.log
00000000000000000000.timeindex
0000000-5367851
00000000000005367851.index
00000000000005367851.log
00000000000005367851.timeindex
00000000000005367851.log
00000000000005367851.timeindex
5367851-9987654
00000000000009987654.index
00000000000009987654.log
00000000000009987654.timeindex
00000000000009987654.log
00000000000009987654.timeindex
9987654就是这个消息写入到此SegmentFile的起始offset
消息日志二分查找
使用稀疏索引
限定了在日志文件中每写入多少条数据,就要在索引中写入一条索引数据,默认是4KB
由索引文件的物理位置定位到某条数据,再向下遍历。偏移量是有序的
消息高性能消费(consumer)
多consumer示例并行消费topic
零拷贝
批量拉取消息
producer分析
producer工作流程
发送流程图
子主题
子主题
在新版本的kafka中(从0.9开始),其实只有异步方式一种,是批量发送的方式
在producer端,存在2个线程,一个是producer主线程,用户端调用send消息时,是在主线程执行的,数据被缓存到RecordAccumulator中,send方法即刻返回,也就是说此时并不能确定消息是否真正的发送到broker。另外一个是sender IO线程,其不断轮询RecordAccumulator,满足一定条件后,就进行真正的网络IO发送,使用的是异步非阻塞的NIO。主线程的send方法提供了一个用于回调的参数,当sender线程发送完后,回调函数将被调用,可以用来处理成功,失败或异常的逻辑
在producer端,存在2个线程,一个是producer主线程,用户端调用send消息时,是在主线程执行的,数据被缓存到RecordAccumulator中,send方法即刻返回,也就是说此时并不能确定消息是否真正的发送到broker。另外一个是sender IO线程,其不断轮询RecordAccumulator,满足一定条件后,就进行真正的网络IO发送,使用的是异步非阻塞的NIO。主线程的send方法提供了一个用于回调的参数,当sender线程发送完后,回调函数将被调用,可以用来处理成功,失败或异常的逻辑
producer 分区策略
指明 partition 的情况下,直接将指明的值直接作为 partiton 值;
没有指明 partition 值但有 key 的情况下,将 key 的 hash 值与 topic 的 partition 数进行取余得到 partition 值;
既没有 partition 值又没有 key 值的情况下,第一次调用时随机生成一个整数(后面每次调用在这个整数上自增),
将这个值与 topic 可用的 partition 总数取余得到 partition值,也就是常说的 round-robin 算法。
将这个值与 topic 可用的 partition 总数取余得到 partition值,也就是常说的 round-robin 算法。
Broker防止消息丢失机制
目的:为保证 producer 发送的数据,能可靠的发送到指定的 topic, topic 的每个 partition 收到producer 发送的数据后,
都需要向 producer 发送 ack(acknowledgement 确认收到),如果producer 收到 ack, 就会进行下一轮的发送,否则重新发送数据。
都需要向 producer 发送 ack(acknowledgement 确认收到),如果producer 收到 ack, 就会进行下一轮的发送,否则重新发送数据。
何时发送ack?确保有follower与leader同步完成,leader再发送ack,这样才能保证leader挂掉之后,能在follower中选举出新的leader。
ACK 发送策略
半数以上的follower同步完成,即可发送ack继续发送重新发送
延迟低,不用等待所有follower都同步完
但是容错率低,同样为了容忍 n 台节点的故障,需要 2n+1 个副本
全部的follower同步完成,才可以发送ack(kafka选择的这种)
延迟高,但网络延迟对kafka影响小
容错率高,同样为了容忍n台节点的故障,只需要 n+1 个副本
ACK机制配置说明
0: producer 不等待 broker 的 ack,这一操作提供了一个最低的延迟,
broker 一接收到还没有写入磁盘就已经返回,当 broker 故障时有可能丢失数据;
broker 一接收到还没有写入磁盘就已经返回,当 broker 故障时有可能丢失数据;
1:producer 等待 broker 的 ack, partition 的 leader 落盘成功后返回 ack,
如果在 follower同步成功之前 leader 故障,那么将会丢失数据
如果在 follower同步成功之前 leader 故障,那么将会丢失数据
-1(all) : producer 等待 broker 的 ack, partition 的 leader 和 ISR 的follower 全部落盘成功后才返回 ack。
但是如果在 follower 同步完成后, broker 发送 ack 之前, leader 发生故障,那么会造成数据重复。
但是如果在 follower 同步完成后, broker 发送 ack 之前, leader 发生故障,那么会造成数据重复。
ISR(in-sync replica set)
出现背景: leader 收到数据,所有 follower 都开始同步数据,但有一个 follower,
因为某种故障,迟迟不能与 leader 进行同步,那 leader 就要一直等下去,直到它完成同步,才能发送 ack
因为某种故障,迟迟不能与 leader 进行同步,那 leader 就要一直等下去,直到它完成同步,才能发送 ack
解决策略:ISR意味和leader保持同步的follow集合,
当 ISR 中的 follower 完成数据的同步之后,就会给 leader 发送 ack。
当 ISR 中的 follower 完成数据的同步之后,就会给 leader 发送 ack。
如何选择ISR中的follow:选择与leader通信频繁的,数据相差小的follow
如果follow与leader信息条数相差大于replica.lag.max.message就踢出ISR
batch批量发送数据原因,会导致follow频繁进出ISR,
然后导致频繁更改存储在Zookeeper中的ISR信息
然后导致频繁更改存储在Zookeeper中的ISR信息
如果leader与follow超过replica.lag.time.max.ms时间为同步,就从ISR中踢出(kafka选的这个)
数据一致性问题
LEO:(Log End Offset)每个副本的最后一个offset
HW:(High Watermark)高水位,指的是消费者能见到的最大的 offset, ISR 队列中所有follow中最小的 LEO
follower 故障:follower 发生故障后会被临时踢出 ISR,待该 follower 恢复后, follower 会读取本地磁盘记录的上次的 HW,并将 log 文件高于 HW 的部分截取掉,从 HW 开始向 leader 进行同步。等该 follower 的 LEO 大于等于该 Partition 的 HW,即 follower 追上 leader 之后,就可以重新加入 ISR 了。
leader 故障:leader 发生故障之后,会从 ISR 中选出一个新的 leader,之后,为保证多个副本之间的数据一致性, 其余的 follower 会先将各自的 log 文件高于 HW 的部分截掉,然后从新的 leader同步数据。
只保证数据一致性,不保证数据不丢失或者不重复(由ACK保证)
ExactlyOnce
将服务器的 ACK 级别设置为-1(all),可以保证 Producer 到 Server 之间不会丢失数据,即 At Least Once 语义。
相对的,将服务器 ACK 级别设置为 0,可以保证生产者每条消息只会被发送一次,即 At Most Once 语义
At Least Once 可以保证数据不丢失,但是不能保证数据不重复;相对的, At Most Once可以保证数据不重复,但是不能保证数据不丢失。 但是,对于一些非常重要的信息,比如说交易数据,下游数据消费者要求数据既不重复也不丢失,即 Exactly Once 语义。
0.11 版本的 Kafka,引入了一项重大特性:幂等性。所谓的幂等性就是指 Producer 不论向 Server 发送多少次重复数据, Server 端都只会持久化一条。
PID:生产者表示
SequenceNumber:消息的序列化号
paratition:分区
如果pid+partition对应的SequenceNumber重复时,则代表这组消息是重复数据,broker只会持久化一条
At Least Once + 幂等性 = Exactly Once,也就是不丢消息,也没有重复消费
producer事务
解决的问题
我们知道At Least Once + 幂等性 = Exactly Once保证了kafka数据不会丢失,也不会重复消费,但还是会出现问题的。幂等性由<Pid,SequenceNumber+partition>来保证,如果producer发送消息给了broker后,broker接收到后再返回ack过程中leader宕机,此时producer就会重新发送消息,这样新选举出来的leader已经同步了之前leader的消息,就会有重复消息,而幂等性就可以消除重复性。但是如果此时producer也宕机了,当他重启后就会生成一个新的Pid,便无法保证幂等性。
解决方式
每个客户端都会给producer生成一个TransactionId,并且TransactionId与Pid进行绑定,TransactionId被维护在Transaction Coordinator中,每次producer都会去coordinator中找相应TransactionId锁对应的自己的Pid,就能保证一个生产者的Pid不会变化
consumer分析
消息队列消费方式
push
push(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由 broker 决定的。
它的目标是尽可能以最快速度传递消息,但是这样很容易造成 consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。
它的目标是尽可能以最快速度传递消息,但是这样很容易造成 consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。
pull(kafka选用的)
pull 模式不足之处是,如果 kafka 没有数据,消费者可能会陷入循环中, 一直返回空数据。 针对这一点, Kafka 的消费者在消费数据时会传入一个时长参数 timeout,如果当前没有数据可供消费, consumer 会等待一段时间之后再返回,这段时长即为 timeout。
再平衡策略的触发事件
consumer group中的新增或删除某个consumer,导致其所消费的分区需要分配到组内其他的consumer上
consumer订阅的topic发生变化,比如订阅的topic采用的是正则表达式的形式,如test-*此时如果有一个新建了一个topic test-user,那么这个topic的所有分区也是会自动分配给当前的consumer的,此时就会发生再平衡
consumer所订阅的topic发生了新增分区的行为,那么新增的分区就会分配给当前的consumer,此时就会触发再平衡
分区分配策略(再平衡策略)
round-robin
round-robin是轮询,它是按照消费者组为主要目标的,也就是把消费者组中所有consumer订阅的所有topic-partition都组合起来,根据这些topic-partition的hash值进行排序,然后再从头依次循环发送给消费者组中的每个消费者,如果分配给这个consumer的topic是它没有订阅的,那么就轮询下一个,指导将这个topic-partition分配给最近的一个订阅了它的consumer。可以看出轮询方式会导致消费者组中,每个cosumer所承载的分区数量不一致,从而导致消费者组中consumer的压力不一致
- 尝试将t0-0分配给C0,由于C0订阅了t0,因而可以分配成功;
- 尝试将t1-0分配给C1,由于C1订阅了t1,因而可以分配成功;
- 尝试将t1-1分配给C2,由于C2订阅了t1,因而可以分配成功;
- 尝试将t2-0分配给C0,由于C0没有订阅t2,因而会轮询下一个consumer;
- 尝试将t2-0分配给C1,由于C1没有订阅t2,因而会轮询下一个consumer;
- 尝试将t2-0分配给C2,由于C2订阅了t2,因而可以分配成功;
- 同理由于t2-1和t2-2所在的topic都没有被C0和C1所订阅,因而都不会分配成功,最终都会分配给C2
range
range是重分配策略,它是按照topic为主题的,也就是把订阅了这个topic的消费者组的所有消费者都组合起来,将topic的分区进行均匀分布(但是当topic的partition数量/消费者组的consumer数量!=整数时,分配还是不均匀的,还会导致消费者组中每个consumer的压力不一致)
假设有两个consumer:C0和C1,两个topic:t0和t1,这两个topic分别都有三个分区,那么总共的分区有六个:t0-0、t0-1、t0-2、t1-0、t1-1和t1-2。那么Range分配策略将会按照如下步骤进行分区的分配:
sticky
Sticky:这种分区策略是最新版本中新增的一种策略,其主要实现了两个目的
目的
将现有的分区尽可能均衡的分配给各个consumer,存在此目的的原因在于Round Robin和Range分配策略实际上都会导致某几个consumer承载过多的分区,从而导致消费压力不均衡
如果发生再平衡,那么重新分配之后在前一点的基础上会尽力保证当前未宕机的consumer所消费的分区不会被分配给其他的consumer上
实现步骤
初始状态分配的特点是,所有的分区都还未分配到任意一个consumer上。
这里我们假设有三个consumer:C0、C1和C2,三个topic:t0、t1和t2,
这三个topic分别有1、2和3个分区,那么总共的分区为:t0-0、t1-0、t1-1、t2-0、t2-1和t2-2。
关于订阅情况,这里C0订阅了t0,C1订阅了t0和1,C2则订阅了t0、t1和t2。
这里我们假设有三个consumer:C0、C1和C2,三个topic:t0、t1和t2,
这三个topic分别有1、2和3个分区,那么总共的分区为:t0-0、t1-0、t1-1、t2-0、t2-1和t2-2。
关于订阅情况,这里C0订阅了t0,C1订阅了t0和1,C2则订阅了t0、t1和t2。
首先将所有的分区进行排序,排序方式为:首先按照当前分区所分配的consumer数量从低到高进行排序,
如果consumer数量相同,则按照分区的字典序进行排序。这里六个分区由于所在的topic的订阅情况各不相同,因而其排序结果如下
如果consumer数量相同,则按照分区的字典序进行排序。这里六个分区由于所在的topic的订阅情况各不相同,因而其排序结果如下
然后将所有的consumer进行排序,其排序方式为:首先按照当前consumer已经分配的分区数量有小到大排序,
如果两个consumer分配的分区数量相同,则会按照其名称的字典序进行排序。
由于初始时,这三个consumer都没有分配任何分区,因而其排序结果即为其按照字典序进行排序的结果:
如果两个consumer分配的分区数量相同,则会按照其名称的字典序进行排序。
由于初始时,这三个consumer都没有分配任何分区,因而其排序结果即为其按照字典序进行排序的结果:
然后将各个分区依次遍历分配给各个consumer,首先需要注意的是,这里的遍历并不是C0分配完了再分配给C1,而是每次分配分区的时候都整个的对所有的consumer从头开始遍历分配,如果当前consumer没有订阅当前分区,则会遍历下一个consumer。然后需要注意的是,在整个分配的过程中,各个consumer所分配的分区数是动态变化的,而这种变化是会体现在各个consumer的排序上的,比如初始时C0是排在第一个的,此时如果分配了一个分区给C0,那么C0就会排到最后,因为其拥有的分区数是最多的
首先将t2-0尝试分配给C0,由于C0没有订阅t2,因而分配不成功,继续轮询下一个consumer;
然后将t2-0尝试分配给C1,由于C1没有订阅t2,因而分配不成功,继续轮询下一个consumer;
接着将t2-0尝试分配给C2,由于C2订阅了t2,因而分配成功,此时由于C2分配的分区数发生变化,各个consumer变更后的排序结果为:
然后将t2-0尝试分配给C1,由于C1没有订阅t2,因而分配不成功,继续轮询下一个consumer;
接着将t2-0尝试分配给C2,由于C2订阅了t2,因而分配成功,此时由于C2分配的分区数发生变化,各个consumer变更后的排序结果为:
接下来的t2-1和t2-2,由于也只有C2订阅了t2,因而其最终还是会分配给C2,
最终在t2-0、t2-1和t2-2分配完之后,各个consumer的排序以及其分区分配情况如下:
最终在t2-0、t2-1和t2-2分配完之后,各个consumer的排序以及其分区分配情况如下:
接着继续分配t1-0,首先尝试将其分配给C0,由于C0没有订阅t1,因而分配不成功,继续轮询下一个consumer;
然后尝试将t1-0分配给C1,由于C1订阅了t1,因而分配成功
同理,接下来会分配t1-1,虽然C1和C2都订阅了t1,但是由于C1排在C2前面,因而该分区会分配给C1
然后尝试将t1-0分配给C1,由于C1订阅了t1,因而分配成功
同理,接下来会分配t1-1,虽然C1和C2都订阅了t1,但是由于C1排在C2前面,因而该分区会分配给C1
尝试将t0-0分配给C0,由于C0订阅了t0,因而分配成功,最终的分配结果为
与前面讲解的Round Robin进行对比,可以很明显的发现,Sticky重分配策略分配得更加均匀一些
consumer的offset的存储
Kafka 0.9 版本之前, consumer 默认将 offset 保存在 Zookeeper 中,从 0.9 版本开始,
consumer 默认将 offset 保存在 Kafka 一个内置的 topic 中,该 topic 为__consumer_offsets
consumer 默认将 offset 保存在 Kafka 一个内置的 topic 中,该 topic 为__consumer_offsets
offset的是以ConsumerGroup+Topic+Partition来分类存储的,因为消费者可能从消费者组中加入或者宕机,
具有不确定性,所以需要通过消费者组来作为唯一标识
具有不确定性,所以需要通过消费者组来作为唯一标识
Consumer事务(保证相对较弱)
由于每个Topic-Partition对应的存储offset的segment有多个,而kafka消费者可以批量消费数据,如果这批数据是跨了2个segment的,而刚好消费者消费消息失败,需要再次消费。但此时第一个segment过期了,就无法消费到第一个segment中的消息了。这是事务所无法保证的。
broker分析
kafka常用场景
1.系统间解耦
一个系统挂掉就都挂掉
2.峰值压力缓冲
3.异步(并行)通信
4.常规消息系统
kafka做消息系统的不足之处
1.未提供事务性
2.没有消息确认机制
3.没有消息分组
kafka不能保证消息的绝对可靠
消息重发
消息发送丢失
5.活动跟踪
6.传递消息
格式化消息(装饰)
将多个消息存放在同一个通知里发送
根据用户配置的首选项发送数据
好处
7.度量指标和日志记录
和flume整合
8.提交日志
和es整合
9.流处理
和sparkStreaming整合
和kafka整合
RocketMQ
核心概念
主题(Topic)
第一级消息类型,书的标题
队列(Queue)
Tag
第二级消息类型,书的目录,可以基于 Tag 做消息过滤
生产者(Producer)
消费者(Consumer)
消费者组(Consumer Group)
Broker
broker-master
broker-salve
Broker部署方式
单个 Master
这种方式风险较大,一旦 Broker 重启或者宕机时,
会导致整个服务不可用,不建议线上环境使用。
会导致整个服务不可用,不建议线上环境使用。
多 Master 模式
一个集群无 Slave,全是 Master,例如 2 个 Master 或者 3 个 Master
优点:配置简单,单个 Master 宕机或重启维护对应用无影响,在磁盘配置为 RAID10
时,即使机器宕机不可恢复情况下,由与 RAID10 磁盘非常可靠,消息也不会丢(异步刷
盘丢失少量消息,同步刷盘一条不丢)。性能最高。
时,即使机器宕机不可恢复情况下,由与 RAID10 磁盘非常可靠,消息也不会丢(异步刷
盘丢失少量消息,同步刷盘一条不丢)。性能最高。
缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息
实时性会受到受到影响。
实时性会受到受到影响。
多 Master 多 Slave 模式
异步复制
异步复制
每个 Master 配置一个 Slave,有多对 Master-Slave,
HA 采用异步复制方式,主备有短暂消息延迟,毫秒级。
HA 采用异步复制方式,主备有短暂消息延迟,毫秒级。
优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响,因为 Master 宕
机后,消费者仍然可以从 Slave 消费,此过程对应用透明。不需要人工干预。性能同多
Master 模式几乎一样。
机后,消费者仍然可以从 Slave 消费,此过程对应用透明。不需要人工干预。性能同多
Master 模式几乎一样。
缺点: Master 宕机,磁盘损坏情况,会丢失少量消息。
多 Master 多 Slave 模式
同步双写
同步双写
每个 Master 配置一个 Slave,有多对 Master-Slave,
HA 采用同步双写方式,主备都写成功,向应用返回成功。
HA 采用同步双写方式,主备都写成功,向应用返回成功。
优点:数据与服务都无单点, Master 宕机情况下,消息无延迟,服务可用性与数据可
用性都非常高
用性都非常高
缺点:性能比异步复制模式略低,大约低 10%左右,发送单个消息的 RT 会略高。目
前主宕机后,备机不能自动切换为主机,后续会支持自动切换功能。
前主宕机后,备机不能自动切换为主机,后续会支持自动切换功能。
Name Server
高可用机制
消息可靠投递
消息可靠消费
消息堆积能力
高性能机制
消息高性能投递
消息高性能消费
参考资料
https://www.processon.com/mindmap/5fa74813079129448c940da3
https://www.processon.com/view/5f93cf947621311c479e49e7?fromnew=1
0 条评论
下一页