RocketMQ-消息发送-消费-消息存储

消息发送

生产者向消息队列里写入消息,不同的业务场景需要生产者采用不同的写入策略。比如同步发送、异步发送、Oneway发送、延迟发送、发送事务消息等。 默认使用的是DefaultMQProducer类,发送消息要经过五个步骤:

1)设置Producer的GroupName。
2)设置InstanceName,当一个Jvm需要启动多个Producer的时候,通过设置不同的
InstanceName来区分,不设置的话系统使用默认名称“DEFAULT”。
3)设置发送失败重试次数,当网络出现异常的时候,这个次数影响消息的重复投递次数。想保证不丢消息,可以设置多重试几次。
4)设置NameServer地址
5)组装消息并发送

消息发生返回状态(SendResult#SendStatus)有如下四种:
FLUSH_DISK_TIMEOUT
FLUSH_SLAVE_TIMEOUT
SLAVE_NOT_AVAILABLE
SEND_OK
不同状态在不同的刷盘策略和同步策略的配置下含义是不同的

  1. FLUSH_DISK_TIMEOUT:表示没有在规定时间内完成刷盘(需要Broker的刷盘策略被设置成SYNC_FLUSH才会报这个错误)。
  2. FLUSH_SLAVE_TIMEOUT:表示在主备方式下,并且Broker被设置成SYNC_MASTER方式,没有在设定时间内完成主从同步。
  3. SLAVE_NOT_AVAILABLE:这个状态产生的场景和FLUSH_SLAVE_TIMEOUT类似,表示在主备方式下,并且Broker被设置成SYNC_MASTER,但是没有找到被配置成Slave的Broker。
  4. SEND_OK:表示发送成功,发送成功的具体含义,比如消息是否已经被存储到磁盘?消息是否被同步到了Slave上?消息在Slave上是否被写入磁盘?需要结合所配置的刷盘策略、主从策略来定。这个状态还可以简单理解为,没有发生上面列出的三个问题状态就是SEND_OK。

写一个高质量的生产者程序,重点在于对发送结果的处理,要充分考虑各种异常,写清对应的处理
逻辑。
提升写入的性能
发送一条消息出去要经过三步

  1. 客户端发送请求到服务器。
  2. 服务器处理该请求。
  3. 服务器向客户端返回应答
    一次消息的发送耗时是上述三个步骤的总和。
    在一些对速度要求高,但是可靠性要求不高的场景下,比如日志收集类应用, 可以采用Oneway方式发送

Oneway方式只发送请求不等待应答,即将数据写入客户端的Socket缓冲区就返回,不等待对方返回结果。
用这种方式发送消息的耗时可以缩短到微秒级。
另一种提高发送速度的方法是增加Producer的并发量,使用多个Producer同时发送,
不用担心多Producer同时写会降低消息写磁盘的效率,RocketMQ引入了一个并发窗口,在窗口内消息可以并发地写入DirectMem中,然后异步地将连续一段无空洞的数据刷入文件系统当中。

顺序写CommitLog可让RocketMQ无论在HDD还是SSD磁盘情况下都能保持较高的写入性能。

在Linux操作系统层级进行调优,推荐使用EXT4文件系统,IO调度算法使用deadline算法

消息消费

简单总结消费的几个要点:

  1. 消息消费方式(Pull和Push)
  2. 消息消费的模式(广播模式和集群模式)
  3. 流量控制(可以结合sentinel来实现,后面单独讲)
  4. 并发线程数设置
  5. 消息的过滤(Tag、Key) TagA||TagB||TagC * null
    当Consumer的处理速度跟不上消息的产生速度,会造成越来越多的消息积压,这个时候首先查看消费逻辑本身有没有优化空间,除此之外还有三种方法可以提高Consumer的处理能力。
  • 提高消费并行度
    在同一个ConsumerGroup下(Clustering方式),可以通过增加Consumer实例的数量来提高并行度。
    通过加机器,或者在已有机器中启动多个Consumer进程都可以增加Consumer实例数。
    注意:总的Consumer数量不要超过Topic下Read Queue数量,超过的Consumer实例接收不到消息。
    此外,通过提高单个Consumer实例中的并行处理的线程数,可以在同一个Consumer内增加
    并行度来提高吞吐量(设置方法是修改consumeThreadMin和consumeThreadMax)

  • 以批量方式进行消费
    某些业务场景下,多条消息同时处理的时间会大大小于逐个处理的时间总和,比如消费消息中涉及update某个数据库,一次update10条的时间会大大小于十次update1条数据的时间。
    可以通过批量方式消费来提高消费的吞吐量。实现方法是设置Consumer的consumeMessageBatchMaxSize这个参数,默认是1,如果设置为N,在消息多的时候每次收到的是个长度为N的消息链表。

  • 检测延时情况,跳过非重要消息
    Consumer在消费的过程中,如果发现由于某种原因发生严重的消息堆积,短时间无法消除堆积,这个时候可以选择丢弃不重要的消息,使Consumer尽快追上Producer的进度

消息存储

  • 存储介质
    关系型数据库DB
    Apache下开源的另外一款MQ—ActiveMQ(默认采用的KahaDB做消息存储)可选用JDBC的方式来做消息持久化,通过简单的xml配置信息即可实现JDBC消息存储。由于,普通关系型数据库(如Mysql)在单表数据量达到千万级别的情况下,其IO读写性能往往会出现瓶颈。在可靠性方面,该种方案非常依赖DB,如果一旦DB出现故障,则MQ的消息就无法落盘存储会导致线上故障
    在这里插入图片描述
    文件系统
    目前业界较为常用的几款产品(RocketMQ/Kafka/RabbitMQ)均采用的是消息刷盘至所部署虚拟机/物理机的文件系统来做持久化(刷盘一般可以分为异步刷盘和同步刷盘两种模式)。消息刷盘为消息存储提供了一种高效率、高可靠性和高性能的数据持久化方式。除非部署MQ机器本身或是本地磁盘挂了,否则一般是不会出现无法持久化的故障问题
    在这里插入图片描述

性能对比
文件系统>关系型数据库DB
消息的存储和发送

  1. 消息存储
    目前的高性能磁盘,顺序写速度可以达到600MB/s, 超过了一般网卡的传输速度。
    但是磁盘随机写的速度只有大概100KB/s,和顺序写的性能相差6000倍!
    因为有如此巨大的速度差别,好的消息队列系统会比普通的消息队列系统速度快多个数量级。
    RocketMQ的消息用顺序写,保证了消息存储的速度

  2. 存储结构
    RocketMQ消息的存储是由ConsumeQueue和CommitLog配合完成 的,消息真正的物理存储文件是CommitLog,ConsumeQueue是消息的逻辑队列,类似数据库的索引文件,存储的是指向物理存储的地址。每 个Topic下的每个Message Queue都有一个对应的ConsumeQueue文件

在这里插入图片描述
消息存储架构图中主要有下面三个跟消息存储相关的文件构成。
(1) CommitLog:消息主体以及元数据的存储主体,存储Producer端写入的消息主体内容,消息内容不是定长的。单个文件大小默认1G ,文件名长度为20位,左边补零,剩余为起始偏移量,比如0000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。消息主要是顺序写入日志文件,当文件满了,写入下一个文件

在这里插入图片描述

(2) ConsumeQueue:消息消费队列,引入的目的主要是提高消息消费的性能RocketMQ是基于主题topic的订阅模式,消息消费是针对主题进行如果要遍历commitlog文件根据topic检索消息是非常低效。Consumer即可根据ConsumeQueue来查找待消费的消息。
其中,ConsumeQueue(逻辑消费队列)作为消费消息的索引:

  1. 保存了指定Topic下的队列消息在CommitLog中的起始物理偏移量offset
  2. 消息大小size
  3. 消息Tag的HashCode值

consumequeue文件可以看成是基于topic的commitlog索引文件,故consumequeue文件夹的组织方式如下:
topic/queue/file三层组织结构
具体存储路径为:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}。

