[心得体会]RabbitMQ
RabbitMQ是什么?





- 有什么用? 有什么应用场景?
- 为什么使用RabbitMQ?
AMQP是什么?
AMQP是什么?
AMQP,即Advanced Message Queuing Protocol,
一个提供统一消息服务的应用层标准高级消息队列协议,
是应用层协议的一个开放标准,为面向消息的中间件设计。
基于此协议的客户端与消息中间件可传递消息,
并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
AMQP,即Advanced Message Queuing Protocol,
一个提供统一消息服务的应用层标准高级消息队列协议,
是应用层协议的一个开放标准,为面向消息的中间件设计。
基于此协议的客户端与消息中间件可传递消息,
并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
- AMQP的应用场景
存储转发(多个消息发送者,单个消息接收者)。
分布式事务(多个消息发送者,多个消息接收者)。
发布订阅(多个消息发送者,多个消息接收者)。
基于内容的路由(多个消息发送者,多个消息接收者)。
文件传输队列(多个消息发送者,多个消息接收者)。
点对点连接(单个消息发送者,单个消息接收者)。
- RabbitMQ安装
Linux安装
rpm -Uvh http://www.rabbitmq.com/releases/erlang/erlang-18.1-1.el7.centos.x86_64.rpm
rpm -Uvh http://www.rabbitmq.com/releases/erlang/erlang-18.1-1.el7.centos.x86_64.rpm
rpm -Uvh http://www.rabbitmq.com/releases/rabbitmq-server/v3.5.6/rabbitmq-server-3.5.6-1.noarch.rpm
rpm -Uvh http://www.rabbitmq.com/releases/rabbitmq-server/v3.5.6/rabbitmq-server-3.5.6-1.noarch.rpm
rpm -qa|grep rabbitmq
rpm -qa|grep rabbitmq
$ sudo chkconfig rabbitmq-server on # 添加开机启动RabbitMQ服务
$ sudo /sbin/service rabbitmq-server start # 启动服务
$ sudo /sbin/service rabbitmq-server status # 查看服务状态
$ sudo /sbin/service rabbitmq-server stop # 停止服务
# 查看当前所有用户
$ sudo rabbitmqctl list_users
# 查看默认guest用户的权限
$ sudo rabbitmqctl list_user_permissions guest
# 由于RabbitMQ默认的账号用户名和密码都是guest。为了安全起见, 先删掉默认用户
$ sudo rabbitmqctl delete_user guest
# 添加新用户
$ sudo rabbitmqctl add_user username password
# 设置用户tag
$ sudo rabbitmqctl set_user_tags username administrator
# 赋予用户默认vhost的全部操作权限
$ sudo rabbitmqctl set_permissions -p / username ".*" ".*" ".*"
# 查看用户的权限
$ sudo rabbitmqctl list_user_permissions username
$ sudo chkconfig rabbitmq-server on # 添加开机启动RabbitMQ服务
$ sudo /sbin/service rabbitmq-server start # 启动服务
$ sudo /sbin/service rabbitmq-server status # 查看服务状态
$ sudo /sbin/service rabbitmq-server stop # 停止服务
# 查看当前所有用户
$ sudo rabbitmqctl list_users
# 查看默认guest用户的权限
$ sudo rabbitmqctl list_user_permissions guest
# 由于RabbitMQ默认的账号用户名和密码都是guest。为了安全起见, 先删掉默认用户
$ sudo rabbitmqctl delete_user guest
# 添加新用户
$ sudo rabbitmqctl add_user username password
# 设置用户tag
$ sudo rabbitmqctl set_user_tags username administrator
# 赋予用户默认vhost的全部操作权限
$ sudo rabbitmqctl set_permissions -p / username ".*" ".*" ".*"
# 查看用户的权限
$ sudo rabbitmqctl list_user_permissions username
开启web管理接口
如果只从命令行操作RabbitMQ,多少有点不方便。幸好RabbitMQ自带了web管理界面,只需要启动插件便可以使用。
$ sudo rabbitmq-plugins enable rabbitmq_management
$ sudo rabbitmq-plugins enable rabbitmq_management
然后通过浏览器访问
输入用户名和密码访问web管理界面了。
配置RabbitMQ
关于RabbitMQ的配置,可以下载RabbitMQ的配置文件模板到/etc/rabbitmq/rabbitmq.config, 然后按照需求更改即可。
关于每个配置项的具体作用,可以参考官方文档。
更新配置后,别忘了重启服务哦!
开启用户远程访问
默认情况下,RabbitMQ的默认的guest用户只允许本机访问, 如果想让guest用户能够远程访问的话,只需要将配置文件中的loopback_users列表置为空即可,如下:
{loopback_users, []}
{loopback_users, []}
另外关于新添加的用户,直接就可以从远程访问的,如果想让新添加的用户只能本地访问,可以将用户名添加到上面的列表, 如只允许admin用户本机访问。
{loopback_users, ["admin"]}
{loopback_users, ["admin"]}
更新配置后,别忘了重启服务哦!
- window安装方法
1. 安装erlang
2. 安装RabbitMQ



