消息中间件——Kafka和RocketMQ

消息队列探索

相关链接:https://kunzhao.org/docs/rocketmq/
https://blog.csdn.net/qq_41822345/article/details/124537385
https://mp.weixin.qq.com/s/kme1N1VH5enXpKQ52V6Fbg
https://kafka.apache.org/documentation/#impl_deletes

一、消息队列设计思想

1、消息队列适用场景

(1)消息队列应用场景

主要应用于:消息不要求实时处理、一份数据多处使用(不同消费方消费速度不同)的场景。

  • 一、应用解耦

在这里插入图片描述

  • 二、异步

在这里插入图片描述

  • 三、流量消峰

在这里插入图片描述

  • 四、数据分发

    通过消息队列可以让数据在多个系统更加之间进行流通。数据的产生方不需要关心谁来使用数据,只需要将数据发送到消息队列,数据使用方直接在消息队列中直接获取数据即可。

在这里插入图片描述

(2)消息队列带来的挑战

优点:解耦、削峰、异步、数据分发

缺点包含以下几点:

  • 系统可用性降低

    系统引入的外部依赖越多,系统稳定性越差。一旦MQ宕机,就会对业务造成影响。

    如何保证MQ的高可用?

  • 系统复杂度提高

    MQ的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过MQ进行异步调用。

    如何保证消息没有被重复消费?怎么处理消息丢失情况?那么保证消息传递的顺序性?

  • 一致性问题

    A系统处理完业务,通过MQ给B、C、D三个系统发消息数据,如果B系统、C系统处理成功,D系统处理失败。

    如何保证消息数据处理的一致性?

(3)主流消息队列产品

在这里插入图片描述

常见的MQ产品包括Kafka、ActiveMQ、RabbitMQ、RocketMQ、Pulsar。

中间件ActiveMQRabbitMQRocketMQKafkaPulsar
开发语言javaerlangjavascalajava
topic数量topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topictopic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源Pulsar采用存算分离的架构,存储和服务分离,Broker负责提供服务,BookKeeper提供存储能力。 两层可以独立扩容,因此topic个数对吞吐量不会产生显著的影响,
单机吞吐万级万级10万级20万级100万级
时延ms级us级ms级ms级以内ms级
可用性高【主从】高【主从】非常高【分布式】分为Dledger架构和普通master-slave架构两种,普通主从架构不支持故障自动切换,运维不太友好非常高【分布式】非常高【分布式】broker层是无状态代理,动态扩容,数据存储层bookeeper采用segment-oriented存储机制,无写入不可用风险
可靠性有较低的概率丢失数据基本不丢经过参数优化配置,可以做到 0 丢失经过参数优化配置,可以做到 最小概率不丢失经过参数配置后,可以做到0丢失
功能特性MQ功能完备。产品成熟,应用公司多。文档全,支持协议多。基于erlang,所以并发能力强,性能好,延时低。UI管理界面丰富。MQ功能较为完备全面、扩展性强。只有主要的MQ功能(无消息查询、回溯等功能)、主要应用于大数据领域。云原生时代的新一代消息中间件,社区活跃、支持多租户、强一致、跨域部署等诸多特性
持久化磁盘内存、文件磁盘磁盘磁盘

2、消息队列主体模型

在这里插入图片描述

  • 生产者

生产者(producer),主要生产消息,并发送给消息队列中,通常有同步、异步两种方式。

  • 消息队列

消息队列(message queue),主要保存/暂存生产者生产的消息,并将消息以某种方式告知消费者,消息队列一般具备消息分类(topic)的能力,存放消息的队列称为msg queue。

  • 消费者

消费者(consumer),主要从消息队列取出消息,并进行消费,这里的取出消息的方式主要有两种(主动拉取消息、等待推送消息)

(1)推/拉模型区别

推/拉模型对比推送方式(push)拉取方式(pull)
消息实时性消息实时性强消息实时性较弱
消费者处理速度消息发送速率由消息队列控制,下游不同消费者消费速度不同,此种模式下对消费者资源无法充分利用消费者根据其消费速度,拉取相应的消息,然后对齐处理,拉取模式能更好的适配下游不同类型的消费者
消息队列内部消息队列内部实现相对容易,只需维护有哪些消费者订阅了哪些主题。当有消息时向对应的消费者推送消息需要消费者告诉消息队列,目前消费到哪个位置,然后再由消息队列发送对应的消息给其消费者
资源消耗需要消息队列对部分消费速度较慢或者出现推送失败的消费者进行消息缓冲然后重试需要消费者和消息队列之间建立长轮询,不断得询问消息队列是否有消息就绪
开源组件RabbitMQ、ActiveMQRabbitMQ、ActiveMQ、RocketMQKafka

