一、 消息中间的入门
一、RocketMq
1、搭建RocketMq
1)、首先需要JDK,Maven,git环境,自行安装
2)、下载RocketMq
3)、解压和编译
unzip rocketmq-all-4.7.1-source-release.zip //解压
cd rocketmq-all-4.7.1/
mvn -Prelease-all -DskipTests clean install -U //编译
cd distribution/target/rocketmq-4.7.1/rocketmq-4.7.1 //到路径下
4)、启动MQ
nohup sh bin/mqnamesrv & # 启动nameserver
tail -f ~/logs/rocketmqlogs/namesrv.log #查看日志
nohup sh bin/mqbroker -n localhost:9876 & # 启动broke
tail -f ~/logs/rocketmqlogs/broker.log # 查看启动日志
启动Nameserver
启动broke
5)、测试发送数据与接受数据
最好开两个命令行窗口
- 发送数据:设置环境变量,启动生产者
export NAMESRV_ADDR=localhost:9876
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
- 接受数据:设置环境变量,启动消费者
export NAMESRV_ADDR=localhost:9876
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
6)、关闭MQ
# 关闭NameServer
sh bin/mqshutdown namesrv
# 关闭Borker
sh bin/mqshutdown borker
7)rocketMq的可视化控制台
-
下载项目地址:https://github.com/apache/rocketmq-externals
-
cd rocketmq-console 下,这就是 RocketMQ 可视化控制台
-
打包rocketmq-console,用maven命令 mvn clean package
-
把打包好的项目启动,其实就是springboot项目,启动命令:mvn spring-boot:run
-
可视化页面
2、RocketMq的学习
2.1 组成结构
Producer:消息的生产者
Consumer:消息的消费者
Broker:消息的队列,broker会有很多的cluster(节点)
NameServer:收集broker能进行提供服务的节点,类似于微服务的注册中心。
交互的过程:
- Broker定时发送自身状态到NameServer;
- Producer请求NameServer获取Broker的地址;
- Producer将消息发送到Broker中的消息队列;
- Consumer订阅Broker中的消息队列,通过拉取消息,或由Broker将消息推送至Consumer
2.2 三种消息发送方式
1、同步消息
producer向broker发送消息,执行API时同步等待,直到broker服务器返回发送结果
2、异步消息
producer向broker发送消息时 ,指定消息发送成功或者发送异常时会有回调方法,调用API后立即返回。producer发送消息线程不阻塞,消息发送成功或者失败的回调任务可以在一个新线程中返回。
3、单向消息
producer向broker发送消息,执行API时直接返回,不等待broker服务器的结果。
2.3 消息结构
1、基础属性
- topic :主题相当于消息的一级分类,具有相同的topic的消息将发送至该topic下的消息队列中。如果一个电商系统可以分为商品消息、订单消息、物流消息等,可以在broker中创建商品主题、订单主题等,所有商品的消息发送至该主题下的消息队列中
- 消息体:消息的内容,可以是字符串,对象等类型(可序列化),消息的最大长度是4M
- 消息Flag:消息的一个标记
2、扩展属性 - tag:相当于消息的二级分类,用于消费消息时进行过滤,可为空
- keys:Message索引键,在运维中可根据这些key快速检索到消息,可为空
- waitStoreMsgOk:消息发送时是否等消息存储完后再返回
2.4 实现
1、创建maven项目,引入maven依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.5.1</version>
</dependency>
2、同步发送消息
/**
* 1、同步发送消息
*/
public class SyncProducer {
public static void main(String[] args) throws Exception {
//声明并初始化一个producer
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
//设置NameServer地址,多个地址之间用;
producer.setNamesrvAddr("127.0.0.1:9876");
//启动
producer.start();
//发送消息到Topic为TopicTest,tag为TagA,消息内容为(Hello RockrtMQ)+i的值
for (int i =0;i<100;i++){
Message msg = new Message("TopicTest","TagA",("Hello RockrtMQ"+i).getBytes(RemotingHelper.DEFAULT_CHARSET));
//调用的是同步send方法,会有返回值
SendResult sendResult = producer.send(msg);
//打印返回结果
System.out.printf("%s%n",sendResult);
}
producer.shutdown();
}
}
2、异步发送消息
/**
* 2、异步发送消息
* 异步传输常用于响应时间敏感的业务场景中
*/
public class AsyncProducer {
public static void main(String[] args) throws MQClientException, InterruptedException {
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
producer.setRetryTimesWhenSendAsyncFailed(0);
int messageCount = 100;
//根据消息数量实例化倒计时计算器
final CountDownLatch countDownLatch = new CountDownLatch(messageCount);
for (int i = 0;i<messageCount;i++){
try {
final int index = i;
//创建消息,并指定Topic,Tag和消息体
Message msg = new Message("Jodie_topic_1023",
"TagA",
"OrderID188",
"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
//sendCallBack接收异步返回结果的回调
producer.send(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
countDownLatch.countDown();
System.out.printf("%-10d OK %s %n", index, sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
countDownLatch.countDown();
System.out.printf("%-10d Exception %s %n", index, e);
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
countDownLatch.await();
producer.shutdown();
}
}
3、单向模式
/**
*3、以单向模式发送消息
* 单向传输用于要求中等可靠性的情况,如日志收集
*/
public class OnewayProducer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
for (int i = 0;i<10;i++){
Message msg = new Message("TopicTest","TagA",("Hello RocketMQ"+i).getBytes(
RemotingHelper.DEFAULT_CHARSET));
//发送单向消息,没有任何返回结果
producer.sendOneway(msg);
}
Thread.sleep(5000);
producer.shutdown();
}
}
4、消费者
/**
* 消费消息
*/
public class Consumer {
public static void main(String[] args) throws MQClientException {
//初始化一个consumer
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
//设置NameServer地址
consumer.setNamesrvAddr("127.0.0.1:9876");
//这里设置的是一个consumer的消费策略
//CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,即跳过历史消息
//CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
//CONSUME_FROM_TIMESTAMP 从某个时间点开始消费,和setConsumeTimestamp()配合使用,默认是半个小时以前
//consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
//设置订阅的Topic和Tag,*代表全部Tag
consumer.subscribe("TopicTest","*");
//设置一个listener,对消息进行处理
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
System.out.printf("%s Receive New Messages: %s %n",Thread.currentThread().getName(),list);
//返回消息状态
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
二、RabbitMq
1、搭建RabbitMq
1)、安装HomeBrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2)、安装完后可用brew命令安装rabbitMq
brew install rabbitmq
但是在下载过程中会出现错误
这个时候,你可以回车再次下载,可能是网络影响了你的下载。直到出现
安装成功
3)、启动可视化,查看你rabbitMq安装的位置
sudo /usr/local/Cellar/rabbitmq/3.8.3/sbin/rabbitmq-server
启动成功
输入 http://127.0.0.1:15672 ,进入rabbitMq的管理页面
默认的 用户名:guest 密码:guest