注意事项

rabbitMQ消息确认
channel.basicQos(1); // accept only one unack-ed message at a time (see below)
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
} finally {
System.out.println(" [x] Done");
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
};
boolean autoAck = false; // 手动Ack功能开始
channel.basicConsume(TASK_QUEUE_NAME, autoAck, deliverCallback, consumerTag -> { });
rabbitmqctl.bat list_queues name messages_ready messages_unacknowledged
linux
sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged
消息持久化
boolean durable = true;
channel.queueDeclare("task_queue", durable, false, false, null);
公平调度
int prefetchCount = 1;
channel.basicQos(prefetchCount);
prefetchCount = 1, 调用basicQos方法这个消费者就会只拿出一个消息进行操作, 其他的消息它都拒绝掉, 拒绝的消息将被滞留带消息队列中, 但是这个消息将会丢给新的消费者
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties; public class NewTask { private static final String TASK_QUEUE_NAME = "task_queue"; public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null); String message = String.join(" ", argv); channel.basicPublish("", TASK_QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
}
} }
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback; public class Worker { private static final String TASK_QUEUE_NAME = "task_queue"; public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
final Connection connection = factory.newConnection();
final Channel channel = connection.createChannel(); channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); channel.basicQos(1); DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8"); System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
} finally {
System.out.println(" [x] Done");
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
};
channel.basicConsume(TASK_QUEUE_NAME, false, deliverCallback, consumerTag -> { });
} private static void doWork(String task) {
for (char ch : task.toCharArray()) {
if (ch == '.') {
try {
Thread.sleep(1000);
} catch (InterruptedException _ignored) {
Thread.currentThread().interrupt();
}
}
}
}
}

1. 消息确认
2. 消息的持久化
3. 公平调度原则
至于啥是TTL???
1. 如何给消息加上TTL?
* 为消息添加TTL时间的方式有两种
* (1) 为添加进入队列的每个消息都加上TTL
* (2) 在消息即将公布的时候, 给消息添加上消息的ttl
(1) 为添加进入队列的每个消息都加上TTL
Map<String, Object> arg = new HashMap<>();
arg.put("x-message-ttl", 60000);
channel.queueDeclare(QUEUE, true, false, false, arg);
(2) 在消息即将公布的时候, 给消息添加上消息的ttl
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("600000").build();
channel.basicPublish("my-exchange", QUEUE, properties, message.getBytes());
同一个消息在不同消息队列中是否会同时寿终正寝?
如何修改TTL的时间?
rabbitmqctl set_policy TTL ".*" '{"message-ttl":60000}' --apply-to queues
window:
rabbitmqctl set_policy TTL ".*" "{""message-ttl"":60000}" --apply-to queues
上面的命令将是 60 秒
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-message-ttl", 60000);
channel.queueDeclare("myqueue", false, false, false, args);
临时修改60秒时间
需要注意:
- 在消息即将公布的时候, 给消息添加上ttl时间
2. 如何给队列加上TTL?
rabbitmqctl set_policy expiry ".*" '{"expires":1800000}' --apply-to queues
window:
rabbitmqctl.bat set_policy expiry ".*" "{""expires"":1800000}" --apply-to queues
也可以在消息队列声明的时候为队列加上TTL
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-expires", 1800000);
channel.queueDeclare("myqueue", false, false, false, args);
// 为添加进入队列的每个消息都加上TTL
// Map<String, Object> arg = new HashMap<>();
// arg.put("x-message-ttl", 60000);
// 为队列添加TTL , 半个小时的时间
Map<String, Object> arg = new HashMap<>();
arg.put("x-expires", 1800000);
channel.queueDeclare(QUEUE, true, false, false, arg);
String message = "Hello World";
// 在消息即将公布的时候, 给消息添加上消息的ttl
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("600000").build();
channel.basicPublish("my-exchange", QUEUE, properties, message.getBytes());
package com.xuecheng.manage_cms.rabbit;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
/**
* @author zhengwei
* @version 1.0.0
* @date 2019/12/4 20:29
* @msg
**/
public class Producer01 {
private final static String QUEUE = "helloworld";
public static void main(String[] args) throws Exception {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
connection = factory.newConnection();
channel = connection.createChannel();
channel.queueDeclare(QUEUE, true, false, false, null);
String message = "Hello World";
// 将生产者的通道设置为持久化状态
channel.basicPublish("", QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
System.out.println("[x] Sent'" + message + "'");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}
}
}
package com.xuecheng.manage_cms.rabbit;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author zhengwei
* @version 1.0.0
* @date 2019/12/4 20:50
* @msg
**/
public class Consumer01 {
private static final String QUEUE = "helloworld";
public static void main(String[] args) throws Exception {
func1();
}
public static void func1() throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE, true, false, false, null);
channel.basicQos(1);
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println("receive message..." + message);
try {
doWork(message);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(" [x] Done");
// 应答
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
};
// 开启消费者的自动 Ack 功能
boolean autoAck = false;
channel.basicConsume(QUEUE, autoAck, deliverCallback, (consumerTag) -> {
System.out.println("consumerTag: " + consumerTag);
});
}
public static void doWork(String task) throws InterruptedException {
for (char ch : task.toCharArray()) {
if (ch == '.') {
Thread.sleep(1000);
}
}
}
public static void func() throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE, true, false, false, null);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String exchange = envelope.getExchange();
String routingKey = envelope.getRoutingKey();
long deliveryTag = envelope.getDeliveryTag();
String msg = new String(body, "utf-8");
System.out.println("receive message..." + msg);
channel.basicAck(envelope.getDeliveryTag(), false);
//true if the rejected message should be requeued rather than discarded/dead-lettered
// 如果拒绝的方式是 true 则这个消息不被丢弃, false的话直接丢弃消息
channel.basicReject(envelope.getDeliveryTag(), true);
}
};
channel.basicConsume(QUEUE, true, consumer);
}
}
前言, 了解学习第二阶段的目标是什么???
1. 发布和订阅
1. Exchanges交换器
sudo rabbitmqctl list_exchanges