在这里插入图片描述
consumequeue文件采取定长设计,每个条目共20个字节,分别为:

  1. 8字节的commitlog物理偏移量
  2. 4字节的消息长度
  3. 8字节tag hashcode
    单个文件由30W个条目组成,可以像数组一样随机访问每一个条目
    每个ConsumeQueue文件大小约5.72M

(3) IndexFile:IndexFile(索引文件)提供了一种可以通过key或时间区间来查询消息的方法。

  1. Index文件的存储位置是: H O M E / s t o r e / i n d e x / HOME/store/index/ HOME/store/index/{fileName}
  2. 文件名fileName是以创建时的时间戳命名的
  3. 固定的单个IndexFile文件大小约为400M
  4. 一个IndexFile可以保存 2000W个索引
  5. IndexFile的底层存储设计为在文件系统中实现HashMap结构,故rocketmq的索引文件其底层实现为hash索引

在这里插入图片描述

过滤消息

RocketMQ分布式消息队列的消息过滤方式有别于其它MQ中间件,是在Consumer端订阅消息时
再做消息过滤的。

RocketMQ这么做是在于其Producer端写入消息和Consumer端订阅消息采用分离存储的机制来实现的,Consumer端订阅消息是需要通过ConsumeQueue这个消息消费的逻辑队列拿到一个索引,然后再从CommitLog里面读取真正的消息实体内容,所以说到底也是还绕不开其存储结构。

