1.RabbitMQ工作模型与基本原理
1. MQ 了解
1.1. 消息队列简介
1.1.1.MQ 的诞生历程
1.1.2.什么是 MQ(Message Queue)?
1.1.3.为什么要使用 MQ?
1.1.1.1.实现异步通信
1.1.1.1.实现系统解耦
// 伪代码
public void returnGoods(){
stockService.updateInventory ();
payService.refund();
noticeService.notice();
}

1.1.1.2.实现流量削峰
1.1.4.使用消息队列带来的一些问题
1.2. RabbitMQ 简介
1.2.1.基本特性
1.2.2.AMQP 协议
1.2.2.1.总体介绍

1.2.2.2.工作模型

1.2.2.3.路由方式

channel.basicPublish(“MY_DIRECT_EXCHANGE”,”spring”,”msg1”);
只有第一个队列能收到消息。

channel.basicPublish("MY_TOPIC_EXCHANGE","junior.fjd.klj","msg 2");
只有第一个队列能收到消息。
channel.basicPublish("MY_TOPIC_EXCHANGE","junior.jvm", "msg 3");
第 一个队列和第三个队列能收到消息。
channel.basicPublish("MY_FANOUT_EXCHANGE", "", "msg 4");
三个队列都会收到 msg 4。
1.3. 基本使用
1.3.1.安装
1.3.2.Java API 编程
1.3.2.1.引入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
1.3.2.2.生产者
package com.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class MyProducer {
private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
// 连接 IP
factory.setHost("127.0.0.1");
// 连接端口
factory.setPort(5672);
// 虚拟机
factory.setVirtualHost("/");
// 用户
factory.setUsername("guest");
factory.setPassword("guest");
// 建立连接
Connection conn = factory.newConnection();
// 创建消息通道
Channel channel = conn.createChannel();
// 发送消息
String msg = "Hello world, Rabbit MQ";
// String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish(EXCHANGE_NAME, "gupao.best", null, msg.getBytes());
channel.close();
conn.close();
}
}
1.3.2.3.消费者
package com.simple;
import com.rabbitmq.client.*;
import java.io.IOException;
public class MyConsumer {
private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
private final static String QUEUE_NAME = "SIMPLE_QUEUE";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
// 连接 IP
factory.setHost("127.0.0.1");
// 默认监听端口
factory.setPort(5672);
// 虚拟机
factory.setVirtualHost("/");
// 设置访问的用户
factory.setUsername("guest");
factory.setPassword("guest");
// 建立连接
Connection conn = factory.newConnection();
// 创建消息通道
Channel channel = conn.createChannel();
// 声明交换机
// String exchange, String type, boolean durable, boolean autoDelete, Map<String, Object> arguments
channel.exchangeDeclare(EXCHANGE_NAME,"direct",false, false, null);
// 声明队列
// String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" Waiting for message....");
// 绑定队列和交换机
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"best");
// 创建消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String msg = new String(body, "UTF-8");
System.out.println("Received message : '" + msg + "'");
System.out.println("consumerTag : " + consumerTag );
System.out.println("deliveryTag : " + envelope.getDeliveryTag() );
}
};
// 开始获取消息
// String queue, boolean autoAck, Consumer callback
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
1.3.2.4.参数详解
1.3.3.UI 管理界面的使用
1.3.3.1.启用管理插件
1.3.3.2.管理界面访问端口
1.3.3.3.虚拟机
2. 深入理解RabbitMQ
2.1. TTL(Time To Live)
2.1.1.消息的过期时间
@Bean("ttlQueue")
public Queue queue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-message-ttl", 11000); // 队列中的消息未被消费 11 秒后过期
return new Queue("TTL_QUEUE", true, false, false, map);
}
MessageProperties messageProperties = new MessageProperties();
messageProperties.setExpiration("4000"); // 消息的过期属性,单位 ms
Message message = new Message("这条消息 4 秒后过期".getBytes(), messageProperties);
rabbitTemplate.send("GP_TTL_EXCHANGE", "ttl", message);
2.2. 死信队列
@Bean("oriUseExchange")
public DirectExchange exchange() {
return new DirectExchange("RI_USE_EXCHANGE", true, false, new HashMap<>());
}
@Bean("oriUseQueue")
public Queue queue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-message-ttl", 10000); // 10 秒钟后成为死信
map.put("x-dead-letter-exchange", "DEAD_LETTER_EXCHANGE"); // 队列中的消息变成死信后,进入死信交换机
return new Queue("ORI_USE_QUEUE", true, false, false, map);
}
@Bean
public Binding binding(@Qualifier("oriUseQueue") Queue queue,@Qualifier("oriUseExchange") DirectExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("ori.use");
}
@Bean("deatLetterExchange")
public TopicExchange deadLetterExchange() {
return new TopicExchange("DEAD_LETTER_EXCHANGE", true, false, new HashMap<>());
}
@Bean("deatLetterQueue")
public Queue deadLetterQueue() {
return new Queue("DEAD_LETTER_QUEUE", true, false, false, new HashMap<>());
}
@Bean
public Binding bindingDead(@Qualifier("deatLetterQueue") Queue queue,@Qualifier("deatLetterExchange") TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("#"); // 无条件路由
}

