RocketMQ整理

RocketMQ整理


一、RocketMQ的相关理论

1.基本概念

在这里插入图片描述1)消息生产者(Producer)
消息一般由业务系统产生,生产者将业务中产生的消息发送给Broker服务器。有多种发送方式:同步发送、异步发送、顺序发送、单向发送,使用同步或异步发送需要Broker返回确认信息。Producer与Name Server的一个随机节点建立长连接,定期从中获取Topic路由信息,并向提供Topic信息的Master建立长连接,且定时向Master发送心跳。

2)消息消费者(Consumer)
消息消费者从Broker服务器拉取消息,并将其提供给程序。从用户应用角度可分为两种消费方式:拉取式消费、推动式消费。Consumer与Name Server中的一个随机节点建立长连接,定期从中获取Topic路由信息,并向提供Topic路由信息的Master和Slave建立长连接,且定时向Master和Slave发送心跳。

3)代理服务器(Broker Server)
消息的中转角色,用来存储和转发消息。负责接收并存储Producer发送的消息,对Consumer发送的消息请求进行消息转发。Broker分为Master和Slave,一个Master可以有多个Slave,一个Slave只能有一个Master,通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0时表示Master,非0时表示Slave。每个Broker与Name Server中的所有节点建立长连接。(注:只有BrokerId=1的Slave才会参与消息的读负载)

4)主题(Topic)
表示一类消息的集合,每条消息只能属于一个Topic,一个Topic可以有多条消息,是RocketMQ进行消息订阅的基本单位。

5)名称服务(Name Server)
名称服务充当路由消息的提供者,Producer和Consumer通过名称服务查找各Topic所对应的Broker服务器。多个实例可组成集群,相互之间独立。

6)标签(Tag)
为消息设置的标识,用来区分同一Topic下不同类型的消息

7)消息队列(Message Queue)
Topic由一个或多个队列组成,Producer的发送机制使得消息尽量平均分布在多个队列中。RocketMQ保证的消息有序即分区(queue)消息的有序。

2.工作流程

  1. 启动Name Server,启动后监听端口,等待Broker、Producer、Consumer的连接,相当于路由控制中心;
  2. 启动Broker,跟所有的Name Server节点建立长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP + 端口)以及存储所有Topic信息。注册成功后,Name Server就有Topic跟Broker的映射信息;
  3. 收发消息前,先创建Topic,创建时需要指定该Topic存储在那些Broker上,也可以在发送消息时自动创建Topic;
  4. Producer发送消息,启动时先和Name Server中的一个节点建立长连接,并从Name Server中获取当前发送的Topic所对应的Broker,轮询从队列列表中选择一个队列,然后与队列所在的Broker建立长连接并发送消息。
  5. Consumer消费消息,启动时先和Name Server中的一个节点建立长连接,并从Name Server中获取当前订阅的Topic所对应的Broker,然后跟Broker建立连接通道,并进行消费。

二、RocketMQ的基础使用

导入依赖

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

1.基本样例

1)发送同步消息
必须等待消息持久化到磁盘中后,RocketMQ给生产者返回信息,才能继续执行后面的业务;

public static void main(String[] args) throws Exception {
	//实例化消息生产者
	DefaultMQProducer producer = new DefaultMQProducer("producerA");
	//设置Name Server地址
	producer.setNamesrvAddr("127.0.0.1:9876");
	//启动生产者
	producer.start();
	//创建消息
	Message messge = new Message(
			"TopicTest",	//指定Topic
			"TagA",			//指定Tag
			"RocketMQ同步消息".getBytes("utf-8")		//消息体
		);
	//发送消息
	SendResult result = producer.send(message);
	//通过SendResult返回消息判断是否成功送达
	System.out.println("%s%n", result);
	//不再发送消息,关闭连接
	producer.shutdown();
} 

2)发送异步消息
不需要等待消息持久化到磁盘中,就可以执行后面的业务,通常使用在对相应时间敏感的业务场景,即发送端不能长时间等待Broker响应;

public static void main(String[] args) throws Exception {
	//实例化消息生产者
	DefaultMQProducer producer = new DefaultMQProducer("producerB");
	//设置Name Server地址
	producer.setNamesrvAddr("127.0.0.1:9876");
	//启动生产者
	producer.start();
	//创建消息
	Message messge = new Message(
			"TopicTest",	//指定Topic
			"TagB",			//指定Tag
			"RocketMQ异步消息".getBytes("utf-8")		//消息体
		);
	//发送消息,SendCallback接收异步返回结果
	producer.send(message, new SendCallback() {
			//发送成功
			@Overrride
			public void onSuccess(SendResult result) {
        		System.out.println("消息发送成功");
    		}
    		//发送失败
    		@Override
    		public void onException(Throwable e) {
       			System.out.println("消息发送失败");
       			e.printStackTrace();
    		}
		});
	//等待信息返回,不能关闭连接
	//producer.shutdown();
} 

3)单向发送消息
用于不关心发送结果的业务场景,例如日志发送;

