后端入门-消息队列 | 青训营笔记

109 阅读6分钟

消息队列

image-20230526114059148.png

发展历程

image-20230526114131377.png

常见的消息队列

image-20230526141306148.png

Kafka

Kafka可以参考这个链接:blog.csdn.net/aaa_a_b_c/a…

使用场景

image-20230526161120375.png

可以通过metrics数据监控查询等耗时问题

日志信息、Metric数据、用户行为等在kafka中都会被放到消息队列中

使用kafka

image-20230526161534599.png

topic指的是业务场景,所有有关的业务场景都存储在topic中

基本概念

image-20230526161558776.png

partition是topic的一个分区的概念 不同分区的消息可以并发处理

image-20230526163237861.png

image-20230526163316869.png

partition会有多个不同的负载 分布在不同的机器上

leader负责对外写入或者读取

follower负责从leader拉取信息 尽量与leader保持一致,如果和leader差距太大的话就会被踢出ISR,如果leader宕机之后可以从ISR中选择follower先顶替leader的工作

image-20230526184547634.png

topic和broker没有明确的对应关系。topic只是一个逻辑上的概念,对消息进行分类。topic在物理上分成多个partition,单独以 leader parition论,partition均匀的分布在broker上,这样做的好处是1、可以负载均衡,2、可以并行发送消息。

数据复制

image-20230526164429964.png

topic1也就是leader在不同的分区上 他在每个分区中相当于controller的角色

但是这种方式存在问题

image-20230526174839253.png

当我们重启其中一个broker的leader的时候,会重新选择一个新的leader 数据的使用还在进行 可能会导致broker之间的数据存在差异(黑色的虚线箭头表示数据的复制) ,所以需要进行数据的同步与追赶,最后需要进行一个leader的回切(防止大部分的leader都跑到其他节点,从而出现负载均衡的问题)

除了重启之外,也可以通过其他方式进行

image-20230526175606733.png

替换和重启类似

只要有节点的变更都会消耗时间

kafka架构

image-20230526165029259.png

主要就是生产者、集群和消费者群

Producer

image-20230526165101439.png

image-20230526165146918.png

image-20230526165213857.png

Broker

image-20230526165334875.png

broker 如何存储数据?

image-20230526165457957.png

以日志的形式存储

image-20230526170029251.png

通过磁盘结构来读写

  1. 磁头移动到指定的磁道上(移动磁头的时间比较长)
  2. 磁盘转动,找到对应的扇区
  3. 在扇区上进行读写

image-20230526170341182.png

通过顺序写的机制来写入,以减少寻道的时间

image-20230526170504836.png

如何读取消息,首先会发送一个fetchrequest请求给broker

image-20230526170556209.png

image-20230526171251607.png

采用的是稀疏索引的方式

image-20230526171435619.png

时间戳索引相对于偏移量索引多加了一个时间戳到offset的查找的步骤 也就是第一个块

image-20230526171551547.png

找到数据之后 在发送给consumer之前需要做一些拷贝,因为数据存储在磁盘中 需要先将数据拷贝到内核空间中才能给到用户空间 最后通过网卡内存(NIC)将数据发送给消费者(这种方式开销比较大)

image-20230526171845422.png

传统的数据拷贝开销较大 kafka使用了零拷贝的方式,直接在内核空间中进行数据的拷贝而不需要通过应用空间

同理 写入也使用了相同的拷贝方式,即零拷贝(写入的时候直接写入内核空间)

Consumer

image-20230526172624609.png

手动分配

image-20230526172710253.png

  1. 如果其中一个consumer挂了,比如consumer3挂了,分区7和分区8的数据流就会断掉(不能自动容灾)
  2. 重新加一个consumer也得重新分配
  3. 优点是:比较快

自动分配

image-20230526173112925.png

分配过程

有consumer进来之后首先会随机选择一个broker(负载比较低的)

image-20230526173620705.png

之后broker会告诉consumer他对应的协调者是具体的哪个broker

然后consumer会发起第二轮请求找到对应的协调者 说consumer想要加入到这个cluster中

image-20230526173830472.png

broker会从consumer中选取一台当做leader,用来计算整个分布的策略

这是因为对于某些特定的业务来说,有自己的业务特性 希望某个分片分配到某个特定的consumer上