3、消息队列存储选型

  • 磁盘存储vs内存存储

    维度硬盘内存
    成本
    容量(单机)
    访问速度慢(顺序IO>随机IO)
    存储特性非易失性存储,断电不丢数据易失性存储,断电丢数据
  • 磁盘IO vs 内存IO

结论:

1、磁盘访问时间:寻道时间+旋转时间+传输时间:
寻道时间:8ms~12ms
旋转时间:7200转/min:半周4ms 传输时间:50M/s,约0.3ms
2、磁盘随机IO ≪ 磁盘顺序IO ≈ 内存随机IO ≪ 内存顺序IO
3、机械磁盘和固态硬盘构成:
机械硬盘:电磁存储,通过电磁信号转变来控制读写,磁头机械臂移动。
固态硬盘:半导体存储,固态电子存储芯片阵列、由控制单元和存储单元组成,内部由闪存颗粒组成。速度较快。

  • 数据磁盘组织的几种模型
维度Innodb/boltdbBitcaskMossPebble/leveldb/rocksdb
适用场景读多写少写多读少写多读少写多读少
数据块文件是否有序有序无序有序有序
内存数据组织方式B+树ATR Tree(保存索引)lsm arrayskiplist等
磁盘数据组织方式采用页划分文件大小差不多的小文件不同大小的小文件分块的小文件、分层存放
数据结构b+树lsm hashlsm arraylsm tree
更新所属分类原地更新非原地更新
压缩方式定时根据内存中的索引重建新的文件,最后替换旧的文件在内存中压缩,在持久化时,也会检测是否压缩定时以及结合一些限制条件进行分层合并压缩

4、消息队列消费模型

1:N:M模型:1个topic下的数据由N个消费组消费,每个消费组下有M个消费者。

在这里插入图片描述

消费者组:为提高消费效率、引入消费者组,发布订阅时,以消费者组/订阅作为单位。offset是以(group+topic+partition)为单位维护。组间广播、组内单播

提示:一个消费队列一般只能被一个消费者组中的一个消费者消费。但一个消费者可以消费多个msg queue中的数据。[生产者负载均衡+消费者负载均衡]

二、kafka消息队列

1、 kafka单实例环境

(1)kafka主体模型

在这里插入图片描述

kafka消费模型:一个partition只能被一个消费者组中的一个消费者消费。但一个消费者可以消费多个partition数据。

(2)kafka消息存储、检索

  • 核心原则
    最大化结合磁盘特性,充分利用顺序IO(追加)写;同时采用文件分段存储方式组织,每条消息附加一个编号(offset);其次还保存了一些索引文件。

  • kafka存储文件

    文件类型主要有三类:xxx.log、xxx.index、xxx.timeindex
    1.xxx.log文件
    每个文件称为segment,每个segment文件以保存的第一条记录offset来命名。
    xxx.log文件内部
    保存以固定的格式每条消息序列化后的数据。
    2.xxx.index文件
    是索引文件。记录数据存储的具体偏移量。如:offset:22354367 position:15730 就是一条索引记录。
    3.xxx.timeindex文件
    是时间戳索引文件。如:timestamp:1552354531245 offset:22354367 就是一条时间戳索引记录。

    offset即偏移量,可以映射出消息在数据文件中物理位置

在Kafka每个segment段都是顺序写入的,也就是顺序写磁盘。同时每个segment端在命名时也很有讲究,每个segment段的命名以当前保存的第一条消息的编号(offset)按照16进制来命名,这样一来,所有的segment段是遵循有序规律的。这样的好处就是当查找某条消息时,可以通过二分查找很快定位到该条消息对应的segment段。然后读取该段的index文件,找到该消息写入数据文件的位置。再从数据文件读取消息内容。在这个过程中主要利用有序二分查找的特性。

(3)kafka消息清理