public static void main(String[] args) throws Exception {
	//实例化消息生产者
	DefaultMQProducer producer = new DefaultMQProducer("producerC");
	//设置Name Server地址
	producer.setNamesrvAddr("127.0.0.1:9876");
	//启动生产者
	producer.start();
	//创建消息
	Message message = new Message(
			"TopicTest",	//指定Topic
			"TagC",			//指定Tag
			"RocketMQ单向消息".getBytes("utf-8")		//消息体
		);
	//单向发送消息,没有返回结果
	producer.sendOneway(message);
	//不再发送消息,关闭连接
	producer.shutdown();
}

4)消费消息

public static void main(String[] args) throws Exception {
	//实例化消息消费者
	DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumerA");
	//设置Name Server地址
	consumer.setNamesrvAddr("127.0.0.1:9876");
	//订阅Topic并过滤Tag
	consumer.subscribe("TopicTest", "*");
	//注册回调实现类来处理从Broker获取到的消息
	consumer.registerMessageListener(new MessageListenerConcurrently() {
				@Override
				public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
					ConsumeConcurrentlyContext context) {
                		System.out.printf("%s Receive New Messages: %s %n", msgs);
                		// 标记该消息已经被成功消费
                		return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            	}
		});
	//启动消费者
	consumer.start();
}

2.顺序消息

顺序消费即FIFO,RocketMQ可以确保消息消费有序,分为分区有序和全局有序;

原理:默认情况下会采取Round Robin轮询方式把消息发送到不同的queue(分区队列)。消息消费时如果从一个queue中拉取,此时保证全局有序;如果从多个queue中拉取时,则只能保证分区有序,即相对于每一个queue,消息的消费都是有序的。

3.延时消息

只需要给要发送的消息设置延迟发送时间即可。

设置延时等级5,表示消息1分钟后发送;

message.setDelayTimeLevel(5);

延时等级如下:

private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";

4.批量消息

批量发送消息可以显著提高发送小消息的性能,限制是这批消息需要有相同的Topic和waitStoreMsgOK,且不能是延时消息。此外,这批消息总大小不能超过4M。不确定是否超过4M时最好进行消息列表分割。

List<Message> messages = new ArrayList<>();
messages.add(new Message("TopicA", "TagA", "批量消息第一条".getBytes("utf-8")));
messages.add(new Message("TopicA", "TagA", "批量消息第二条".getBytes("utf-8")));
messages.add(new Message("TopicA", "TagA", "批量消息第三条".getBytes("utf-8")));
messages.add(new Message("TopicA", "TagA", "批量消息第四条".getBytes("utf-8")));

5.过滤消息

Tag标志用来进行过滤选择想要的信息;

接受Topic为TopicTest下标志为TagA或TagB或TagC的信息:

consumer.subscribe("TopicTest", "TagA || TagB || TagC");

也可以通过使用SQL语句来进行复杂的选择:

例如两条信息如下:

|---------|
| message |
|---------|
|a = 7    |
|b = 'abc'|
|---------|

|---------|
| message |
|---------|
|a = 3    |
|b = 'abc'|
|---------|

如下为判断选择第一条

consumer.subscribe("TopicTest", MessageSelector.bySql("a > 5 and b = 'abc'"))

三、Springboot的集成使用

1.导入依赖

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.0.3</version>
</dependency>

2.配置文件

1)生产者配置

server:
  port: 8888
rocketmq:
  name-server: 127.0.0.1:9876
  producer:
    group: pro-group

2)消费者配置

server:
  port: 7777
rocketmq:
  name-server: 127.0.0.1:9876

3.代码示例

1)消息生产者

@RestController
public class Prod {
	@Autowired
	private RocketMQTemplate rocketMQTemplate;
	
	@RequestMapping("/sendOne")
	public String sendMsg(String message) throws Exception() {
		//发送同步消息
		rocketMQTemplate.syncSend("TopicA", message);

		//发送异步消息
		rocketMQTemplate.asyncSend("TopicA", message, new SendCallback() {
				@Override
    			public void onSuccess(SendResult sendResult) {
       				System.out.println("消费成功");
    			}
    			@Override
   				public void onException(Throwable e) {
        			System.out.println("消费失败");
    			}
			});

		//发送单向消息
		rocketMQTemplate.sendOneWay("TopicA", message);

		//发送延时消息,”5000“是超时时间,单位毫秒, “2”是延时等级
		rocketMQTemplate.syncSend("TopicA", MessageBuilder.withPayload(message).build(), 5000, 2);

		//过滤消息,需要使用 : 进行分隔
		rocketMQTemplate.syncSend("TopicA:" + "TagA", message);

		return "SUCCESS";
	}
}

2)消息消费者

@Component
@RocketMQMessageListener(
		//指定要监听的topic
		topic = "TopicA",
		//指定消费者组
		consumerGroup = "consumer-group",
		//指定消费模式为广播模式,为MessageModel.CLUSTERING时为集群模式
		messageModel = MessageModel.BROADCASTING,
		//指定Tag,过滤消息
		selectorType = SelectorType.TAG,
		selectorExpression = "TagA"
	)
public class Consu implements RocketMQListener<Message> {
	@Override
	public void onMessage(MessageExt messageExt) {
        System.out.println("消费消息" + new String(messageExt.getBody()));
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值