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 ...
随机推荐
- 4、NameNode启动过程详解
NameNode 内存 本地磁盘 fsimage edits 第一次启动HDFS 格式化HDFS,目的就是生成fsimage start NameNode,读取fsimage文件 start Data ...
- Spring Security 认证执行流程
本文基于 Spring Security 5.x 推荐阅读: 项目集成Spring Security SpringSecurity 整合 JWT 一.外层-正常登陆调用 项目启动后会自动寻找 User ...
- 过滤器的API
1.API a.生命周期(和servletcontext相似): (1)创建:服务器启动的时候创建(执行init方法). (2)销毁:服务器关闭的时候销毁(执行destory方法). b.filter ...
- pgloader 方便的数据迁移工具
pgloader 是一个支持多种数据源迁移到pg 数据库的工具,高性能,使用灵活同时作者 也提供了docker 版本的镜像,今年3月份使用此工具的时候,发现好久都没更新了,但是 最近作者有了新版本的发 ...
- gulp开发工具之postcss
参考文章:http://www.cnblogs.com/givebest/p/4771154.html package.json { "name": "postcss&q ...
- Coffee Break
题目链接:Coffee Break Gym-101911A 题目大意:有一位员工想要利用喝咖啡来休息,他给了一个数组表示他想要喝咖啡的时间点(假设他喝咖啡用时1分钟),老板规定每次喝咖啡的时间间隔必 ...
- OpenFOAM——平行平板间具有相对运动(库埃特流)
本算例翻译整理自:http://the-foam-house5.webnode.es/products/chapter-1-plane-parallel-plates-case/ 这个算例研究了一个距 ...
- 范仁义html+css课程---4、文本标签
范仁义html+css课程---4.文本标签 一.总结 一句话总结: 文本标签大致掌握一下,做到它站在你对面的时候最好认得,认不得也没关系,直接百度 1.ins标签.u标签和del标签 作用? ins ...
- IDEA2019.2.1中文乱码解决
写在前面 太晚了, 长话短说, idea更新到2019.2.1, 项目任何地方输入中文都是乱码, 修改编码UTF-8依然如此.参考https://blog.csdn.net/chenjk10/arti ...
- 三层架构BLL+DAL+Model & MVC & MVVM
三层架构 - 国内版 Binghttps://cn.bing.com/search?FORM=U227DF&PC=U227&q=%E4%B8%89%E5%B1%82%E6%9E%B6% ...