其ConsumeQueue的存储结构如下,可以看到其中有8个字节存储的Message Tag的哈希值,基于Tag的消息过滤正式基于这个字段值的

在这里插入图片描述
主要支持如下2种的过滤方式
(1) Tag过滤方式:Consumer端在订阅消息时除了指定Topic还可以指定TAG,如果一个消息有多
个TAG,可以用||分隔。

  1. Consumer端会将这个订阅请求构建成一个 SubscriptionData,发送一个Pull消息的请求给
    Broker端。
  2. Broker端从RocketMQ的文件存储层—Store读取数据之前,会用这些数据先构建一个
    MessageFilter,然后传给Store。
  3. Store从 ConsumeQueue读取到一条记录后,会用它记录的消息tag hash值去做过滤。
  4. 在服务端只是根据hashcode进行判断,无法精确对tag原始字符串进行过滤,在消息消费端拉
    取到消息后,还需要对消息的原始tag字符串进行比对,如果不同,则丢弃该消息,不进行消
    息消费

(2) SQL92的过滤方式:
仅对push的消费者起作用。
Tag方式虽然效率高,但是支持的过滤逻辑比较简单。
SQL表达式可以更加灵活的支持复杂过滤逻辑,这种方式的大致做法和上面的Tag过滤方式一样,
只是在Store层的具体过滤过程不太一样
真正的 SQL expression 的构建和执行由rocketmq-filter模块负责的。
每次过滤都去执行SQL表达式会影响效率,所以RocketMQ使用了BloomFilter避免了每次都去执行。
SQL92的表达式上下文为消息的属性
在这里插入图片描述
在这里插入图片描述
首先需要开启支持SQL92的特性,然后重启broker:

mqbroker -n localhost:9876 -c /opt/rocket/conf/broker.conf

RocketMQ仅定义了几种基本的语法,用户可以扩展:

  1. 数字比较: >, >=, <, <=, BETWEEN, =
  2. 字符串比较: =, <>, IN; IS NULL或者IS NOT NULL;
  3. 逻辑比较: AND, OR, NOT;
  4. Constant types are: 数字如:123, 3.1415; 字符串如:‘abc’,必须是单引号引起来 NULL,特殊常量 布尔型如:TRUE or FALSE;

在这里插入图片描述
(3) Filter Server方式。这是一种比SQL表达式更灵活的过滤方式,允许用户自定义Java函数,根据Java函数的逻辑对消息进行过滤。

要使用Filter Server,首先要在启动Broker前在配置文件里加上 filterServer-Nums=3 这样的配置,Broker在启动的时候,就会在本机启动3个Filter Server进程。Filter Server类似一个RocketMQ的Consumer进程,它从本机Broker获取消息,然后根据用户上传过来的Java函数进行过滤,过滤后的消息再传给远端的Consumer。

这种方式会占用很多Broker机器的CPU资源,要根据实际情况谨慎使用。上传的java代码也要经过检查,不能有申请大内存、创建线程等这样的操作,否则容易造成Broker服务器宕机

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值