1.消息队列的作用,以及准备工作
1.1. 为什么要用 MQ 1.流量消峰 举个例子,如果订单系统最多能处理一万次订单,这个处理能力应付正常时段的下单时绰绰有余,正 常时段我们下单一秒后就能返回结果。但是在高峰期,如果有两万次下单操作系统是处理不了的,只能限 制订单超过一万后不允许用户下单。使用消息队列做缓冲,我们可以取消这个限制,把一秒内下的订单分 散成一段时间来处理,这时有些用户可能在下单十几秒后才能收到下单成功的操作,但是比不能下单的体 验要好。 2.应用解耦 以电商应用为例,应用中有订单系统、库存系统、物流系统、支付系统。用户创建订单后,如果耦合 调用库存系统、物流系统、支付系统,任何一个子系统出了故障,都会造成下单操作异常。当转变成基于 消息队列的方式后,系统间调用的问题会减少很多,比如物流系统因为发生故障,需要几分钟来修复。在 这几分钟的时间里,物流系统要处理的内存被缓存在消息队列中,用户的下单操作可以正常完成。当物流 系统恢复后,继续处理订单信息即可,中单用户感受不到物流系统的故障,提升系统的可用性。 3.异步处理 有些服务间调用是异步的,例如 A 调用 B,B 需要花费很长时间执行,但是 A 需要知道 B 什么时候可 以执行完,以前一般有两种方式,A 过一段时间去调用 B 的查询 api 查询。或者 A 提供一个 callback api, B 执行完之后调用 api 通知 A 服务。这两种方式都不是很优雅,使用消息总线,可以很方便解决这个问题, A 调用 B 服务后,只需要监听 B 处理完成的消息,当 B 处理完成后,会发送一条消息给 MQ,MQ 会将此 消息转发给 A 服务。这样 A 服务既不用循环调用 B 的查询 api,也不用提供 callback api。同样 B 服务也不 用做这些操作。A 服务还能及时的得到异步处理成功的消息。
1.2.rabbitMQ在linux下的常用命令
1.添加开机启动 RabbitMQ 服务 chkconfig rabbitmq-server on 2.启动服务 /sbin/service rabbitmq-server start 3.查看服务状态 /sbin/service rabbitmq-server status 4.停止服务(选择执行) /sbin/service rabbitmq-server stop 5.开启 web 管理插件 rabbitmq-plugins enable rabbitmq_management 用默认账号密码(guest)访问地址 http://192.168.121.111:15672/出现权限问题 6.添加一个新的用户 创建账号 rabbitmqctl add_user admin 123
admin 123代表账号和密码(自己设置) 7.设置用户角色 rabbitmqctl set_user_tags admin administrator 8.设置用户权限 rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
用户 user_admin 具有/vhost1 这个 virtual host 中所有资源的配置、写、读权限
9.当前用户和角色
rabbitmqctl list_users
2.简单的代码整合
2.1用Java代码进行操作
P代表一个生产者,C代表一个消费者 ,生产者负责将消费者传递给消费者
![](https://i-blog.csdnimg.cn/blog_migrate/a05f494f77a447b49dee4d3355e36e3d.png)
下面引入非SpringBoot整合的依赖包(后边会有整合SpringBoot的包)
<!--指定 jdk 编译版本-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--rabbitmq 依赖客户端-->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.8.0</version>
</dependency>
<!--操作文件流的一个依赖-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
生产者代码
/**
* 生产者:发消息
*/
public class Producer {
//队列
public static final String QUEUE_NAME="hello";
//
public static void main(String[] args) throws IOException, TimeoutException {
//创建一个连接工厂
ConnectionFactory factory=new ConnectionFactory();
//设置连接工场ip,连接rabbitMQ的队列
factory.setHost("192.168.121.111");
//用户名
factory.setUsername("admin");
//密码
factory.setPassword("123");
//创建连接
Connection connection = factory.newConnection();
//获取信道
Channel channel = connection.createChannel();
/**
* 生成一个队列
* 1.队列名称
* 2.队列里面的消息是否持久化 默认情况 消息存储在内存中
* 3.该队列是否只供一个消费者进行消息共享,true:可以多个,false:一个
* 4.是否自动删除,最后一个消费者开连接后该队列是否自动删除,true:自动,false:则相反
*/
Map<String,Object> arguments=new HashMap<>();
arguments.put("x-max-priority",10);//官方允许是在0-255,允许优先级的范围0-10
channel.queueDeclare(QUEUE_NAME,false,false,false,arguments);
//发消息
String message="hello world";
channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
/**
* 发送一个消息
* 1.发送到哪个交换机
* 2.路由的key值是哪个,本次是队列的名称
* 3.其他参数信息
* 4.发送的消息的消息体
*/
System.out.println("消息发送完毕");
}
}
消费者代码
/**
* 消费者 接受消息的
*/
public class Consumer {
//队列名称
public static final String QUEUE_NAME="hello";
//接收消息
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置连接工场ip,连接rabbitMQ的队列
factory.setHost("192.168.121.111");
//用户名
factory.setUsername("admin");
//密码
factory.setPassword("123");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//声明
DeliverCallback deliverCallback=(String var1, Delivery var2)->{
System.out.println(new String(var2.getBody()));
};
//取消消息时的回调
CancelCallback cancelCallback=consumerTag->{
System.out.println("消息消费被中断");
};
/**
* 消费者消费消息
* 1.消费哪个队列
* 2.消费成功后是否自动应答 true 代表的是自动应答,false代表的是手动应答
* 3.消费者未成功消费的回调
* 4.消费者取消消费的回调
*/
channel.basicConsume(QUEUE_NAME,true,deliverCallback,cancelCallback);
}
}
这样就实现了一个简单的工作队列