数据需要删除,否则的话磁盘空间最终会被占满,造成服务性能和可用性降低。

在Kafka中数据的清理也是以segment为单位进行清理的。

kafka采用两种清理方式:
基于每个日志文件中最大记录的时间戳删除。
基于设定的文件个数阈值删除。

2、 kafka多实例(集群)环境

kafka集群架构

在这里插入图片描述

kafka集群中几个名词含义

  • ISR:in-sync replica set
    每个分区中同步的副本列表,包括leader

  • LEO:log end offset
    每个服务维护的最新消息的offset

  • HW:high watermark
    HW=min(LEOleader ,LEOfollowers).
    所有ISR列表中,最小的LEO的取值

  • Committed Message
    以被所有的ISR同步的消息

  • Lagging Message
    没有达到所有ISR同步的消息

  • 一图说明 kafka集群中的几个名词

在这里插入图片描述

(1)kafka集群数据复制

在这里插入图片描述

(2)kafka集群数据一致性

ack取值ack=0ack=1ack=-1(all)
取值含义leader接收到消息后,立即返回给生产者leader接收到消息记录完毕后,返回给生产者leader接收到消息并同步给ISR中的follower节点。等待follower节点都响应leader后才返回给生产者
特点数据异步复制和存储,速度快、吞吐量高、可用性高、可靠性差Leader保存有完整数据,速度较快、吞吐量较高、可用性较高、可靠性较差Leader和ISR中的follower节点都保存有数据,同步较慢、可靠性较高
数据一致性丢失数据风险最高、基本没有一致性丢失数据风险较高丢失数据的风险最低。极端情况(ISR列表为空)时也有丢失数据的风险

(3)kafka集群故障转移

  • leader故障

1.重新选择一位leader(从ISR列表中选新的leader),选择标准是数据最新/最完整的节点。
2.保证集群节点间数据的一致性(无法保证不丢数据):每个节点都有自己的LEO(log end offset);定义HW(high watermark)其他follower节点截取日志到HW,然后从新leader拉取之后的日志

  • follower故障

follower发生故障后,从ISR中剔除该节点。当该节点重新启动后,根据上次记录的HW截取掉高于HW的日志,从leader节点开始同步HW之后的日志,当日志追赶上leader后(follower的LEO大于等于该partition的HW时),再将其加入到ISR列表中。

(4)如何保证消费一次、幂等性保证

  • At Most Once

    当ack=0时,可以保证生产者每条消息只会发送一次,即最多一次。

  • At Least Once

    当ack=-1时,可以保证生产者发送的消息不会丢失,即最少一次。

  • Exactly Once

    At Least Once + 幂等(0.11引入了幂等性) = Exactly Once。

kafka幂等性实现:给producer分配一个pid,然后往同一partition发送消息时会附带一个seq。broker内部会对<pid,partition,seq>进行缓存用作消息去重。

(5)kafka集群数据分片

  • 数据分片/分区
    一个topic可以设置多个分区partition。其中数据的高可用是按照partition为维度划分的。

  • 生产者分区策略
    轮询分区、随机分区、按照key分区、自定义分区;(核心原则:一条消息发给一个partition)。

  • 消费者分区策略
    轮询(roundRobin)策略、(range)策略;一个分区只能分配给一个消费者组里的一个消费者。

3、扩展:kafka为什么快?

Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗,通过mmap提高I/O速度,写入数据的时候由于单个Partion是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。

  • 数据分片/分区(提高并行度)

    Kafka 将消息分成多个 partition,增加了并行处理的能力。

  • 顺序写磁盘(提升写性能)

    Producer 发送的消息顺序追加到文件中,Consumer 从 Broker 自带偏移量读取消息。这两者可以充分利用磁盘的顺序写和顺序读性能,速度远快于随机读写。

  • 数据零拷贝(减少上下文切换和拷贝次数)

    mmap 持久化文件:Broker 写入数据,并非真正的 flush 到磁盘上了,而是写入到 mmap 中。

    sendfile 读取:Customer 从 Broker 读取数据,采用 sendfile,将磁盘文件读到 OS 内核缓冲区后,直接转到 socket buffer 进行网络发送。

  • 批处理(提升IO性能,减少网络传输开销)

    Producer 发送多个消息到同一分区,通过批量发送可以减少系统性能开销。

    • batch.size:默认积压到 16K 就会批量发送
    • linger.ms:设置一定延迟来收集更多消息。默认 0ms ,即有消息就立马发送。

    上述两个条件有任一条件满足,就会触发批量发送。

  • 数据压缩

    Kafka 支持三种压缩算法:lz4 gzip snappy。