(3) 发布命名交换器
channel.basicPublish( "logs", "", null, message.getBytes());
2. Temporary queues
是什么?
作用
3. Bindings
(1) 用于交换机和队列之间的绑定
(2) 如何绑定:
channel.queueBind(queueName, "logs", "");
(3) 查看先有的绑定
4. Putting it all together

public class EmitLog {
private static final String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
Connection connection = null;
Channel channel = null;
try {
connection = factory.newConnection();
channel = connection.createChannel();
// 声明一个扇形交换机, 向所有的消费者发布消息
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
String message = "zhazha Hello World";
// 指定 logs(EXCHANGE_NAME) 交换器, 将消息发布出去
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}
}
}
public class ReceiveLogs {
private static final String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, EXCHANGE_NAME, "");
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("message = " + new String(message.getBody(), StandardCharsets.UTF_8));
};
channel.basicConsume(queueName, true, deliverCallback, (consumerTag) -> {
});
}
}
路由选择


直接交换
1. 是什么?
是一个算法, 消息发送到与其binding key与消息routing key完成匹配的队列
绑定键就是图中的orange, black, green, 直接交换就是图中的 direct 就是那个 X
核心: 关注routing key, 这个就是将消息传递到这个绑定键的东西

多重绑定

发出日志
emmmmmmmmmmmm
订阅


总结

public class EmitLogDirect {
private static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String routingKey = "info";
String message = "zhazha";
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println(" [x] Sent '" + routingKey + "':'" + message + "'");
}
}
public class ReceiveLogsDirect {
private static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] args) throws IOException, TimeoutException {
String[] argv = new String[]{"info", "warning", "error"};
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String queueName = channel.queueDeclare().getQueue();
for (String routingKey : argv) {
channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
}
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println(" [x] Received '" + delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
};
channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {
});
}
}
主题 -- Topics

