RocketMQ基础--系列之一

目录

1、什么是消息队列?

2、消息队列有哪些功能?

2.1 流量消峰

2.2 应用解耦

2.3 消息分发(异步)

3、RocketMQ

3.1 RocketMQ简介

3.2 RocketMQ使用

3.3 RocketMQ四大组件

3.3.1 Consumer

3.3.1.1 DefaultMQPushConsumer

3.3.1.2 DefaultMQPullConsumer

3.3.2 Producer

3.3.2.2 消息发送基本流程

3.3.2.3三种消息类型

3.3.3 NameServer

3.3.3.1 NameServer的集群状态存储结构

3.3.3.2 NameServer的状态维护逻辑

3.3.3.3 新建Topic

3.3.3.4 为何不用ZooKeeper

3.3.4 Broker

3.3.4.1 消息存储机制

3.3.4.2 刷盘机制

3.3.4.3 复制机制


1、什么是消息队列?

  • 消息队列一般简称为 MQ (Messges Queue),是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成,是在消息的传输过程中保存消息的容器。消息队列本质上是一个队列,而队列中存放的是一个个消息。
     
  • 队列是一个数据结构,具有先进先出的特点。而消息队列就是将消息放到队列里,用队列做存储消息的介质。消息的发送放称为生产者,消息的接收方称为消费者。
     
  • 消息队列由 Broker(消息服务器,核心部分)、Producer(消息生产者)、Consumer(消息消费者)、Topic(主题)、Queue(队列)和Message(消息体)组成。

2、消息队列有哪些功能?

消息队列主要有三个功能,分别是流量消峰、应用解耦和消息分发(异步)。

2.1 流量消峰

流量削峰主要用于在高并发情况下,业务异步处理,提供高峰期业务处理能力,避免系统瘫痪。


举个例子,假设Qunar订单系统每秒最多能处理1000次下单,这个处理能力应对正常时段的下单是绰绰有余的。但在五一、十一期间,下单QPS峰值达到了5000甚至更高,此时如果没有消息队列这种缓冲机制,为了保证系统稳定,我们只能在一秒内订单超过1000次后就不允许用户下单了;如果有消息队列做缓冲,我们可以取消这个限制,把一秒内下的订单分散成一段时间来处理,这时虽然有些用户可能在下单后十几秒才能收到下单成功的状态,但是也比不能下单的体验要好

2.2 应用解耦

应用解耦主要用于当一个业务需要多个模块共同实现时,只需要主业务完成以后,发送一条MQ,其余模块消费MQ消息,即可实现业务,降低模块之间的耦合。


复杂的应用里会存在多个子系统,比如在电商应用中有订单系统、库存系统、物流系统、支付系统等。这个时候如果各个子系统之间的耦合性太高,整体系统的可用性就会大幅降低。多个低错误率的子系统强耦合在一起,得到的是一个高错误率的整体系统
用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障或者因为升级等原因暂时不可用,都会造成下单操作异常,影响用户使用体验

当转变成基于消息队列的方式后,系统可用性就高多了,比如物流系统因为发生故障,需要几分钟的时间来修复,在这几分钟的时间里,物流系统要处理的内容被缓存在消息队列里,用户的下单操作可以正常完成。当物流系统恢复后,补充处理存储在消息队列里的订单信息即可,用户感知不到物流系统发生过几分钟的故障。

2.3 消息分发(异步)

消息分发主要用于某些数据需要被多个系统使用的场景。数据的产生方只需要把自己的数据写入一个消息队列即可,数据使用方根据各自需求订阅感兴趣的数据,不同系统所订阅的数据可以重复也可以不重复,互不干扰,也不必和数据产生方关联。


此外,消息分发也实现了异步的功能,对于一些实时性要求不高的业务,主系统可以将数据放入消息队列中后由其他系统来处理,主系统就可以继续执行后续操作,从而提高系统相应时间。

3、RocketMQ

3.1 RocketMQ简介

  • RocketMQ是一个纯Java、分布式、队列模型的开源消息中间件,前身是MetaQ,是阿里参考Kafka特点研发的一个队列模型的消息中间件,后开源给apache基金会成为了apache的顶级开源项目,具有高性能、高可靠、高实时、分布式特点。
     
  • RocketMQ由四部分组成,分布式消息队列是用来高效地传输消息的,它的功能和现实生活中的邮局收发信件很类似,我们类比地说一下相应的模块。现实生活中的邮政系统要正常运行,离不开下面这四个角色,一是发信者,二是收信者,三是负责暂存、传输的邮局,四是负责协调各个地方邮局的管理机构。对应到RocketMQ中,这四个角色就是Producer、Consumer、Broker和NameServer。

3.2 RocketMQ使用

启动RocketMQ的顺序是先启动NameServer,再启动Broker,这时候消息队列已经可以提供服务了,想发送消息就使用Producer来发送,想接收消息就使用Consumer来接收。


代码中导入依赖:

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.9.1</version>
</dependency>

启动NameServer:

start mqnamesrv -n 127.0.0.1:9876

启动Broker:

start mqbroker -n 127.0.0.1:9876 autoCreateTopicEnable=true


消费者接收消息:

public class RocketMqConsumer {
    public static void main(String[] args) throws MQClientException {
        new RocketMqConsumer().defaultMQPushConsumer();
    }
    public void defaultMQPushConsumer() throws MQClientException {
        //定义消费者,可以指定消费集群
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_group_name");
        //同样的,指定name server 的地址
        consumer.setNamesrvAddr("127.0.0.1:9876");
        //订阅topicA下的所有消息
        consumer.subscribe("topicA","*");
        //一个consumer可以订阅多个topic
        consumer.subscribe("topicB","*");
        consumer.subscribe("topicC","*");
        //程序第一次启动从消息队列头取数据
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        //注册订阅消息(消息监听)
        consumer.registerMessageListener(
                (MessageListenerConcurrently) (list, Context) -> {
                    MessageExt msg = list.get(0);
                    System.out.println("-收到消息:id-"+msg.getMsgId()
                            +","+ new String(msg.getBody(), StandardCharsets.UTF_8)
                            +","+"keys: "+msg.getKeys()
                    );
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
        );
        consumer.start();
        System.out.println("consumer消费者启动");
    }
}



生产者发送消息:

public class RocketMqProducer {
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值