主题(Topic)
一个生产者可以发送消息给一个或者多个Topic,消息的消费者也可以订阅一个或者多个Topic消息。
消息队列(Message Queue)
存储消息的容器,生产者发过来的消息就回存到这里。一个TopIc下面可以绑定多个Queue。
分组(Group)
同一个Consumer Group下的各个实例将共同消费topic的消息,起到负载均衡的作用,注意是平均分配。
标签(Tag)
RocketMQ支持给在发送的时候给消息打tag,同一个topic的消息虽然逻辑管理是一样的。但是消费同一个topic时,如果你消费订阅的时候指定的是tagA,那么tagB的消息将不会投递。
偏移量(Offset)
Message queue是无限长的数组。一条消息进来下标就会涨1,而这个数组的下标就是offset,Message queue中的max offset表示消息的最大offset。
在发送的时候,我们往往不需要指定Offset,消费的时候可以通过日志看到当前这条消息属于队列的哪个位置。
1、生产者发送消息:基于topIc发送,Tag是非必填。
2、TopIc是的数据都存在commitLog日志里面,通过comsumerQueue再去commitLog找具体数据内容,comsumerQueue就类似于索引,
所以queue1和queue是不同的消息队列,共同组成topIc的所有消息内容。
3、consumer针对于topIc有两种消费模式,【消费者分组并不是运行实体,而是一个逻辑资源】所以我们可以把consumer1和consumer2看成一个组,
也可以把consumer1和consumer3看成一个组,也就相当于是人为定义的一个概念。
消费消息
负载均衡消费:是指【队列】下单消息发给Group,Group下的消费者【分摊】消费
广播消费:队列消息发给Group,Group下的消费者【都投递一遍】消费。
上图说明:生产者,发送消息到topIc,topIC可以绑定多个队列,一个队列下面有多个【消费者组】,每个消费者组,下面有多个消费者。
发送同步消息、发送异步消息、单向发送
同步发送是指消息发送方发出数据后,同步等待,直到收到接收方发回响应之后才发下一个请求。这种可靠性同步地发送方式使用的比较广泛
2、发送异步消息
消息发送方在发送了一条消息后,不等接收方发回响应,接着进行第二条消息发送。发送方通过回调接口的方式接收服务器响应,并对响应结果进行处理
单向发送
单向(Oneway)发送特点为发送方只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。此方式发送消息的过程耗时非常短,一般在微秒级别。
三种消息发送的比较
1、拉取式消费
2、推送式消费
拉取式消费 :Consumer主动从Broker中拉取消息,主动权由Consumer控制。一旦获取了批量消息,就会启动消费过程。
不过,该方式的实时性较弱,即Broker中有了新的消息时消费者并不能及时发现并消费。
缺点:
间隔太短,空请求比例会增加;
间隔太长,消息的实时性太差。
推送式消费: 该模式下Broker收到数据后会主动推送给Consumer,该获取方式一般实时性较高。
该获取方式是典型的发布-订阅模式,即Consumer向其关联的Queue注册了监听器,一旦发现有新的消息到来就会触发回调,
去Queue中拉取消息。而这些都是基于Consumer与Broker间的【长连接】的,长连接的维护是需要消耗系统资源的。
负载均衡模式(集群消费)、广播消费
一个分组(Group)下的【多个消费者】【共同消费】队列消息,每个消费者处理的消息不同。一个Consumer Group中的各个Consumer实例【分摊】去消费消息,即一条消息只会投递到一个Consumer Group下面的一个实例。集群消费模式是消费者默认的消费方式。
广播消费模式中消息将对一个Consumer Group下的各个Consumer实例【都投递一遍】。即使这些 Consumer属于同一个Consumer Group,消息也会被Consumer Group 中的每个Consumer都消费一次
集群模式: 消费进度保存在broker中。consumer group中的所有consumer共同消费同一个Topic中的消息,
同一条消息只会被消费一次。消费进度会参与到了消费的负载均衡中,故消费进度是需要共享的。
广播模式: 消费进度保存在consumer端。因为广播模式下consumer group中每个consumer都会消费所有消息,
但它们的消费进度是不同。所以consumer各自保存各自的消费进度。
有序包含:【分区有序】或者【全局有序】
生产消息时在默认的情况下消息发送会采取Round Robin轮询方式把消息发送到不同的queue(分区队列);
而消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。
但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序
当发送和消费参与的queue只有一个,则是【全局有序】
如果多个queue参与,则为【分区有序】,即相对于每个queue,消息都是有序的。
全局有序
全局有序,全局是相对于多个消息生产者,那就要保证队列和消费只有一个。
全局有序比较简单,主要控制在于创建Topic指定只有一个队列,同步确保生产者与消费者都只有一个实例进行即可。
分区有序:分区有序是指多个队列时,每个队列里面的消息,是有序的。但是队列和队列的有序是没有办法保障的。
要完成分区有序性,在生产者环节使用自定义的【消息队列选择】策略,确保【相同的业务数据】消息会被先后发送到同一个
队列中,然后再消费端开启【负载均衡模式】,最终确保一个消费者拿到的消息对于【同一业务】数据来说是有序的。
【负载均衡】默认就是使用【平均分配算法】。
Producer 将消息发送到消息队列 RocketMQ 服务端,但并不期望这条消息立马投递(被消费者消费),而是延迟一定时间后才投递到 Consumer 进行消费,该消息即延时消息。
目前只支持固定精度的定时消息,因为如果要支持任意的时间精度,在 Broker 层面,必须要做消息排序,如果再涉及到持久化,那么消息排序要不可避免的产生巨大性能开销。(RocketMQ的商业版本Aliware MQ提供了任意时刻的定时消息功能,Apache的RocketMQ并没有,阿里并没有开源)
Apache RocketMQ发送延时消息是设置在每一个消息体上的,在创建消息时设定一个延时时间长度,消息将从当前发送时间点开始延迟固定时间之后才开始投递。
延迟消息的level,区分18个等级:level为1,表示延迟1秒后消费;level为2表示延迟5秒后消费;level为3表示延迟10秒后消费;以此类推;最大level为18表示延迟2个小时消费。
在高并发场景中,批量发送消息能显著提高传递消息发送时的性能(减少网络连接及IO的开销)。
1、使用批量消息时的限制是这些批量消息应该有【相同的topic】,相同的【waitStoreMsgOK】(集群时会细讲),
且不能是延时消息。
在发送批量消息时先构建一个消息对象集合,然后调用send(Collection msg)系列的方法即可。
由于批量消息的4MB限制,所以一般情况下在集合中添加消息需要先计算当前集合中消息对象的大小是否超过限制,
如果超过限制也可以使用分割消息的方式进行多次批量发送。
在实际的开发应用中,对于【同一类消息】尽可能使用一个Topic进行存储,但在消费时需要选择您想要的消息,
这时可以使用RocketMQ的消息过滤功能,具体实现是利用消息的Tag和Key。
【Key】一般用于消息在业务层面的唯一标识。对发送的消息设置好 Key,以后可以根据这个 Key 来查找消息。
比如消息异常了,导致消息丢失,进行查找会很方便。
RocketMQ会创建专门的索引文件,用来存储 Key与消息的映射,由于底层实现是Hash索引,应尽量使 Key唯一,避免潜在的哈希冲突。
【Tag】可以理解为是二级分类。以淘宝交易平台为例,订单消息和支付消息属于不同业务类型的消息,
分别创建OrderTopic 和PayTopic,其中订单消息根据不同的商品品类以不同的 Tag 再进行细分,
如手机类、家电类、男装类、女装类、化妆品类,最后它们都被各个不同的系统所接收。通过合理的使用 Topic 和 Tag,
可以让业务结构清晰,更可以提高效率。
Key和Tag的主要差别是使用场景不同,Key主要用于通过命令行命令查询消息,而Tag用于在消息端的代码中,用来进行服务端消息过滤。
使用Tag过滤的方式是在消息生产时传入感兴趣的Tag标签,然后在消费端就可以根据Tag来选择您想要的消息。具体的操作是在创建Message的时候添加,一个Message只能有一个Tag
。。。。。。。
开启事务消息需要经历2个流程,先是发送Mq变成【半事务阶段】,然后在发送提交或者撤销命令也叫【确认阶段】
半事务阶段:
该阶段主要发一个消息到rocketmq,但该消息只储存在commitlog中,但consumeQueue中不可见,
也就是消费端(订阅端)无法看到此消息
确认阶段(commit/rollback):
该阶段主要是把半事务消息保存到consumeQueue中,即让消费端可以看到此消息,也就是可以消费此消息。
如果是rollback就不保存。
流程:
1、生产者将消息发送至Apache RocketMQ服务端。
2、Apache RocketMQ服务端将消息持久化成功之后,向生产者返回Ack确认消息已经发送成功,此时
消息被标记为"暂不能投递",这种状态下的消息即为半事务消息。
3、生产者开始执行本地事务逻辑。
4、生产者根据本地事务执行结果向服务端提交二次确认结果(Commit或是Rollback),服务端收到确认结果后处理逻辑如下:
4.1 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者。
4.2 二次确认结果为Rollback:服务端将回滚事务,不会将半事务消息投递给消费者。
5、在断网或者是生产者应用重启的特殊情况下,若服务端未收到发送者提交的二次确认结果,或服务端收到的二次确
认结果为Unknown未知状态,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查。
说明 服务端回查的间隔时间和最大回查次数,请参见参数限制。
6、生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
7、生产者根据检查到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。
RocketMQ 中"Request-Reply"模式允许Producer发出消息后,以同步或异步的形式等Consumer消费并返回一个响
应消息,达到类似RPC的调用过程。
RocketMQ因为有高可靠性的要求(宕机不丢失数据),所以数据要进行持久化存储。所以RocketMQ 采用文件进行存储。
CommitLog:存储消息的元数据
ConsumerQueue:存储消息在CommitLog的索引
IndexFile:为了消息查询,提供了一种通过key或时间区间来查询消息的方法,这种通过IndexFile来查找消息的方法不影响发送与消费消息的主流程
存储
RocketMQ消息的存储是由ConsumeQueue和CommitLog配合完成的
消息真正的物理存储文件是CommitLog,ConsumeQueue是消息的逻辑队列,类似数据库的索引文件,存储的是指向物理存储的地址。
每个Topic下的每个Message Queue都有一个对应的ConsumeQueue文件。
清楚机制:
由于 RocketMQ 操作 CommitLog,ConsumeQueue文件是基于内存映射机制并在启动的时候会加载 commitlog,ConsumeQueue 目录下的所有文件,
为了避免内存与磁盘的浪费,不可能将消息永久存储在消息服务器上,所以需要引入一种机制来删除己过期的文件。
删除过程分别执行清理消息存储文件( Commitlog )与消息消费队列文件( ConsumeQueue 文件), 消息消费队列文件与消息存储文件共用一套过期文件机制。
RocketMQ 清除过期文件的方法是 :如果非当前写文件在一定时间间隔内没有再次被更新,则认为是过期文件,可以被删除,
RocketMQ 不会关注这个文件上的消息是否全部被消费。默认每个文件的过期时间为 42小时(不同版本的默认值不同,这里以4.4.0为例) ,
通过在 Broker 配置文件中设置 fileReservedTime 来改变过期时间,单位为小时。
触发文件清除操作的是一个定时任务,而且只有定时任务,文件过期删除定时任务的周期由该删除决定,默认每10s执行一次。
文件删除主要是由这个配置属性:fileReservedTime-文件保留时间。也就是从最后一次更新时间到现在,如果超过了该时间,则认为是过期文件, 可以删除。
RocketMQ 如何保证消息正常【投递】和【消费】
Message是RocketMQ消息引擎中的主体。messageId是全局唯一的。MessageKey是业务系统(生产者)生成的,所以如果要结合业务,
可以使用MessageKey作为业务系统的唯一索引。
Message{
String MessageKey;
xxx equals(){}
xxx hashCode(){}
}
另外Message中的equals方法和hashCode主要是为了完成消息只处理一次(Exactly-Once)。
Exactly-Once是指发送到消息系统的消息只能被消费端处理且仅处理一次,即使生产端重试消息发送导致某消息重复投递,该消息在消费端也只被消费一次。
Tags是在同一Topic中对消息进行分类的。
Queue是消息物理管理单位,一个topIc下面会有多个Queue,多个Queue对应的数据共同组成了TopIc所有的消息,
对于每一个Queue来说都有Offset,这个是消费位点。
topic、queue是逻辑概念,topic和queue是一对多的关系。
queue是逻辑上存储消息的队列,物理上存储消息的是broker中的commitLog。
在commitLog中,每一条消息都有一个queueId。queue信息是由comsumerQueue来维护,可以把comsumerQueue看成索引,commitLog看成数据文件, comsumerQueue与commitLog存在映射关系。
RocketMq官方文档:跳转
详细介绍文档:跳转