[心得体会]RabbitMQ的更多相关文章
- 关于Solr的使用总结的心得体会
摘要:在项目中使用Solr作为搜索引擎对大数据量创建索引,提供服务,本文是作者对Solr的使用总结的一点心得体会, 具体包括使用DataImportHandler从数据库中近实时同步数据.测试Solr ...
- 加快FineReport报表设计的几个心得体会
加快FineReport报表设计的几个心得体会 一.从远程服务器大批量取数进行表样设计时,最好按“列顺序”取一个“空的SQL语句”,这样可提高设计速度.否则每次设计时模板均要从远程读取数据,速度相当慢 ...
- 十天来学习java的心得体会
有关学习java是几天来的心得体会: 十天学习java遇到很多问题,每个问题都是经过反复的看书本以及上网查找资料来解决的,发现这一点真的需要自己来而不是去遇到什么问题就去依靠他人(师兄.同学).在其中 ...
- 消息中间件的技术选型心得-RabbitMQ、ActiveMQ和ZeroMQ
消息中间件的技术选型心得-RabbitMQ.ActiveMQ和ZeroMQ 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs RabbitMQ.Active ...
- Git的基本使用方法和安装&心得体会
1. git的安装和github的注册.代码托管.创建organization.邀请member. (1)git的安装 因为我电脑是windows系统,所以下载的是git for windows.在官 ...
- "琳琅满屋"调查问卷 心得体会及结果分析
·关于心得体会 当时小组提出这个校园二手交易市场的时候,就确定了对象范围,仅仅是面向在校大学生,而且在我们之前就已经有了很多成功的商品交易的例子可以让我们去借鉴,再加上我们或多或少的有过网 ...
- 关于多本小说站的SEO—从”易读中文网”获得的心得体会
从目前国内的网站流量来说,电影站,小说站,游戏站等的流量占总流量的比例还是很高的,许多站长把目光投入到了这几个方面,本文就着重来说对于小说站,尤其是多本小说站的SEO心得体会! 对于小说站来说,只要排 ...
- AngularJS心得体会
AngularJS早些时候有过了解,知道这是一个JS的MVC框架,同类型的框架还有Backbone等.这次是由于项目需要,学习了两天的Angular后开始着手改之前的项目代码,这里大概说一下这一周学习 ...
- 关于Dropdownlist使用的心得体会
2013-07-23关于Dropdownlist使用的心得体会: Dropdownlist使用最多的几个属性: 一.Dropdownlist.Items,负责包含所有选项的容器 DropDownLis ...
随机推荐
- xxl-job使用遇到的问题(二)
xxl-job使用遇到的问题(二) 关联阅读 xxl-job使用遇到的问题(一) 1.问题现象 最近有个老定时任务迁移到xxl-job的时候,遇到一个小问题.虽然很快解决,但是还是有必要记录一下~ j ...
- lua table的遍历
--ordered table iterator sorted by key function pairsByKeys(t) local a = {} for n in pairs(t) do a[# ...
- .NET平台系列16 .NET5/Asp.Net Core 在全球Web框架权威性能测试 Web Framework Benchmarks 中的吊炸天表现
系列目录 [已更新最新开发文章,点击查看详细] TechEmpower Web Framework Benchmarks 是许多Web应用程序框架执行基本任务(如JSON序列化.数据库访问和服 ...
- Sqlflow 之隐私政策(Privacy plolicy)介绍
在大数据技术流行的今天,SQLFlow 可以通过分析各种数据库对象的定义给开发和管理者带来很大的助力.能够让您在大数据时代应对自如,如虎添翼. 在之前的文章中我们已经详细介绍过SQLFlow是什么.能 ...
- 卷积神经网络(CNN,ConvNet)
卷积神经网络(CNN,ConvNet) 卷积神经网络(CNN,有时被称为 ConvNet)是很吸引人的.在短时间内,变成了一种颠覆性的技术,打破了从文本.视频到语音等多个领域所有最先进的算法,远远超出 ...
- MinkowskiEngine多GPU训练
MinkowskiEngine多GPU训练 目前,MinkowskiEngine通过数据并行化支持Multi-GPU训练.在数据并行化中,有一组微型批处理,这些微型批处理将被送到到网络的一组副本中. ...
- Single Shot Multibox Detection (SSD)实战(上)
Single Shot Multibox Detection (SSD)实战(上) 介绍了边界框.锚框.多尺度对象检测和数据集.现在,我们将利用这些背景知识构建一个目标检测模型:单次多盒检测(SSD) ...
- CSS 常见问题笔记
CSS 常见问题 布局 一.盒模型宽度计算 问题:div1 的 offsetWidth 是多少? <style> #div1 { width: 100px; padding: 10px; ...
- SpringBoot原理深入及源码剖析(一) 依赖管理及自动配置
前言 传统的Spring框架实现一个Web服务需要导入各种依赖jar包,然后编写对应的XML配置文件等,相较而言,SpringBoot显得更加方便.快捷和高效.那么,SpringBoot究竟是如何做到 ...
- springmvc——CharacterEncodingFilter过滤器要放在所有过滤器前面
CharacterEncodingFilter的拦截顺序必须是第一个,否则还是会出现乱码问题.这是因为 request对象的parameter并不是一开始就解析的,它是等你第一次调用getParame ...