三、RocketMQ消息队列

RocketMQ在架构设计上与Kafka非常相像。那么为什么还需要RocketMQ?

  • kafka存在问题:Kafka中单个broker分区过多,会导致有大量的segment段,同时顺序写变成随机写。
    RocketMQ为了解决这个问题,在数据文件设计上做了如下处理:[数据文件固定大小+索引文件固定大小]
    每个broker实例上所有的topic共用一个数据文件。该文件称为commitlog,该文件的特点是固定文件大小,然后采用mmap进行内存映射读取数据。 因为所有topic的数据都存储在一个数据文件中,即便随着topic数量的增加,同一时间在RocketMQ单个broker内也只有一个日志文件在执行写操作,完全是顺序写磁盘,从而彻底避免了kafka前面存在的随机写的问题,同时也能更好的利用组提交特性。
    既然数据是存储在一起,那就需要在索引上进行分开,每个topic对应的msgqueue内部存储的就是每条消息的索引信息,该索引信息也是固定长度(20字节:offset(8字节)+size(4字节)+tagHashCode(8字节))。同样索引文件也是固定大小的,单个文件大小为5.72M,可以存储30w条索引,索引定长设计后,可以充分利用操作系统的磁盘预读特性,这也是为什么RocketMQ在topic数据上升时吞吐量不会有明显影响的原因。

  • RocketMQ消息功能更加完备

    eg:消息过滤:消费者可以根据Tag或者自定义属性进行消息过滤
    消息可靠性:硬件资源可恢复的情况下,通过(同步双写)保证消息不丢失
    消息重试/重投:消费者消费消息失败重试;生产者同步生产消息失败重投,异步消息失败重试
    事务消息:支持分布式事务功能,可以将应用本地事务和发送消息定义到全局事务中,保证全局事务的原子性
    延时消息:支持延时消息(延时队列)功能,给消息指定特定时间消费
    流量控制:当broker处理能力达到瓶颈时,进行生产者流控;当消费者消费能力达到瓶颈时,进行消费者流控

在这里插入图片描述

1、 RocketMQ单实例环境

(1)RocketMQ主体模型

在这里插入图片描述

RocketMQ消费模型:RocketMQ中,一个msg queue只能被一个消费者组中的一个消费者消费。但一个消费者可以消费多个msg queue数据。

(2)RocketMQ消息存储、检索

  • 存储

在这里插入图片描述

  • 检索

在这里插入图片描述

  • 过滤

在这里插入图片描述

2、RocketMQ多实例(集群)

在这里插入图片描述

(1)RocketMQ故障转移

RocketMQ集群架构:主从(master/slave)架构< RocketMQ4.5以前>,Dledger(raft)架构<RocketMQ4.5以后>。

引入Dledger的目的:
解决故障自动转移问题。

在主从架构下,当master故障时,需要人工手动转移,选择新的master节点;为此解决该问题有两种方案:
方案1、借助zookeeper或者etcd第三方组件选主(引入新组件,运维复杂度增加)。
方案2、集群内部自发选主如利用raft协议选主。RocketMQ最终选择了方案2。

(2)RocketMQ负载均衡

  • 生成者负载均衡

在这里插入图片描述

  • 消费者负载均衡

在这里插入图片描述

(3)RocketMQ同步&异步

在这里插入图片描述

集群方式运维特点消息可靠性(master宕机)服务可用性(master宕机)其他特点备注
单Master结构简单,扩容方便,机器要求低同步刷盘消息一条都不会丢整体可用,未被消费的消息无法取得,影响实时性性能最高不推荐
多Master故障时会丢失消息整体可用,不影响实时性适合消息可靠性略高,实时性中等、性能要求不高的需求
Master-Slave(异步复制)结构复杂,扩容方便异步有毫秒级丢失,同步双写不丢失整体可用,实时性影响毫秒级别性能很高适合消息可靠性中等,实时性中等的要求
Master-Slave (同步双写)结构复杂,扩容方便不丢消息差评,主备不能自动切换,且备机只能读不能写,会造成服务整体不可写性能比异步低10%,所以实时性也并不比异步方式太高不考虑,除非自己提供主从切换的方案