image-20230526174309571.png

第三个请求用来同步整个集群的方案数据等

image-20230526174346232.png

连接成功之后每个consumer会在一定间隔内给cluster发送心跳

image-20230526174445100.png

image-20230526174508545.png

负载不均衡问题

image-20230526175817262.png

可以将其中的partition迁到另一个broker中 但是迁出的时候会有数据复制的问题 (需要进行权衡)

image-20230526175850707.png

存在问题

image-20230526180022919.png

BMQ

优点:兼容kafka协议,存算分离,云原生消息队列

整体架构

image-20230526180320508.png

相比于kafka来说增加了代理模块和分布式存储系统

image-20230526181643002.png

HDFS

写文件流程

image-20230526181736365.png

image-20230526181857937.png

数据不会都分配在同一个节点 上图中共数据选择是哪个节点进行写入,然后随机的在dataNode上进行分配(比如P1S1 分别分配在,1 2 3 DataNode)

broker状态机

image-20230526182221907.png

不会在同一个broker中有相同的分片,分片会在规定的机制下进行流转

recover:争夺使用权,抢锁,即一个文件只能有一个进程来写入;检查broker是否处于宕机等问题状态,如果是的话直接进行数据写入会造成问题,因此需要recover进行broker的恢复

fileover:如果append数据的时候出现异常 用来保证数据不会被中断

image-20230530160719631.png

write thread 异步处理

如果写入到buffer中就算写入成功的话:会有很高的吞吐,但是如果只写入到buffer中但是还没写入到磁盘中此时磁盘宕掉了,那么会造成写入数据的丢失

checkpoint:相当于一个标识,表示已经写入磁盘并且建立了索引,和上一张的checkpoint相同

image-20230530161713020.png

如果datanode挂了 failover机制会找一个其他的datanode继续进行写入操作 而不是等待原来的那个修复

proxy读取数据

image-20230530162019094.png

wait:如果没有wait机制的话 topic如果没有读取到数据会一直轮训,io压力较大;wait中设置了两种返回方式:1. 数据大小到达一定量的时候返回 2. 超过设置时间之后还没到读取一定量的数据也会进行返回

多机房部署

image-20230530162525885.png

proxy一个就可以工作了

broker需要全部一起进行工作

高级特性

image-20230530162802138.png

可应对复杂场景

image-20230530162843924.png

image-20230530162938796.png

image-20230530163002613.png

两种BOE测试各有优缺点

image-20230530163047296.png

image-20230530163223189.png

将主干和泳道的topic分开

Databus

image-20230530163333478.png

解决

image-20230530163456084.png

agent 所有消息都会发送到agent,然后再由agent发送给BMQ

server 保存配置

mirror

image-20230530163724134.png

image-20230530163819515.png

通过mirror可以异步写入,如果写入都是CN可以直接写,同时也不会影响其他区域的写入,然后通过mirror将写入的内容分发到其他区

index

image-20230530164030895.png

image-20230530164106776.png

parquet

image-20230530164234720.png

image-20230530164459291.png

RocketMQ

image-20230526183715197.png

VS.Kafka

image-20230526183739543.png

基本概念

image-20230526183830543.png

架构

image-20230526183908478.png

Nameserver(充当路由的角色): 告诉生产者消费者在哪个broker上可以更加准确的进行消费或者生产

整个机器是一个master 而另一个机器是slave

消息存储

image-20230526184711405.png

所有消息都会发送到broker上,每一个broker只有一个commitLog,会承接所有生产者数据,然后根据不同的分区dispatch出去,但是中间T1:Q0中存储的不是真实数据 而是真实数据在commitLog中的地址,相当于是个索引(而且是个立即索引)

每个Producer group只有一个commitLog来承接所有的数据 然后根据不同的分区来dispatch

高级特性

image-20230530165032356.png

把消息写入到队列中,然后再异步的处理

需要用到事务保证库存记录-1和将消息放入到消息队列共同进退

image-20230530165242661.png

image-20230530170634222.png

提前将消息发送到队列中并且给消息设置好可以消费的时间

image-20230530170749357.png

image-20230530170941951.png

丢掉消息还是重新发送?

image-20230530171002434.png