2.3. 延迟队列
2.3.1.TTL+DLX 的实现
2.3.2.基于延迟队列插件的实现(Linux)
whereis rabbitmq
cd /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.12/plugins
wget
https://bintray.com/rabbitmq/community-plugins/download_file?file_path=rabbitmq_delayed_message_exchange-0.0.1.ez
mv download_file?file_path=rabbitmq_delayed_message_exchange-0.0.1.ez
rabbitmq_delayed_message_exchange-0.0.1.ez
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
rabbitmq-plugins disable rabbitmq_delayed_message_exchange
@Bean("delayExchange")
public TopicExchange exchange() {
Map<String, Object> argss = new HashMap<String, Object>();
argss.put("x-delayed-type", "direct");
return new TopicExchange("GP_DELAY_EXCHANGE", true, false, argss);
}
MessageProperties messageProperties = new MessageProperties();
// 延迟的间隔时间,目标时刻减去当前时刻
messageProperties.setHeader("x-delay", delayTime.getTime() - now.getTime());
Message message = new Message(msg.getBytes(), messageProperties);
// 不能在本地测试,必须发送消息到安装了插件的 Linux 服务端
rabbitTemplate.send("GP_DELAY_EXCHANGE", "#", message);
2.4. 服务端流控(Flow Control)
2.4.1.内存控制
[{rabbit, [{vm_memory_high_watermark, 0.4}]}].
rabbitmqctl set_vm_memory_high_watermark 0.3
2.4.2.磁盘控制
disk_free_limit.relative = 3.0
disk_free_limit.absolute = 2GB
2.5. 消费端限流
channel.basicQos(2); // 如果超过 2 条消息没有发送 ACK,当前消费者不再接受队列消息
channel.basicConsume(QUEUE_NAME, false, consumer);
container.setPrefetchCount(2);
spring.rabbitmq.listener.simple.prefetch=2
3. Spring AMQP
3.1. Spring AMQP 介绍
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
3.2. Spring AMQP 核心组件
3.2.1.ConnectionFactory
3.2.2.RabbitAdmin
// 声明一个交换机
rabbitAdmin.declareExchange(new DirectExchange("ADMIN_EXCHANGE", false, false));
// 声明一个队列
rabbitAdmin.declareQueue(new Queue("ADMIN_QUEUE", false, false, false));
// 声明一个绑定
rabbitAdmin.declareBinding( new Binding("ADMIN_QUEUE", Binding.DestinationType.QUEUE,
"ADMIN_EXCHANGE", "admin", null));
declareExchanges(channel, exchanges.toArray(new Exchange[exchanges.size()]));
declareQueues(channel, queues.toArray(new Queue[queues.size()]));
declareBindings(channel, bindings.toArray(new Binding[bindings.size()]));
3.2.3.Message
3.2.4.RabbitTemplate 消息模板
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback(){
public void returnedMessage(Message message,
int replyCode,
String replyText,
String exchange,
String routingKey){
}
});
return rabbitTemplate;
}
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
System.out.println("消息确认成功");
} else {
// nack
System.out.println("消息确认失败");
}
}
});
3.2.5.MessageListener 消息侦听
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(getSecondQueue(), getThirdQueue()); //监听的队列
container.setConcurrentConsumers(1); // 最小消费者数
container.setMaxConcurrentConsumers(5); // 最大的消费者数量
container.setDefaultRequeueRejected(false); //是否重回队列
container.setAcknowledgeMode(AcknowledgeMode.AUTO); //签收模式
container.setExposeListenerChannel(true);
container.setConsumerTagStrategy(new ConsumerTagStrategy() { //消费端的标签策略
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID().toString();
}
});
return container;
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory)
{
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
factory.setAcknowledgeMode(AcknowledgeMode.NONE);
factory.setAutoStartup(true);
return factory;
}
@Component
@PropertySource("classpath:mq.properties")
@RabbitListener(queues = "${com.firstqueue}", containerFactory="rabbitListenerContainerFactory")
public class FirstConsumer {
@RabbitHandler
public void process(@Payload Merchant merchant){
System.out.println("First Queue received msg : " + merchant.getName());
}
}
public class ContainerSender {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new CachingConnectionFactory(new URI("amqp://guest:guest@localhost:5672"));
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
SimpleMessageListenerContainer container = factory.createListenerContainer();
// 不用工厂模式也可以创建
// SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setConcurrentConsumers(1);
container.setQueueNames("BASIC_SECOND_QUEUE");
container.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
System.out.println("收到消息:"+message);
}
});
container.start();
AmqpTemplate template = new RabbitTemplate(connectionFactory);
template.convertAndSend("BASIC_SECOND_QUEUE", "msg 1");
}
}
3.2.6.转换器 MessageConvertor
@Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
return rabbitTemplate;
}
3.3. Spring 集成 RabbitMQ 配置解读
<rabbit:connection-factory id="connectionFactory" virtual-host="/" username="guest" password="guest"
host="127.0.0.1" port="5672" />
<rabbit:admin id="connectAdmin" connection-factory="connectionFactory" />
<rabbit:queue name="MY_FIRST_QUEUE" durable="true" auto-delete="false" exclusive="false"
declared-by="connectAdmin" />
<rabbit:direct-exchange name="MY_DIRECT_EXCHANGE" durable="true" auto-delete="false"
44
declared-by="connectAdmin">
<rabbit:bindings>
<rabbit:binding queue="MY_FIRST_QUEUE" key="FirstKey">
</rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
<bean id="jsonMessageConverter"
class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
<rabbit:template id="amqpTemplate" exchange="${gupao.exchange}" connection-factory="connectionFactory"
message-converter="jsonMessageConverter" />
<bean id="messageReceiver" class="com.gupaoedu.consumer.FirstConsumer"></bean>
<rabbit:listener-container connection-factory="connectionFactory">
<rabbit:listener queues="MY_FIRST_QUEUE" ref="messageReceiver" />
</rabbit:listener-container>