3、扩展:RocketMQ为什么性能好?

  • 数据分散多集群(数据分片)
    在RocketMQ中,整个集群环境由多个分散的小集群组成,所以topic首先会分片到多个小集群中,然后每个小集群内部又会分成多个msgqueue。这两层的分片很大程度上提升了系统的性能。

  • 顺序写磁盘、磁盘预读
    RocketMQ存储模型设计时,设计成每个broker实例上所有的topic共用一个commitlog文件。从而保证全局顺序写。同时索引格式设计是固定长度,充分利用操作系统磁盘预读特性提升性能。

  • mmap内存映射
    RocketMQ commitlog在保证顺序写的情况下,通过采用mmap方式来加速读数据过程。使其随机读也不会大幅度影响系统性能。

四、kafka对比RocketMQ

1、架构对比

从图中我们可以看到它们整体的结构是大同小异的。主要由四部分组成:

  1. 生产者:数据的生产方,生产数据发送给Broker集群存储。
  2. Broker集群:消息队列的核心集群,存储生产者发送的数据,并分发给消费者消费。
  3. 消费者:消费生产者生产的消息。
  4. 元数据中心集群:Kafka中的zookeeper和RocketMQ中的NameServer都扮演同样的角色,内部维护集群以及topic相关的元数据 。
  • Kafka架构

在这里插入图片描述

  • RocketMQ架构

版本4.5之前:主从(master/slave)架构

在这里插入图片描述

版本4.5之后:Dledger(raft)架构

在这里插入图片描述

2、数据组织对比

从数据结构上来说,Kafka和RocketMQ有很大的区别:

  1. Kafka数据层级结构: topic->partition->segment->(.log、.index、.timeindex)
  2. RocketMQ数据层级结构: topic->分片topic->msgqueue->(offset)
    在这里插入图片描述
  • Kafka数据组织结构

在Kafka中一般由几台broker构成一个集群,一个topic(例如topicA)在创建时需要指定partition数和replicate副本数。这些partition会分散在每个broker上。一个topic会对应多个partition分区。每个partition都保存完整的数据,是一个逻辑上的队列结构。其中在每个分区内部数据又是按照segment分段存储的。每个segment中会包含数据文件(.log)、索引文件(.index、.timeindex)。
同时值得注意的是Kafka中数据的同步是以partition为维度进行的。

  • RocketMQ数据组织结构

RocketMQ集群通常是由多个内部小集群构成。同样在RocketMQ中对外访问时以topic为单位,在其内部一个topic会首先按照小集群进行分片,也就是分片topic,在每个小集群内部再将分片的topic拆分为多个msgqueue。每个msgqueue就是一个逻辑队列。在RocketMQ中,每个msgqueue也是分小段存储的,不过每个段中存储的都是每个消息的索引数据。
在RocketMQ中,数据同步是按照每个小集群进行同步的,每个小集群内部按照同步或者异步方式同步数据。

3、存储模型对比

在这里插入图片描述

五、总结

kafka提纲

1.单实例环境分析
1.1 单客户端数据生产、单客户端数据消费
1.2 数据中间缓存
1.3 多个客户端数据消费(同一个数据多次消费、同一个数据一次消费)—消费者组
1.4 数据掉电了怎么办?(存储)—存在哪?怎么存储?存储后怎么高效生产、怎么高效消费
1.5 数据存储方案详解
2.多实例分布式集群分析
2.1 为什么要有集群?(解决单点故障)
2.2 怎么提升吞吐量?(数据分片存储、读写分离等)
2.3 怎么解决单机容量问题?(数据分片存储)
2.4 数据怎么同步?怎么复制?
2.5 数据怎么分片?分片规则?
2.6 数据一致性怎么抉择?强一致还是弱一致?
3.整体方案概述
4.整体总结

RocketMQ提纲

1.rocketMQ特点
2.rocketMQ整体架构
3.rocketMQ单机特点
3.1数据如何存储
3.2数据如何检索
4.rocketMQ集群结构
4.1数据如何复制
4.2故障如何转移
4.3数据一致性
4.4数据分片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的程序猿~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值