目录
[MQ 的优势](#MQ 的优势)
[MQ 的劣势](#MQ 的劣势)
基本概念
多个系统之间的通信方式有两种,一是直接远程调用,二是通过第三方,mq就是这个第三方
MQ 的优势
1.应用解耦
一个好的系统肯定会要求高内聚低耦合。
像下面这个,订单系统发个订单到库存时,如果库存系统损坏了可能会连带影响订单系统。
有了mq之后,消息存放在mq里面,哪怕库存坏了几分钟,好了之后也可以从mq中接着拿消息出来。
还有一个时,如果要添加一个新的x系统,一般要修改订单系统的代码来兼容。
有了mq之后,订单系统会把所有消息都放到mq里面,新的系统的不管是什么都从mq里面拿东西就好了,就不需要改代码了
2.异步提速
同步下需要走完整个流程才能有反馈,所以很慢。
异步下,即使没有运行完整个流程,也会立刻返回消息,后面的系统会继续从mq中取出消息执行。这种属于是骗人
3.削峰填谷
瞬时请求太多致使服务器宕机了。
mq在这里只是缓存消息和发布消息,不负责业务逻辑处理,因此完全可以承载更多的请求。
如果一层mq解决不了,那就再加一层。
使用mq技术在项目里面之后这些优势可以作为项目亮点写在简历上。
MQ 的劣势
使用mq的条件
常见MQ产品
RabbitMQ简介
RabbitMQ支持AMQP协议,
在AMQP中,交换机分发消息,queue存储消息。分发通过Routes进行 。
RabbitMq里面RabbitMQ Server作为服务端,生产者和消费者都是作为客户端,通过tcp连接和服务端进行通信。如果每一次通信都建立tcp连接资源消耗极大,故这里Connection作为一个连接池,里面有许多管道,通过channel进行通信,这样可以节约资源。
RabbitMq中有很多虚拟机,每个虚拟机里面有很多Exchange和Queue,交换机可以绑定到不同的队列上,Binding就是交换价绑定到队列上的过程。
RabbitMQ的六种工作模式
生产消息和消费消息的工作方式
JMS
类比jdbc是java程序和数据库通信的接口,JMS就是java程序和消息队列通信的接口。
RabbitMQ安装和配置。
在云服务器上直接安装docker版本的就可以了。
Downloading and Installing RabbitMQ --- RabbitMQ
XML
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-management
运行如下所示
安装好后通过IP+端口访问管理界面。
管理界面端口是15672,tcp连接的端口是5672。
账号密码都是guest
RabbitMQ控制台使用。
在控制台可以看见有一个Overview概览,Connection连接,channels通道,Exchanges交换机,Queues,和Admin,Admin中可以管理用户和虚拟机等
这里新建了一个超级用户yhy和一个虚拟机itcast授权给yhy。
有了管理员权限就可以用新用户的账号密码登录了。
RabbitMQ快速入门------生产者
需求:
在idea中创建一个新的空工程,添加两个maven模块。
然后再在两个工程里面分别导入rabbitMQ的依赖和编译的版本插件。
XML
<dependencies>
<!--rabbitmq的java客户端-->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
有基本架构图和简单工作模式的图可得以下流程。因为简单模式中没有交换机,所以这里不涉及交换机的创建。
java
//发送消息
public class producer {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("XXX.XX.XXX.XXX"); //设置ip地址。默认为127.0.0.1
factory.setPort(5672); //端口 默认值5672
factory.setVirtualHost("/itcast"); //设置虚拟机 默认值/
factory.setUsername("yhy"); //用户名,默认值guest
factory.setPassword("XXXXXX"); //密码,默认值guest
//3.创建连接Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/*
queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
参数:
1.queue:队列名称
2.durable:是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占。只能有一个消费者监听这队列
*当Connection关闭时,是否删除队列
4.autoDelete: 是否自动删除。当没有Consumer时,自动删除掉
5.arguments:参数。
*/
//如果没有一个名叫hello_yhy的队列,则会自动创建一个
channel.queueDeclare("hello_yhy",true,false,false,null);
//6.发送消息
/*
basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
参数:
1.exchange:交换机名称。简单模式下交换机会使用默认的""。
2.routerKey:路由名称。
3.props:配置信息
4.body:发送消息数据
*/
String body="hello rabbitmq!!!";
channel.basicPublish("","hello_yhy",null,body.getBytes());
//7.释放资源
channel.close();
connection.close();
}
}
在控制台中可以看见现在没有一个队列。
运行完之后可以看见hello_yhy队列出现了。
但是没有新的Connection和channel出现,因为最后关闭了,如果代码最后不关闭就会出现。
然后程序不同就会显示一直running。
RabbitMQ快速入门------消费者
与生产者非常类似。
但是由上图可知,创建channel的参数虽然一样,但是是不同的channel.
在写生产者时已经有一个队列了,所以再创建一次也没有问题
目前队列中有两条消息。
java
public class consumer {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("XXX.XX.XXX.XXX"); //设置ip地址。默认为127.0.0.1
factory.setPort(5672); //端口 默认值5672
factory.setVirtualHost("/itcast"); //设置虚拟机 默认值/
factory.setUsername("yhy"); //用户名,默认值guest
factory.setPassword("XXXXXX"); //密码,默认值guest
//3.创建连接Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/*
queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
参数:
1.queue:队列名称
2.durable:是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占。只能有一个消费者监听这队列
*当Connection关闭时,是否删除队列
4.autoDelete: 是否自动删除。当没有Consumer时,自动删除掉
5.arguments:参数。
*/
//如果没有一个名叫hello_yhy的队列,则会自动创建一个
channel.queueDeclare("hello_yhy",true,false,false,null);
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* 参数:
* 1.队列名称
* 2.autoAck:是否自动确认
* 3.callback:回调对象
* */
//6.接收消息
Consumer consumer=new DefaultConsumer(channel){
/*
* 回调方法,当收到消息后,会自动执行该方法
* 1.consumerTag:标识
* 2.envelope :获取一些信息,交换机,路由key...
* 3.properties: 配置信息
* 4.body: 数据
* */
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("consumerTag:"+consumerTag);
System.out.println("Exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);
System.out.println("body:"+new String(body));
}
};
channel.basicConsume("hello_yhy",true,consumer);
//不需要关闭资源
}
}
运行消费者代码之后
可以看见雀氏取出了两条消息。并且控制台看见已经没有消息了。