3.4. Spring Boot 集成 RabbitMQ
3.4.1.配置文件
@Bean("vipDirectExchange")
public DirectExchange getDirectExchange(){
return new DirectExchange(directExchange);
}
@Bean("vipTopicExchange")
public TopicExchange getTopicExchange(){
return new TopicExchange(topicExchange);
}
@Bean("vipFanoutExchange")
public FanoutExchange getFanoutExchange(){
return new FanoutExchange(fanoutExchange);
}
@Bean("vipFirstQueue")
public Queue getFirstQueue(){
return new Queue(firstQueue);
}
@Bean("vipSecondQueue")
public Queue getSecondQueue(){
return new Queue(secondQueue);
}
@Bean("vipThirdQueue")
public Queue getThirdQueue(){
return new Queue(thirdQueue);
}
@Bean("vipFourthQueue")
public Queue getFourthQueue(){
return new Queue(fourthQueue);
}
@Bean
public Binding bindFirst(@Qualifier("vipFirstQueue") Queue queue, @Qualifier("vipDirectExchange")
DirectExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("gupao.best");
}
@Bean
public Binding bindSecond(@Qualifier("vipSecondQueue") Queue queue, @Qualifier("vipTopicExchange")
TopicExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("*.gupao.*");
}
@Bean
public Binding bindThird(@Qualifier("vipThirdQueue") Queue queue, @Qualifier("vipFanoutExchange")
FanoutExchange exchange){
return BindingBuilder.bind(queue).to(exchange);
}
@Bean
public Binding bindFourth(@Qualifier("vipFourthQueue") Queue queue, @Qualifier("vipFanoutExchange")
FanoutExchange exchange){
return BindingBuilder.bind(queue).to(exchange);
}
3.4.2.消费者
@Component
@PropertySource("classpath:mq.properties")
@RabbitListener(queues = "${com.firstqueue}")
public class FirstConsumer {
@RabbitHandler
public void process(@Payload Merchant merchant){
System.out.println("First Queue received msg : " + merchant.getName());
}
}
3.4.3.生产者
@Autowired
AmqpTemplate upTemplate;
public void send() throws JsonProcessingException {
Merchant merchant = new Merchant(1001,"a direct msg : 中原镖局","汉中省解放路 266 号");
upTemplate.convertAndSend(directExchange,directRoutingKey, merchant);
upTemplate.convertAndSend(topicExchange,topicRoutingKey1,"a topic msg : shanghai.teacher");
upTemplate.convertAndSend(topicExchange,topicRoutingKey2,"a topic msg : changsha.student");
// 发送 JSON 字符串
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(merchant);
System.out.println(json);
upTemplate.convertAndSend(fanoutExchange,"", json);
}
3.5. Spring Boot 参数解析
1.RabbitMQ工作模型与基本原理的更多相关文章
- 认识RabbitMQ交换机模型
前言 RabbitMQ是消息队列中间件(Message Queue Middleware)中一种,工作虽然有用到,但是却没有形成很好的整体包括,主要是一些基础概念的认识,这里通过阅读<Rabbi ...
- [转载] PHP工作模型与运行机制
转载自http://www.nowamagic.net/librarys/veda/detail/350 PHP的工作模型非常特殊.从某种程度上说,PHP和ASP.ASP.NET.JSP/Servle ...
- HTTPD三种工作模型
HTTPD三种工作模型 MPM是apache的多道处理模块,用于定义apache对客户端请求的处理方式.在linux中apache常用的三种MPM模型分别是prefork.worker和event. ...
- RabbitMQ系列(二)深入了解RabbitMQ工作原理及简单使用
深入了解RabbitMQ工作原理及简单使用 RabbitMQ系列文章 RabbitMQ在Ubuntu上的环境搭建 深入了解RabbitMQ工作原理及简单使用 RabbitMQ交换器Exchange介绍 ...
- 深入解读RabbitMQ工作原理及简单使用
RabbitMQ系列目录 RabbitMQ在Ubuntu上的环境搭建 深入解读RabbitMQ工作原理及简单使用 Rabbit的几种工作模式介绍与实践 Rabbit事务与消息确认 Rabbit集群搭建 ...
- Git Flow 工作模型与使用
一. Git Flow 工作模型的原理 无规矩不成方圆,但是规矩太多了,则感觉到束缚.我们一个人工作的时候喜欢无拘无束,想怎么干就怎么干,没有人评判,没有人检验.时间久了就会盲目自大,以为增删改查熟悉 ...
- linux下的工作模型以及Nginx工作原理
Web服务器主要任务就是处理来自客户端的请求,一般情况下Web服务器处理并发连接请求的工作模型有以下几种方式: 1.单线程web服务器(Single-threaded web servers) 此 ...
- 【 Linux 】I/O工作模型及Web服务器原理
一.进程.线程 进程是具有一定独立功能的,在计算机中已经运行的程序的实体.在早期系统中(如linux 2.4以前),进程是基本运作单位,在支持线程的系统中(如windows,linux2.6) ...
- 【python】-- RabbitMQ RPC模型
RabbitMQ RPC模型 RPC(remote procedure call)模型说通俗一点就是客户端发一个请求给远程服务端,让它去执行,然后服务端端再把执行的结果再返回给客户端. 1.服务端 i ...
随机推荐
- 洛谷 P3518 [POI2011] SEJ-Strongbox 题解
思路: 首先先将每个输入的数据与n的最大公约数求出(因为如果a[i]是密码,那么所有a[i]与n最大公约数的倍数也是密码:于是如果a[i]不是密码,那么所有a[i]与n最大公约数的倍数也都不是密码)再 ...
- windows系统的快速失败机制---fastfail
windows系统的快速失败机制---fastfail,是一种用于“快速失败”请求的机制 — 一种潜在破坏进程请求立即终止进程的方法. 无法使用常规异常处理设施处理可能已破坏程序状态和堆栈至无法恢复的 ...
- Why We Changed YugaByte DB Licensing to 100% Open Source
转自:https://blog.yugabyte.com/why-we-changed-yugabyte-db-licensing-to-100-open-source/ 主要说明了YugaByte ...
- Python 05 Geany的基本使用1
问题01:代码中包含中文编译时提示错误 原文:https://blog.csdn.net/weixin_43345286/article/details/82951698 解决:文档 - 设置文件编码 ...
- Codevs 2009 大dota英雄 2013年省队选拔赛辽宁(状压DP)
2009 大dota英雄 2013年省队选拔赛辽宁 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 话说退役后的生活好无聊啊,以 ...
- 63、Spark Streaming:架构原理深度剖析
一.架构原理深度剖析 StreamingContext初始化时,会创建一些内部的关键组件,DStreamGraph,ReceiverTracker,JobGenerator,JobScheduler, ...
- 【洛谷P3369】普通平衡树——Splay学习笔记(一)
二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...
- JavaScript的入门篇
快速认识JavaScript 熟悉JavaScript基本语法 窗口交互方法 通过DOM进行网页元素的操作 学会如何编写JS代码 运用JavaScript去操作HTML元素和CSS样式 <!DO ...
- Exception in thread "main" java.lang.IllegalStateException: Failed to read 问题解决
开发中偶尔遇到这样的问题:Exception in thread "main" java.lang.IllegalStateException: Failed to read .. ...
- Fluent也弹窗
具体步骤见<fluent加载第三方(C++,Fortran等)动态链接库> 我们对导入的动态链接库进行改动 打开VS2013 源代码: #include #ifdef __cplusplu ...