分布式消息通信之RabbitMQ_01
官网
RabbitMQ
RabbitMQ Tutorials & 1 Hello World! | 2 Work queues | 3 Publish/Subscribe | 4 Routing | 5 Topics | 6 RPC & RabbitMQ 教程
Installation Guide
1. RabbitMQ安装
1.1 Window版安装
a.需要首先安装安装Erlang
以及对应版本的rabbitmq-server
,可在此处Installing on Windows下载;
本次安装版本为rabbitmq-server-3.7.14.exe
及OTP 21.3 Windows 64-bit
;下载完成后一直next即可;可将erl
和rabbitMQ
加入环境变量;
b.安装完成后启用rabbitmq_management
C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.14\sbin>enable rabbitmq_management
'enable' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.14\sbin>rabbitmq-plugins.bat enable rabbitmq_management
Enabling plugins on node rabbit@DESKTOP-2NHH5NJ:
rabbitmq_management
The following plugins have been configured:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
Applying plugin configuration to rabbit@DESKTOP-2NHH5NJ...
The following plugins have been enabled:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
set 3 plugins.
Offline change; changes will take effect at broker restart.
C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.14\sbin>
c.之后启动RabbitMQ,net start RabbitMQ
C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.14\sbin>rabbitmq-server.bat net start RabbitMQ
"WARNING: Using RABBITMQ_ADVANCED_CONFIG_FILE: C:\Users\EDDY~1.SHE\AppData\Roaming\RabbitMQ\advanced.config"
## ##
## ## RabbitMQ 3.7.14. Copyright (C) 2007-2019 Pivotal Software, Inc.
########## Licensed under the MPL. See https://www.rabbitmq.com/
###### ##
########## Logs: C:/Users/EDDY~1.SHE/AppData/Roaming/RabbitMQ/log/RABBIT~1.LOG
C:/Users/EDDY~1.SHE/AppData/Roaming/RabbitMQ/log/rabbit@DESKTOP-2NHH5NJ_upgrade.log
Starting broker...
completed with 3 plugins.
启动成功后可打开http://localhost:15672/#/测试地址查看,用户名密码默认均为guest
1.2 Linux版安装
2. 典型应用场景
异步,解耦,削峰
跨系统的异步通信;
系统内的同步变为异步;
基于pub/sub模型的广播订阅;
分布式事物的最终一致性解决方案;
3. 基本介绍
3.1 AMQP协议
AMQP协议,跨语言,跨系统,跨平台的协议,Advanced Message Queuing Protocol 一种高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的消息中间件可跨产品,跨语言的消息通信。Erlang中的实现有 RabbitMQ等。
3.2 RabbitMQ的特性
RabbmitMQ使用Erlang语言编写,使用Mnesia数据库存储消息。
1)可靠性(Reliability) RabbitMQ使用一些机制来保证消息传输的可靠性,如持久化,传输确认,发布确认。
2)灵活的路由(Flexible Routing) 在消息进入队列之前,通过Exchange来路由消息。对应典型的路由功能,RabbmitMQ已经内置了一些Exchange来支持。针对更复杂的路由功能,可以将多个Exchange绑定在一起,也可以通过插件机制实现自己的Exchange。
3) 消息集群(Clustering) 多个RabbitMQ服务可以组成一个集群,形成一个逻辑Broker。
4) 高可用队列(Highly Available Queues) 队列可以在集群机器上进行镜像,使得在部分节点出现问题的情况下队列让然可用。
5) 多种协议(Multi Protocol) RabbitMQ支持多种消息队列协议,如 AMQP, STOMP, MQTT等。
6) 多语言客户端(Clients) RabbitMQ几乎支持所有常用语言,如 Python, Java, Ruby, PHP, C#, JavaScript, Go, Elixir, Objective-C等。
7) 管理界面(Management UI) RabbitMQ提供了一个易用的用户界面,使得用户可以监控和管理消息,集群中的节点。
8) 插件机制(Plugin) RabbitMQ提供了许多插件,以实现多方面的扩展,当然也可以编写自己的插件。
3.3 工作模型
工作流程:
1. 首先生产者将消息发布至交换机Exchange
,绑定路由关键字Routing Key
(生产者不会讲消息直接放入队列,就算是不声明交换机,也是先发布至默认的交换机)
2. 消费者创建通道channel
,队列queue
,并指定队列queue
绑定的交换机Exchange
,使用绑定关键字Binding Key
来绑定(一个交换机可绑定多个队列queue,一个交换机绑定一个队列时,也可以使用多个绑定关键字)
3. 当交换机收到消息,根据生产者发送消息时的路由关键字routing key
和消费者定义的绑定关键字Binding Key
做匹配,匹配合适的话就将消息存入匹配到的队列中去
4. 消费者从队列中取走消息
关键字:
Broker
RabbitMQ的实体服务器,提供一种传输及服务,维护一条从生产者到消费者的传输路线,保证消息按指定的方式传输。
Exchange
消息交换机,指定消息按照哪种规则路由到哪个队列Queue。
Queue
消息队列。消息的载体,每个消息都会被投送到一个或多个队列中。
Binding
绑定。将Exchange和Queue按照某种路由规则绑定。
Routing Key
路由关键字。和 Binding Key对应,按照关键字匹配通过Exchange找到对应的Queue。
VHost
虚拟主机。相当于一个小的Broker,小的rabbitMQ服务器,一个Broker可以有一到多个虚拟主机,用于不同用户的权限分离。一个虚拟主机拥有一组 Exchange, Queue和 Binding。
Producer
消息生产者。将消息投递到Exchange上,一般是独立的应用程序。
Consumer
消息消费者。消息的接受者,一般是独立的应用程序。
Connection
Producer,Broker和Consumer之间的TCP长连接。
Channel
消息通道,也成信道。在客户端的每个连接里可以建立多个Channel,每个Channel代表一个会话认为。在RabbitMQ Java Client中,channel上定义了大量的编程接口。
3.4 三种主要的交换机
Direct Exchange 直连交换机
使用直连类型的交换机时,发送消息时的路由关键字Routing Key
和接收消息时的绑定关键字Binding Key
必须完全匹配时,生产者发送的消息才能被对应的消费者所接收到;
如上图,当生产者发送消息指定路由关键字是error的时候,交换机发现第一个和第二个队列都是以error绑定的,所以队列1,2都会受到消息;当生产者发送消息指定路由关键字是info或者warning时,只有第二个队列能匹配,消费者C2才能受到消息。
Topic Exchange 主题交换机
路由关键字Routing Key
和绑定关键字Binding Key
不需要完全匹配,类似于正则表达式符合一定规则匹配到即可接收消息。通配符有两个:
* 代表匹配一个单词;
# 代表匹配零到多个单词;
多个单词之间用.分隔。
如上图,当使用路由关键字fast.orange.tiger发送消息时,表达式匹配队列Q1,消费者C1会受到消息;
当使用路由关键字fast.orange.rabbit发送消息时,表达式匹配队列Q1,Q2,消费者C1,C2都会受到消息;
当使用路由关键字lazy.blue.rabbit发送消息时,队列Q2绑定交换机时使用的两个关键字都可以匹配到,但只会受到1条消息,不会多次发送;
Fanout Exchange 广播交换机
使用广播类型的交换机时,不需要指定Routing Key
和Binding Key
,生产者将消息发送至该交换机后,所有与之绑定的队列都能收到消息。
如上图,当生产者发送一条消息时,不需要指定路由关键字,消息都会通过Fanout Exchange发送至队列1和队列2,消费者C1,C2都会受到消息。
4. Java API编程
// 声明交换机
com.rabbitmq.client.Channel#exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable)
// 声明队列
com.rabbitmq.client.Channel#queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
// 发布消息
com.rabbitmq.client.Channel#basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
参数说明
声明交换机
exchange
: 交换机名称
type
: 交换机类型,DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers"); 4种,也可以直接使用字符串表示
durable
: 是否持久化,代表交换机在服务器重启后是否存在
声明队列
String queue
: 队列名称
boolean durable
: 是否持久化,代表队列在服务器重启后是否存在
boolean exclusive
: 是否排他队列,如果要声明一个只有自己可见,其余用户都不可见的队列,可以使用排他队列;该队列有两个特性:1)
只有首次声明它的连接(connection)可见(对connection中的多个channel也可见),2)
会在连接断开时自动删除
boolean autoDelete
:是否自动删除,如果为true,在没有消费者连接到这个队列时,会自动删除
Map<String, Object> arguments
:队列的其他属性,例如x-message-ttl、x-expires、x-max-length、x-max-length-bytes、x-dead-letter-exchange、x-dead-letter-routing-key、x-max-priority;
发布消息
BasicProperties props,
:14个属性
public static class BasicProperties extends com.rabbitmq.client.impl.AMQBasicProperties {
private String contentType;
private String contentEncoding;
private Map<String,Object> headers; // 消息的其他自定义参数
private Integer deliveryMode; // 2持久化,其他 瞬态
private Integer priority; // 消息的优先级
private String correlationId;
private String replyTo; // 回调队列
private String expiration; // TTL 消息过期时间,单位毫秒
private String messageId;
private Date timestamp;
private String type;
private String userId;
private String appId;
private String clusterId;
...
5. 进阶知识
5.1 自动删除没人消费的消息
TTL (Time To Live) 可以通过设置队列的过期时间或者每条消息的过期时间来实现:
// 队列设置过期时间
Map<String, Object> queueArgs = new HashMap<>();
queueArgs.put("x-message-ttl", 60000); //queue msg ttl 6s
channel.queueDeclare("MY_TTL_QUEUE", true, false, false, queueArgs);
...
// 消息设置过期时间
AMQP.BasicProperties msgArgs = new AMQP.BasicProperties().builder()
.expiration("5000") // TTL 5s
.deliveryMode(2) // 消息持久化
.contentEncoding("UTF-8")
.build();
channel.basicPublish("", "MY_TTL_QUEUE", msgArgs, "Hello World".getBytes());
5.2 无法路由的消息,去了哪里
创建队列的时候可以指定队列中的消息无法路由或者过期后的去处,转发到指定的交换机,也就是死信交换机,和死信交换机绑定的队列为死信队列。
三种情况消息会进入死信交换机DLX(Dead Letter Exchange):
消息过期;
消费端设置autoAck为false,不使用自动应答而是使用手工应答,并且手工应答的处理是reject或者Nack,且requeue属性为false,被拒绝的消息不会重新入队的时候
-- 消费端 autoAck为false
com.rabbitmq.client.Channel#basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback);
...
-- requeue 重新入队为false
com.rabbitmq.client.Channel#basicReject(long deliveryTag, boolean requeue);
com.rabbitmq.client.Channel#basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException;
队列达到最大长度,先入队的消息会被放至DLX
可以为普通的队列设置死信交换机,当队列中的消息变为死信后会进入指定的死信交换机,然后定义我们的死信队列来接收死信交换机里的内容:
String myDeadLetterExchange = "MY_DLX_EXCHANGE";
String myDeadLetterQueue = "MY_DLX_QUEUE";
Map<String, Object> commonQueueArgs = new HashMap<>();
commonQueueArgs.put("x-message-ttl", 60000);
commonQueueArgs.put("x-max-length", 4); // 队列最大长度
commonQueueArgs.put("x-expires", "9000"); // TTL过期时间
commonQueueArgs.put("x-dead-letter-exchange", myDeadLetterExchange);
// 声明普通队列
channel.queueDeclare("MY_TTL_QUEUE", true, false, false, commonQueueArgs);
// 声明死信交换机
channel.exchangeDeclare(myDeadLetterExchange, "topic");
// 声明死信队列
channel.queueDeclare(myDeadLetterQueue, false, false, false, null);
// 绑定
channel.queueBind(myDeadLetterQueue, myDeadLetterExchange, "#");
5.3 可以让消息优先得到消费吗
当队列中消息堆积时,可以设置队列和消息的优先级,级别高的消息会优先消费。
设置队列支持的最大优先级属性x-max-priority
及消息优先级属性com.rabbitmq.client.AMQP.BasicProperties#priority,当队列中消息堆积时,队列会根据属性优先级大小进行优先消费,如果消息不会堆积,设置优先级并没什么用。
// 生产者 发送消息时设置消息优先级
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("name", "test");
headers.put("level", "top");
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2) // 2代表持久化
.contentEncoding("UTF-8") // 编码
.expiration("10000") // TTL,过期时间
.headers(headers) // 自定义属性
.priority(5) // 消息的优先级,默认为5,配合队列的 x-max-priority 属性使用
.messageId(String.valueOf(UUID.randomUUID()))
.build();
// 消费者创建队列时设置队列支持的最大优先级
Map<String, Object> map = new HashMap<>();
map.put("x-max-priority", 10); //指定队列的最大优先级
// 声明队列(默认交换机AMQP default,Direct)
// String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
5.4 延迟队列
当在使用智能产品时,比如要设置1个小时以后发送一条短信,可以使用延迟队列;消息会立刻进入队列,但1个小时后才会被消费掉;
Rabbit MQ本身并不支持延迟队列,可以使用之前提到的消息过期时间TTL加死信队列DLX来实现。
或者使用插件 rabbitmq-delayed-message-exchange
5.5 RPC
5.6 服务端流控
Flow Control, Rabbit MQ中数据是存储在磁盘或者内存中的,可以设置内存使用率,来达到限流效果。
RabbitMQ 会在启动时检测机器的物理内存数值。默认当 MQ 占用 40% 以上内存时,MQ 会主动抛出一个内存警告并阻塞所有连接(Connections)。可以通过修改 rabbitmq.config 文件来调整内存阈值,默认值是 0.4,如下所示: [{rabbit, [{vm_memory_high_watermark, 0.4}]}].,默认情况,如果剩余磁盘空间在 1GB 以下,RabbitMQ 主动阻塞所有的生产者。这个阈值也是可调的。
注意队列长度只在消息堆积的情况下有意义,而且会删除先入队的消息,不能实现服务端限流。
5.6 消费端限流
当多个消费者C1,C2,C3绑定同一个队列,队列中的消息由可以快速处理和处理很慢的类型构成,比如现在队列中有100条消息,默认会均匀分给C1,C2,C3三个消费者33-34条,假设C1,C2接收到的都是可以很快处理掉的消息,快速的把数据处理完了,而此时C3在处理业务比较复杂的数据类型,处理的很慢,可能处理起来会话很长时间;但此时C1,C2其实已经空闲下来了,造成了资源的不合理利用。
消费端限流可以达到每个消费者只可以同时处理1或N条消息的目的,当前消息没有处理完,RabbitMQ不会在给当前消费者推送消息,这和 java JUC包下的 java.util.concurrent.Semaphore
很类似,具体代码实现如下:
// 消费端 autoAck=false 非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息。
channel.basicQos(1);
channel.basicConsume(QUEUE_NAME, false, consumer);
6. UI管理界面
UI页面可以用来监控消息,管理交换机队列等。不论是是由代码创建的交换机队列,还是UI界面或者http api方式创建,如果名称和参数都一样,都是可以创建的。
当RabbitMQ需要升级时,原有RabbitMQ内的交换机,队列等重新建立会很麻烦,UI界面提供了export功能,可以将老的导出然后导入新的RabbitMQ内。
7. Spring配置方式集成RabbitMQ
8. Spring Boot集成RabbitMQ
分布式消息通信之RabbitMQ_01的更多相关文章
- 分布式消息通信(ActiveMQ)
分布式消息通信(ActiveMQ) 应用场景 异步通信 应用解耦 流量削峰 # ActiveMQ安装 下载 http://activemq.apache.org/ 压缩包上传到Linux系统 apac ...
- 分布式消息通信ActiveMQ
消息中间件 消息中间件是指利用高效可靠的消息传递机制进行平台无关的数据交流,并且基于数据通信来进行分布式系统的集成.通过提供消息传递和消息排队模型,可以在分布式架构下扩展进程之间的通信. 消息中间件能 ...
- 分布式消息通信Kafka-原理分析
本文目标 TopicPartition 消息分发策略 消息消费原理 消息的存储策略 Partition 副本机制 1 关于 Topic 和 Partition 1.1 Topic 在 kafka 中, ...
- 分布式消息通信之RabbitMQ Tutorials
目录 官网 1 Hello World! 1.1 生产者demo producer 1.2 消费者demo consumer 1.3 查看queue队列中的信息 页面查看,可看到有4条消息 命令查看 ...
- 分布式消息通信之RabbitMQ_Note
目录 1. RabbitMQ 安装 2. RabbitMQ 应用场景,特性 3. 官网入门指引 4. RabbitMQ 工作模型 5. RabbitMQ 主要的几种交换机类型 6. Java API的 ...
- 分布式消息通信之RabbitMQ_02
目录 1. 可靠性投递分析 1.1 消息投递 1.2 消息路由 1.3 消息存储 1.4 消息消费 1.5 其他 2. 高可用架构部署方案 2.1 集群 2.2 镜像 3. 经验总结 3.1 配置文件 ...
- Netty构建分布式消息队列实现原理浅析
在本人的上一篇博客文章:Netty构建分布式消息队列(AvatarMQ)设计指南之架构篇 中,重点向大家介绍了AvatarMQ主要构成模块以及目前存在的优缺点.最后以一个生产者.消费者传递消息的例子, ...
- C#分布式消息队列 EQueue 2.0 发布啦
前言 最近花了我几个月的业余时间,对EQueue做了一个重大的改造,消息持久化采用本地写文件的方式.到现在为止,总算完成了,所以第一时间写文章分享给大家这段时间我所积累的一些成果. EQueue开源地 ...
- ZeroMQ:云时代极速消息通信库
ZeroMQ:云时代极速消息通信库(大规模|可扩展|低成本|高效率解决之道,大规模分布式|多线程应用程序|消息传递架构构建利器) [美]Pieter Hintjens(皮特.亨特金斯)著 卢涛 李 ...
随机推荐
- 自己编写jQuery插件之Tab切换
自己编写jQuery插件之 Tabs切换 jquery ui 带有Tabs切换插件,但其css样式太难维护,引用的东西太多,因此就自己写了个. 起初我Html代码架子是这样的: <div cla ...
- go html 转字符串存mysql表中
func HTMLMarshal(str string) (returnStr string) { bf := bytes.NewBuffer([]byte{}) jsonEncoder := jso ...
- 关系型数据库与NoSQL的对比
SQL(结构化的查询语言)数据库是过去四十年间存储数据的主要方式.20世纪90年代末随着Web应用和MySQL.PostgreSQL和SQLite等开源数据库的兴起,用户爆炸式的增长. NoSQL数据 ...
- RabbitMq、ActiveMq、Kafka和Redis做Mq对比
转载自:https://blog.csdn.net/qiqizhiyun/article/details/79848834 一.RabbitMq RabbitMQ是一个Advanced Message ...
- 使用std::function改善模板的低效性
泛型编程中,模板会根据传入类型的不同,生成多种实例,相对低效. 模板编程: #include <iostream> using namespace std; //未使用函数包装器 temp ...
- leetcode解题报告(10):Merge Two Sorted Lists
描述 Merge two sorted linked lists and return it as a new list. > The new list should be made by sp ...
- luogu 2331
给出 $n * 1$ 的矩阵,选出 $k$ 个互不重叠的子矩阵,使得其最大$sum[i]$ 为列的前缀和设 $f[i][j]$ 表示前 $i$ 个数选出 $j$ 个互不重叠的子矩阵的最大价值若第 $i ...
- maven项目无法查看类库的源码
一个Maven项目有两种类库,分别是JRE System Libaray和Maven Dependencies. JRE System Libaray 一般有两种方法指定. 1.由pom.xml中的m ...
- 十一、FHS基础原理
文件系统: http://note.youdao.com/noteshare?id=298f02714da5b9483429a40dda667f35&sub=6120396419BA477 ...
- 修改history记录数
在linux系统下.history命令会保存多少条命令呢?曾在一本书上说,如果注销系统,那么会将所有的历史命令都定入到~/.bash_history, 但只保留1000条命令(这个是由默认的shell ...