中间件系列一 RabbitMQ之安装和Hello World Demo
https://blog.csdn.net/hry2015/article/details/79016854
1. 概述
RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现。本文的包含的主要内容如下:
- RabbitMQ的安装和管理界面
- 第一个Hello World程序
- 详细介绍RabbitMQ中消息代理(message brokers)、连接(Connections)、通道(Channels)、队列(queue)、发送消息和消息属性、发送/接收消息及使用注意事项
- 1
- 2
- 3
2. RabbitMQ 概述
RabbitMQ是一个消息代理(message brokers),它负责从发布者(publishers)亦称生产者(producers)那儿接收消息,并根据既定的路由规则把接收到的消息发送给处理消息的消费者(consumers)
如果要了解RabbitMQ,最好学习一下AMQP协议,会对理解RabbitMQ工作原理有很大帮助,详细见AMQP 0-9-1 协议简介
3. 安装RabbitMQ和管理界面
- 安装RabbitMQ服务并启动,参考这篇文章: Ubuntu 16.04 安装 RabbitMQ
- 安装管理界面插件
#启用rabbitmq-management插件:
sudo rabbitmq-plugins enable rabbitmq_management
使用guest/guest帐号登录管理界面 http://127.0.0.1:15672 - 创建新的帐号 hry/hry,并设置类型为Administrator
4. 第一个HelloWold程序
第一个RabbitMQ的HelloWorld实现如下功能,生产者发送一个消息,消息者接收到此消息:
5. 发布者(publishers)亦称生产者(producers)
负责发布消息,本节介绍发布者的代码和相关的方法
业务逻辑如下:
1 配置连接工厂
2 建立TCP连接
3 在TCP连接的基础上创建通道
4 声明一个队列
5 发送消息
5.1. 连接(Connections)和通道(Channels)
生产者和消费者是使用TCP和RabbitMQ建立长连接。但是TCP是非常耗费资源,为了减少TCP连接的数据,RabbitMQ提出通道的概念。在同一个TCP连接上可以建立多个通道,即可以把通道理解成共享一个TCP连接的多个轻量化连接。通道不是线程安全的,不推荐多个线程共用一个通道。在多线程/进程应用中,为每个线程/进程开启一个通道(channel),并且这些通道不能被线程/进程共享。
一个特定通道上的通讯与其他通道上的通讯是完全隔离的,因此每个AMQP方法都需要携带一个通道号,这样客户端就可以指定此方法是为哪个通道准备的。
以下功能的代码如下:
1 配置连接工厂
2 建立TCP连接
3 在TCP连接的基础上创建通道
// 配置连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(host);
factory.setUsername(userName);
factory.setPassword(password);
Connection connection = null;
Channel channel = null;
// 建立TCP连接
connection = factory.newConnection();
// 在TCP连接的基础上创建通道
channel = connection.createChannel();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
5.2. 队列(queue)
用于存储即将要发送的消息(message)。它的大小理论上是无限的,唯一限制大小是RabbitMQ的内存和磁盘大小.队列在声明(declare)后才能被使用。声明队列操作是幂等操作,即如果一个队列尚不存在,声明一个队列会创建它,如果声明的队列已经存在,并且属性完全相同,那么此次声明不会对原有队列产生任何影响,如果声明中的属性与已存在队列的属性有差异,那么一个错误代码为406的通道级异常就会被抛出。
创建队列方法:
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map<String, Object> arguments) throws IOException
- 1
- 2
队列配置参数说明:
第一个参数queue
定义队列的名称,最多255字节的一个utf-8字符串。如果此参数为空字符串,则RabbitMQ会自动生成一个唯一的队列名,在同一个通道的后续的方法中,我们可以使用空字符串来表示之前生成的队列名称,之所以之后的方法可以获取正确的队列名是因为通道可以默默地记住消息代理最后一次生成的队列名称
以”amq.”开始的队列名称被预留做消息代理内部使用,不能被应用使用,否则抛出403 (ACCESS_REFUSED)错误
第二个参数 durable
是否持久化,如果true,则此种队列叫持久化队列(Durable queues)。此队列会被存储在磁盘上,当消息代理(broker)重启的时候,它依旧存在。没有被持久化的队列称作暂存队列(Transient queues)。
持久化的队列并不会使得路由到它的消息也具有持久性。倘若消息代理挂掉了,重新启动,那么在重启的过程中持久化队列会被重新声明,无论怎样,只有经过持久化的消息才能被重新恢复。
第三个参数 execulusive
表示此对应只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参数的优先级高于durable
第四个参数 autoDelete
当没有生成者/消费者使用此队列时,此队列会被自动删除。
(即当最后一个消费者退订后即被删除)
第五个参数 arguments
其它的扩展属性,如一些消息代理用他来完成类似与TTL功能时相关的参数
声明一个队列代码如下:
channel.queueDeclare(QUEUE_NAME+4, false, false, false, null);
- 1
备注:还有一些特殊队列
- 临时队列:等价于建立一个durable=false,execulusive=true,autoDelete=true,名称为随机的队列
- 内部队列:以”amq.”开始的队列名称被预留做消息代理内部使用。如果试图在队列声明时打破这一规则的话,一个通道级的403 (ACCESS_REFUSED)错误会被抛出
5.3. 发送消息和消息属性
发送消息方法
void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
- 1
详细参数说明:
第一个参数exchange:
执行队列使用的交换机(exchange),交换机拿到一个消息之后将它路由给一个或零个队列。关于这块的内容后面会详细说明。如果值为空字符串,则表示使用默认交换机。默认交换机(default exchange)实际上是一个由消息代理预先声明好的没有名字(名字为空字符串)的直连交换机(direct exchange)。它有一个特殊的属性使得它对于简单应用特别有用处:那就是每个新建队列(queue)都会自动绑定到默认交换机上,绑定的路由键(routing key)名称与队列名称相同。
第二个参数routingKey:
指定路由键,如果使用默认交换机,则此值和队列名称相同
第三个参数props:
除了Routing key外,消息还可以配置如下属性,常用属性如下:
○ Content type:内容类型
○ Content encoding:内容编码
○ headers; 消息的头信息,类似http协议中的header属性
○ Delivery mode (persistent or not) 投递模式(持久化 或 非持久化): 如果此值是persistent ,则此消息存储在磁盘上。如果服务器重启,系统会保证收到的持久化消息未丢失,将消息以持久化方式发布时,会对性能造成一定的影响
○ Message priority:消息优先级
○ String correlationId;
○ ReplyTo; 反馈队列
○ Expiration period: 消息有效期
○ String messageId;
○ Message publishing timestamp:消息发送的时间戳
○ String type;
○ String userId;
○ Publisher application id:发布应用的ID
○ String clusterId;
第四个参数body:
消息的有效负载pPayload(消息实际携带的数据),它被RabbitMQ当作不透明的字节数组来对待。消息代理不会检查或者修改有效载荷。消息可以只包含属性而不携带有效载荷。
发送消息代码如下
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
- 1
5.4. 交换机(Exchange)
虽然代码没有出现交换机的配置,但是实际我们使用了交换机。
交换机拿到一个消息之后将它路由给一个或零个队列。它使用哪种路由算法是由交换机类型和被称作绑定(bindings)的规则所决定的。RabbitMQ的提供了四种交换机
- Direct exchange(直连交换机)
- Fanout exchange(扇型交换机)
- Topic exchange(主题交换机)
- Headers exchange(头交换机)
我的例子里只使用了默认交换机:默认交换机(default exchange)实际上是一个由消息代理预先声明好的名字为空字符串的直连交换机(direct exchange)。它有一个特殊的属性使得它对于简单应用特别有用处:那就是每个新建队列(queue)都会自动绑定到默认交换机上,绑定的路由键(routing key)名称与队列名称相同。
其他的交换机,我们后续文章再介绍。
6. 消费者(consumers)
接收并处理消息,业务如下
- 配置连接工厂
- 建立TCP连接
- 在TCP连接的基础上创建通道
- 声明一个队列
- 接收消息并处理
以上代码和发送者部分类似,这是略,只列出不同的部分
6.1. 接收消息并消费
Consumer
消息的接收是异常的,通过com.rabbitmq.client.Consumer定义回调方法。回调接口用于处理订阅的消息。DefaultConsumer是此接口的默认,官方也推荐如果要实现自己的Consumer,则继承此类
// 默认消费者实现
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [HelloworldRecv] Received '" + message + "'");
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
接收消息方法
String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;
- 1
详细参数说明:
第一个参数queue
要接收消息的队列名称
第二个参数autoAck
消费者在处理消息的时候偶尔会失败或者有时会直接崩溃掉,而且网络原因也有可能引起各种问题。为了解决这个问题,RabbitMQ给我们两种建议:
○ 自动确认模式(automatic acknowledgement model):当RabbitMQ将消息发送给消费者后,立即从内存中删除消息。
○ 显式确认模式(explicit acknowledgement model):只有消费者发送确认回执(acknowledgement),RabbitMQ才删除消息。如果一个消费者在尚未发送确认回执的情况下挂掉了,那RabbitMQ会将消息重新投递给另一个消费者。如果当时没有可用的消费者了,RabbitMQ会死等下一个注册到此队列的消费者,然后再次尝试投递。
第三个参数callback
指定处理消息的回调类
接收消息代码如下
// 接收消息
channel.basicConsume(QUEUE_NAME, true, consumer);
- 1
- 2
7. 完整代码和测试
生产者的完整代码
HelloworldSend
消费者完整代码
HelloworldRecv
测试代码完整代码
测试如下场景:一个消费者启动并接收消息,一个生产者启动并发送消息
public class BasicTest {
// 测试线程池
private ExecutorService executorService = Executors.newFixedThreadPool(10);
// rabbitmq的IP地址
private final String rabbitmq_host = "10.240.80.147";
// rabbitmq的用户名称
private final String rabbitmq_user = "hry";
// rabbitmq的用户密码
private final String rabbitmq_pwd = "hry";
@Test
public void helloworld() throws InterruptedException {
// 接收端
executorService.submit(() -> {
HelloworldRecv.execute(rabbitmq_host, rabbitmq_user, rabbitmq_pwd);
});
Thread.sleep(5* 100);
// 发送端
executorService.submit(() -> {
HelloworldSend.execute(rabbitmq_host, rabbitmq_user, rabbitmq_pwd);
});
// sleep 10s
Thread.sleep(10 * 1000);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
测试
执行BasicTest 的helloworld()方法,结果如下
[HelloworldRecv] Waiting for messages.
[HelloworldSend] Sent 'Hello World!1515574041536'
[HelloworldRecv] Received 'Hello World!1515574041536'
- 1
- 2
- 3
8. 代码
中间件系列一 RabbitMQ之安装和Hello World Demo的更多相关文章
- RabbitMQ系列之RabbitMQ单机安装
安装epel源 rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm #ht ...
- 中间件系列三 RabbitMQ之交换机的四种类型和属性
概述本文介绍RabbitMQ中交换机类型和属性,主要内容如下: 交换机的作用交换机的类型:Direct exchange(直连交换机).Fanout exchange(扇型交换机).Topic exc ...
- 消息中间件系列二:RabbitMQ入门(基本概念、RabbitMQ的安装和运行)
一.基本概念 1. AMQP AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议.支持不同语言和不同的产品 2. 生产者 ...
- SpringBoot系列之RabbitMQ使用实用教程
SpringBoot系列之RabbitMQ使用实用教程 @ 目录 1. 消息队列概述 1.1 MQ的概述 1.2 MQ目的地形式 2. 消息队列实现方式 2.1 常见MQ框架 2.2 MQ实现方式 3 ...
- Linux下 RabbitMQ的安装与配置-3
一 Erlang安装 1.RabbitMQ是基于Erlang的,所以首先必须配置Erlang环境. 从Erlang的官网http://www.erlang.org/download.html 下载最 ...
- rabbitmq的安装和使用
一.RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件).RabbitMQ服务器是用Erlang语言编写的,而群集和故障转移是构建在开放电信平台框架上的.所有 ...
- RabbitMQ使用教程(一)RabbitMQ环境安装配置及Hello World示例
你是否听说过或者使用过队列? 你是否听说过或者使用过消息队列? 你是否听说过或者使用过RabbitMQ? 提到这几个词,用过的人,也许觉得很简单,没用过的人,也许觉得很复杂,至少在我没使用消息队列之前 ...
- RabbitMQ 离线安装(带视频)
疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列 [博客园总入口 ] 架构师成长+面试必备之 高并发基础书籍 [Netty Zookeeper Redis 高并发实战 ] 疯狂创客圈 高并 ...
- RabbitMQ的安装与使用(Centos7,linux版本)
1.主流的消息中间件简单介绍哦. 1).ActiveMQ是Apache出品,最流行的,能力强劲的开源消息总线,并且它一个完全支持jms(java message service)规范的消息中间件.其丰 ...
随机推荐
- 抗DDOS应急预案实践-生产环境总结-建议必看
一.首先摸清楚环境与资源 为DDoS应急预案提供支撑 所在的网络环境中,有多少条互联网出口?每一条带宽多少? 每一条互联网出口的运营商是否支持DDoS攻击清洗,我们是否购买,或可以紧急试用?当发生DD ...
- 我成为 Microsofti Azure MVP 啦!(ps:不是美国职业篮球)
一,引言 今天是个高兴的日子,早上10点左右收到了来自微软的MVP的礼包的快递,对我来说,这是一件很值得纪念的日子.所以今天就水一篇心得感想吧!!! 我是年前2月9号开始申请MVP的,经历了差不多1个 ...
- 并发编程-线程池&J.U.C
8. 共享模型之工具 8.1 线程池 池化技术相比大家已经屡见不鲜了,线程池.数据库连接池.Http 连接池等等都是对这个思想的应用.池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率 ...
- java7与java9中的try-finally关闭资源
1.java7中的try 在java7之前,对于一些需要使用finally关闭资源的操作,会显得很臃肿. try { // } catch(Exception e) { // } finally { ...
- Day11_51_Collections工具类之sort方法和list集合的遍历方式
Collections工具类之sort方法 * 使用Collections工具类对List集合进行排序 Collections.sort(List集合) * Collections.sort()方法只 ...
- scrapy爬虫框架调用百度地图api数据存入数据库
scrapy安装配置不在本文 提及, 1.在开始爬取之前,必须创建一个新的Scrapy项目.进入自定义的项目目录中,运行下列命令 scrapy startproject mySpider 其中, my ...
- 1072 Gas Station
A gas station has to be built at such a location that the minimum distance between the station and a ...
- 深入探索Android热修复技术原理读书笔记 —— 热修复技术介绍
1.1 什么是热修复 对于广大的移动开发者而言,发版更新是最为寻常不过的事了.然而,如果你 发现刚发出去的包有紧急的BUG需要修复,那你就必须需要经过下面这样的流程: 这就是传统的更新流程,步骤十分繁 ...
- 【Nginx(四)】Nginx配置集群 负载均衡策略
1.Nginx常见的负载均衡策略 ip_hash (固定分发) 简介:根据请求按访问ip的hash结果分配,这样每个用户就可以固定访问一个后端服务器 场景:服务器业务分区.业务缓存.Session需要 ...
- hdu4279 找规律+小想法
题意: 蛋疼的题意,最后是泽神给我讲的题意,题意是对于一个数来说,如果他不能整除另一个数同时他和另一个数非互质,那么另一个数就是这个数的特别数,如10 的特别数有 4 6 8三个,同时题目还 ...