什么是消息中间件?
消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。对于消息中间件,常见的角色大致也就有Producer(生产者)、Consumer(消费者)例如:寄快递。
常见消息中间件比较
RocketMQ
RocketMQ是阿里巴巴开源的分布式消息中间件,现在是Apache的一个顶级项目。在阿里内部使用非常广泛,已经经过了"双11"这种万亿级的应用场景考验。
1.RocketMQ的架构及概念
如上图所示,整体可以分成4个角色,分别是:NameServer,Broker,Producer,Consumer
为了方便理解,我们将整套RocketMQ可以理解成为一套完整的快递业务:
- Broker(邮递员):Broker是RocketMQ的核心,负责消息的接收,存储,投递等功能
- NameServer(邮局):消息队列的协调者,Broker向它注册路由信息,同时Producer和Consumer向其获取路由信息
- Producer(寄件人):消息的生产者,需要从NameServer获取Broker信息,然后与Broker建立连接,向Broker发送消息
- Consumer(收件人):消息的消费者,需要从NameServer获取Broker信息,然后与Broker建立连接,从Broker获取消息
- Topic(地区):用来区分不同类型的消息,发送和接收消息前都需要先创建Topic,针对Topic来发送和接收消息
- Message Queue(邮件):为了提高性能和吞吐量,引入了Message Queue,一个Topic可以设置一个或多个MessageQueue,这样消息就可以并行往各个Message Queue发送消息,消费者也可以并行的从多个Message Queue读取消息
- Message:Message 是消息的载体。
2.RocketMQ消息发送和接收演示
- 启动RocketMQ
在解压缩后的bin目录中启动cmd命令窗口:
输入指令:start mqnamesrv.cmd(启动NameServer);
输入指令:start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnable=true;
如果弹出框提示‘错误: 找不到或无法加载主类 xxxxxx’。在bin下找到并打开runbroker.cmd,然后将‘%CLASSPATH%’加上英文双引号
- 项目中加入RocketMQ依赖坐标:
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
- 发送同步消息(创造消息生产者)
/**
* @author 杨树林
* @version 1.0
* @since 14/8/2023
*/
//同步消息发送
public class RocketMQSendTest1 {
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
//1.创建消息生产者,指定生产者所属的组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("myproducer-group");
//2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("localhost:9876");
//3.启动生产者
defaultMQProducer.start();
//4.创建消息对象,指定主题,标签和消息体
for (int i = 0; i <10 ; i++) {
Message message = new Message("myTopic","myTag",("十行代码九个错误八个警告竟敢说七天精通六天学会五湖四海也不见如此三心二意之程序简直一等下流"+i).getBytes());
//5.发送消息
SendResult sendResult = defaultMQProducer.send(message);
System.out.println(sendResult);
}
//6.关闭生产者
defaultMQProducer.shutdown();
}
}
- 接收消息(创造消息消费者)
/**
* @author 杨树林
* @version 1.0
* @since 14/8/2023
*/
public class RocketMQReceiveTest1 {
public static void main(String[] args) throws MQClientException {
//1.创建消费者并分组
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("myconsumer-group");
//2.指定nameserver地址
consumer.setNamesrvAddr("localhost:9876");
//3.指定消费者订阅主题和标签
consumer.subscribe("myTopic","*");
//均衡模式:多个消费者瓜分生产者的消息
// consumer.setMessageModel(MessageModel.CLUSTERING);
//广播模式:多个消费者都拿到全部的生产者消息
consumer.setMessageModel(MessageModel.BROADCASTING);
//4.设置回调函数,编写处理消息的方法
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
//获取传输数据
System.out.println(new String(list.get(0).getBody()));
//返回消费状态
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//5.启动消费者
consumer.start();
System.out.println("Consumer Starting!");
}
}
- 发送方式除了同步发送以外,还有异步发送和单向发送两种
异步发送:异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
public class RocketMQSendTest2 {
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException {
//1.创建消息生产者
DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");
//2.指定nameserver
producer.setNamesrvAddr("localhost:9876");
//3.启动生产者
producer.start();
for (int i = 0; i <10 ; i++) {
Message message = new Message("myTopic","MyTag2","三二一".getBytes());
producer.send(message,new SendCallback(){
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("发送成功"+sendResult);
}
@Override
public void onException(Throwable throwable) {
System.out.println("发送失败"+throwable);
}
});
TimeUnit.SECONDS.sleep(3);
}
//关闭生产者
producer.shutdown();
}
}
单向发送:这种方式主要用在不特别关心发送结果的场景,例如日志发送。
//单向消息发送
public class RocketMQSendTest3 {
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
//1.创建消息生产者,指定生产者所属的组名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("myproducer-group");
//2.指定Nameserver地址
defaultMQProducer.setNamesrvAddr("localhost:9876");
//3.启动生产者
defaultMQProducer.start();
//4.创建消息对象,指定主题,标签和消息体
for (int i = 0; i <10 ; i++) {
Message message = new Message("myTopic", "myTag", "十行代码九个错误八个警告竟敢说七天精通六天学会五湖四海也不见如此三心二意之程序简直一等下流".getBytes());
//5.发送消息,没有返回值,只管发送,不管接收
defaultMQProducer.sendOneway(message);
}
//6.关闭生产者
defaultMQProducer.shutdown();
}
}
- 三种发送方式的区别: