mq系列rabbitmq-01简介,安装,api操作
一。rabbitmq介绍
RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue高级消息队列 )的开源实现 主要包含以下组件
1.Server(broker): 接受客户端连接,实现AMQP消息队列和路由功能的进程。
2.Virtual Host:其实是一个虚拟概念,类似于权限控制组,一个Virtual Host里面可以有若干个Exchange和Queue,但是权限控制的最小粒度是Virtual Host
3.Exchange:接受生产者发送的消息,并根据Binding规则将消息路由给服务器中的队列。ExchangeType决定了Exchange路由消息的行为,例如,在RabbitMQ中,ExchangeType有direct、Fanout和Topic三种,不同类型的Exchange路由的行为是不一样的。
4.Message Queue:消息队列,用于存储还未被消费者消费的消息。
5.Message: 由Header和Body组成,Header是由生产者添加的各种属性的集合,包括Message是否被持久化、由哪个Message Queue接受、优先级是多少等。而Body是真正需要传输的APP数据。
6.Binding:Binding联系了Exchange与Message Queue。Exchange在与多个Message Queue发生Binding后会生成一张路由表,路由表中存储着Message Queue所需消息的限制条件即Binding Key。当Exchange收到Message时会解析其Header得到Routing Key,Exchange根据Routing Key与Exchange Type将Message路由到Message Queue。Binding Key由Consumer在Binding Exchange与Message Queue时指定,而Routing Key由Producer发送Message时指定,两者的匹配方式由Exchange Type决定。
7.Connection:连接,对于RabbitMQ而言,其实就是一个位于客户端和Broker之间的TCP连接。
8.Channel:信道,仅仅创建了客户端到Broker之间的连接后,客户端还是不能发送消息的。需要为每一个Connection创建Channel,AMQP协议规定只有通过Channel才能执行AMQP的命令。一个Connection可以包含多个Channel。之所以需要Channel,是因为TCP连接的建立和释放都是十分昂贵的,如果一个客户端每一个线程都需要与Broker交互,如果每一个线程都建立一个TCP连接,暂且不考虑TCP连接是否浪费,就算操作系统也无法承受每秒建立如此多的TCP连接。RabbitMQ建议客户端线程之间不要共用Channel,至少要保证共用Channel的线程发送消息必须是串行的,但是建议尽量共用Connection。
9.Command:AMQP的命令,客户端通过Command完成与AMQP服务器的交互来实现自身的逻辑。例如在RabbitMQ中,客户端可以通过publish命令发送消息,txSelect开启一个事务,txCommit提交一个事务。
二。rabbitmq安装
1》安装rabbitmq
安装过程 参考 (http://www.rabbitmq.com/install-rpm.html)
rabbitmq-server 目前安装包被包含在 Fedora rpm仓库中 Fedora是epel库
yum -y install epel-release.noarch
查看是否存在rabbitmq 然后安装
yum search rabbitmq-server
yum -y install rabbitmq-server
查看安装包
tail -1000 /var/log/yum.log
安装了很多erlang语言包和一个rabbitmq-server包
Nov 07 05:05:50 Installed: lksctp-tools-1.0.17-2.el7.x86_64
Nov 07 05:05:50 Installed: erlang-crypto-R16B-03.18.el7.x86_64
Nov 07 05:05:51 Installed: erlang-kernel-R16B-03.18.el7.x86_64
Nov 07 05:05:52 Installed: erlang-stdlib-R16B-03.18.el7.x86_64
Nov 07 05:05:53 Installed: erlang-erts-R16B-03.18.el7.x86_64
Nov 07 05:05:53 Installed: erlang-syntax_tools-R16B-03.18.el7.x86_64
Nov 07 05:05:53 Installed: erlang-compiler-R16B-03.18.el7.x86_64
Nov 07 05:05:54 Installed: erlang-hipe-R16B-03.18.el7.x86_64
Nov 07 05:05:55 Installed: erlang-mnesia-R16B-03.18.el7.x86_64
Nov 07 05:05:55 Installed: erlang-runtime_tools-R16B-03.18.el7.x86_64
Nov 07 05:05:56 Installed: erlang-snmp-R16B-03.18.el7.x86_64
Nov 07 05:05:56 Installed: erlang-otp_mibs-R16B-03.18.el7.x86_64
Nov 07 05:05:56 Installed: erlang-sd_notify-0.1-1.el7.x86_64
Nov 07 05:05:56 Installed: erlang-xmerl-R16B-03.18.el7.x86_64
Nov 07 05:05:56 Installed: erlang-asn1-R16B-03.18.el7.x86_64
Nov 07 05:05:57 Installed: erlang-public_key-R16B-03.18.el7.x86_64
Nov 07 05:05:57 Installed: erlang-ssl-R16B-03.18.el7.x86_64
Nov 07 05:05:57 Installed: erlang-inets-R16B-03.18.el7.x86_64
Nov 07 05:05:57 Installed: erlang-tools-R16B-03.18.el7.x86_64
Nov 07 05:05:57 Installed: erlang-sasl-R16B-03.18.el7.x86_64
Nov 07 05:05:58 Installed: erlang-os_mon-R16B-03.18.el7.x86_64
Nov 07 05:06:00 Installed: rabbitmq-server-3.3.5-34.el7.noarch
查看rabbitmq-server被安装的所有文件的位置
/etc/logrotate.d/rabbitmq-server
/etc/rabbitmq
/etc/rabbitmq/rabbitmq.config
/usr/lib/ocf/resource.d/rabbitmq/rabbitmq-server
/usr/lib/rabbitmq/bin
/usr/lib/rabbitmq/bin/rabbitmq-defaults
/usr/lib/rabbitmq/bin/rabbitmq-env
/usr/lib/rabbitmq/bin/rabbitmq-plugins
/usr/lib/rabbitmq/bin/rabbitmq-server
/usr/lib/rabbitmq/bin/rabbitmqctl
查看rabbitmq-server所有的参考文档
[root@node3 log]# rpm -qd rabbitmq-server-3.3.5-34.el7.noarch
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-APACHE2-ExplorerCanvas
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-APL2-Stomp-Websocket
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-Apache-Basho
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-BSD-base64js
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-BSD-glMatrix
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-EJS10
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-Flot
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-Mochi
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-Sammy060
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-eldap
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-jQuery164
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MPL-RabbitMQ
/usr/share/doc/rabbitmq-server-3.3.5/rabbitmq.config.example
/usr/share/man/man1/rabbitmq-plugins.1.gz
/usr/share/man/man1/rabbitmq-server.1.gz
/usr/share/man/man1/rabbitmqctl.1.gz
/usr/share/man/man5/rabbitmq-env.conf.5.gz
其中比较重要的两个参考文件(这两个只是参考)
运行配置文件:rabbitmq.config.example
环境配置文件:/usr/share/man/man5/rabbitmq-env.conf.5.gz
默认该两文件需要配置在 /etc/rabbitmq目录下 默认只有一个
[root@node3 log]# cd /etc/rabbitmq && ll
total 20
-rw-r--r-- 1 root root 18555 Aug 11 2014 rabbitmq.config
单机默认配置足够 具体配置参考官网 (http://www.rabbitmq.com/configure.html)
rabbitmq默认安装后 会添加账号rabbitmq 默认以该账号运行
[root@node3 rabbitmq]# more /etc/passwd | grep rabbitmq
rabbitmq:x:992:990:RabbitMQ messaging server:/var/lib/rabbitmq:/sbin/nologin
2》启动rabbitmq
启动后 查看默认的端口 5672
[root@node3 rabbitmq]# netstat -aon | grep 5672
tcp 0 0 0.0.0.0:25672 0.0.0.0:* LISTEN off (0.00/0/0)
tcp6 0 0 :::5672 :::* LISTEN off (0.00/0/0)
查看运行状态(默认在cd /etc/init.d下)
[root@node3 rabbitmq]# service rabbitmq-server status
Redirecting to /bin/systemctl status rabbitmq-server.service
● rabbitmq-server.service - RabbitMQ broker
Loaded: loaded (/usr/lib/systemd/system/rabbitmq-server.service; disabled; vendor preset: disabled)
Active: active (running) since Tue 2017-11-07 05:52:27 PST; 6min ago
Main PID: 8507 (beam)
CGroup: /system.slice/rabbitmq-server.service
├─8507 /usr/lib64/erlang/erts-5.10.4/bin/beam -W w -K true -A30 -P 1048576 -- -root /usr/lib64/erlang -progname...
├─8522 /usr/lib64/erlang/erts-5.10.4/bin/epmd -daemon
├─8579 inet_gethost 4
└─8580 inet_gethost 4
Nov 07 05:52:24 node3 systemd[1]: Starting RabbitMQ broker...
Nov 07 05:52:24 node3 systemd[1]: rabbitmq-server.service: Got notification message from PID 8522, but reception on...ID 8507
Nov 07 05:52:26 node3 rabbitmq-server[8507]: RabbitMQ 3.3.5. Copyright (C) 2007-2014 GoPivotal, Inc.
Nov 07 05:52:26 node3 rabbitmq-server[8507]: ## ## Licensed under the MPL. See http://www.rabbitmq.com/
Nov 07 05:52:26 node3 rabbitmq-server[8507]: ## ##
Nov 07 05:52:26 node3 rabbitmq-server[8507]: ########## Logs: /var/log/rabbitmq/rabbit@node3.log
Nov 07 05:52:26 node3 rabbitmq-server[8507]: ###### ## /var/log/rabbitmq/rabbit@node3-sasl.log
Nov 07 05:52:26 node3 rabbitmq-server[8507]: ##########
Nov 07 05:52:27 node3 systemd[1]: Started RabbitMQ broker.
Nov 07 05:52:27 node3 rabbitmq-server[8507]: Starting broker... completed with 0 plugins.
Hint: Some lines were ellipsized, use -l to show in full.
关闭和查看rabiitmq的状态可以使用命令
[root@node3 system]# rabbitmqctl stop
Stopping and halting node rabbit@node3 ...
...done.
默认的日志目录是(/var/log/rabbitmq)
[root@node3 rabbitmq]# ll
total 4
-rw-r--r-- 1 rabbitmq rabbitmq 3190 Nov 7 06:12 rabbit@node3.log
-rw-r--r-- 1 rabbitmq rabbitmq 0 Nov 7 05:52 rabbit@node3-sasl.log
rabbitmq默认提供了一个web管理工具(rabbitmq_management)参考官方http://www.rabbitmq.com/management.html 默认已经安装 是一个插件
查看所有插件
[root@node3 rabbitmq]# rabbitmq-plugins list
[ ] amqp_client 3.3.5
[ ] cowboy 0.5.0-rmq3.3.5-git4b93c2d
[ ] eldap 3.3.5-gite309de4
[ ] mochiweb 2.7.0-rmq3.3.5-git680dba8
[ ] rabbitmq_amqp1_0 3.3.5
[ ] rabbitmq_auth_backend_ldap 3.3.5
[ ] rabbitmq_auth_mechanism_ssl 3.3.5
[ ] rabbitmq_consistent_hash_exchange 3.3.5
[ ] rabbitmq_federation 3.3.5
[ ] rabbitmq_federation_management 3.3.5
[ ] rabbitmq_management 3.3.5
[ ] rabbitmq_management_agent 3.3.5
[ ] rabbitmq_management_visualiser 3.3.5
[ ] rabbitmq_mqtt 3.3.5
[ ] rabbitmq_shovel 3.3.5
[ ] rabbitmq_shovel_management 3.3.5
[ ] rabbitmq_stomp 3.3.5
[ ] rabbitmq_test 3.3.5
[ ] rabbitmq_tracing 3.3.5
[ ] rabbitmq_web_dispatch 3.3.5
[ ] rabbitmq_web_stomp 3.3.5
[ ] rabbitmq_web_stomp_examples 3.3.5
[ ] sockjs 0.3.4-rmq3.3.5-git3132eb9
[ ] webmachine 1.10.3-rmq3.3.5-gite9359c7
启用该插件即可
rabbitmq-plugins enable rabbitmq_management
重启rabbitmq-server
[root@node3 rabbitmq]# service rabbitmq-server restart
Redirecting to /bin/systemctl restart rabbitmq-server.service
浏览器访问(开启了端口 15672 当前机器ip是58.150) (http://192.168.58.150:15672/)
输入用户名 guest和guest
该管理界面有几个视图 分别是
三。rabbitmq api调用
参考官方文档 http://www.rabbitmq.com/getstarted.html
rabbitmq 官方操作api提供了n多种语言 前面几种都会 java是本职 所以使用java
rabbitmq支持6种消息接受和转发机制
1》简单模式(http://www.rabbitmq.com/tutorials/tutorial-one-java.html)
单个发送者(生产者) 将消息发送到队列(每个队列都有一个唯一名字) 单个接受者(消费者)获取消息
eclipse添加maven的jar项目添加依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.2.0</version>
</dependency>
生产者代码
package cn.et.p1;
import java.io.IOException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* 消息发送者 - 生产者
* @author jiaozi
*
*/
public class Pub {
/**
* 队列名称
*/
private final static String QUEUE_NAME = "hello";
public static void main(String[] args) throws Exception {
//连接远程rabbit-server服务器
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.58.150");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//定义创建一个队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
//发送消息
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8")); //注意发送和接受段相同字符集否则出现乱码
System.out.println(" [x] Sent '" + message + "'");
channel.close();
connection.close();
}
}
消费者代码
package cn.et.p1;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.QueueingConsumer;
/**
* 消息接受者 - 消费者
*
* @author jiaozi
*
*/
public class Rec {
/**
* 获取消息队列名称
*/
private final static String QUEUE_NAME = "hello";
/**
* 异步接收
* @throws Exception
*/
public static void asyncRec() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.58.150");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//消费者也需要定义队列 有可能消费者先于生产者启动
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
//定义回调抓取消息
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(" [x] Received '" + message + "'");
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
}
/**
* 同步接收 消费者定时去抓取
* 该种方式已过期
* @throws Exception
*/
public static void asyncFalseRec() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.58.150");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(QUEUE_NAME, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" [x] Received '" + message + "'");
}
}
public static void main(String[] args) throws Exception {
asyncRec();
}
}
发布消息到队列可以通过web管理界面查看消息 使用命令行
[root@node3 rabbitmq]# rabbitmqctl list_queues
Listing queues ...
hello 2 队列名称 队列的消息个数
...done.
web界面可以模拟添加队列 删除 模拟发送消息 也可以查看队列消息 具体自己研究
2》工作队列模式(http://www.rabbitmq.com/tutorials/tutorial-two-java.html)
工作队列一般用于任务分配 发布者发布任务到队列 多个消息接受者 接受消息 谁接受到某个消息 其他接受者就只能消费其他消息 队列中的
一个消息只能被一个接受者消费(类似12306抢票一样 比如某个车次 就相当于队列 该车次 出来一些座位票 一张票只能被一个人抢到 最终 所有的座位票
都被不同的人抢到 注意: 一个人可以抢多张票)
模拟 两个任务接受者 一个发布者发布6个消息 2个任务接受者抢这6个消息 一般来说都是rr轮询制 基本是平均分配给每个接受者的
发布者代码:
package cn.et.p2;
import java.io.IOException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* 消息发送者 - 生产者
* @author jiaozi
*
*/
public class Pub {
/**
* 队列名称
*/
private final static String QUEUE_NAME = "mywork";
public static void main(String[] args) throws Exception {
//连接远程rabbit-server服务器
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.58.150");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//定义创建一个队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = null;
//同时发送5条消息
for(int i=0;i<=5;i++){
message="发送第"+i+"消息";
//发送消息
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
}
System.out.println(" [x] Sent 5 message");
channel.close();
connection.close();
}
}
接受任务者
package cn.et.p2;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.QueueingConsumer;
/**
* 消息接受者 - 消费者
*
* @author jiaozi
*
*/
public class Rec {
/**
* 获取消息队列名称
*/
private final static String QUEUE_NAME = "mywork";
/**
* 异步接收
* @throws Exception
*/
public static void asyncRec() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.58.150");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//消费者也需要定义队列 有可能消费者先于生产者启动
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
//定义回调抓取消息
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(" [x] Received '" + message + "'");
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
}
public static void main(String[] args) throws Exception {
asyncRec();
}
}