一、Virtual Hosts

每一个 RabbitMQ 服务器都能创建虚拟的消息服务器,我们称之为虚拟主机 (virtual host) ,简称为vhost。每一个 vhost 本质上是一个独立的小型 RabbitMQ 服务器,拥有自己独立的队列、交换器及绑定关系等,井且它拥有自己独立的权限。vhost 就像是虚拟机与物理服务器一样,它们在各个实例间提供逻辑上的分离,为不同程序安全保密地运行数据,它既能将同一个RabbitMQ 中的众多客户区分开,又可以避免队列和交换器等命名冲突。vhost 之间是绝对隔离的,无法将 vhostl 中的交换器与 vhost2 中的队列进行绑定,这样既保证了安全性,又可以确保可移植性。如果在使用 RabbitMQ 达到一定规模的时候,建议用户对业务功能、场景进行归类区分,并为之分配独立的 vhost。

1.1、Virtual Hosts 的功能说明

vhost可以限制最大连接数和最大队列数,并且可以设置vhost下的用户资源权限和Topic权限,具体权限见下方说明。
  • 在 Admin -> Limits 页面可以设置vhost的最大连接数和最大队列数,达到限制后,继续创建,将会报错。
AMQP 0-9-1 Operation   configure write read
exchange.declare (passive=false) exchange    
exchange.declare (passive=true)      
exchange.declare (with [AE](ae.html)) exchange exchange (AE) exchange
exchange.delete   exchange    
queue.declare (passive=false) queue    
queue.declare (passive=true)      
queue.declare (with [DLX](dlx.html)) queue exchange (DLX) queue
queue.delete   queue    
exchange.bind     exchange (destination) exchange (source)
exchange.unbind     exchange (destination) exchange (source)
queue.bind     queue exchange
queue.unbind     queue exchange
basic.publish     exchange  
basic.get       queue
basic.consume       queue
queue.purge       queue
 
举例说明:
    • 比如创建队列时,会调用 queue.declare 方法,此时会使用到 configure 权限,会校验队列名是否与 configure 的表达式匹配。
    • 比如队列绑定交换器时,会调用 queue.bind 方法,此时会用到 write 和 read 权限,会检验队列名是否与 write 的表达式匹配,交换器名是否与 read 的表达式匹配。
    • Topic权限是RabbitMQ 针对STOMP和MQTT等协议实现的一种权限。由于这类协议都是基于Topic消费的,而AMQP是基于Queue消费,所以AMQP的标准资源权限不适合用在这类协议中,而Topic权限也不适用于AMQP协议。所以,我们一般不会去使用它,只用在使用了MQTT这类的协议时才可能会用到。

2.2、vhost使用示例

1. 使用管理员用户登录Web管理界面。
2.页面添加一个名为 v1 的Virtual Hosts。(此时还需要为此vhost分配用户,添加一个新用户)

3.在 Admin -> Users 页面添加一个名为 order-user 的用户,并设置为 management 角色。

4. 从 Admin 进入 order-user 的用户设置界面,在 Permissions 中,为用户分配vhost为/v1,并为每种权限设置需要匹配的目标名称的正则表达式。
 

字段名
值 
说明 
Virtual Host 
/v1 
指定用户的vhost,以下权限都只限于 /v1 vhost中
Configure regexp
eq-.*
只能操作名称以eq-开头的exchange或queue;为空则不能操作任何exchange和queue 
Write regexp 
.*
能够发送消息到任意名称的exchange,并且能绑定到任意名称的队列和任意名称的目标交
换器(指交换器绑定到交换器),为空表示没有权限 
Read regexp 
^test$ 
只能消费名为test队列上的消息,并且只能绑定到名为test的交换器
5.代码演示
public class Producer {
public static void main(String[] args) {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置连接属性
factory.setUsername("order-user");
factory.setPassword("order-user");
factory.setVirtualHost("v1"); Connection connection = null;
Channel channel = null; // 3、设置每个节点的链接地址和端口
Address[] addresses = new Address[]{
new Address("192.168.0.1", 5672),
new Address("192.168.0.2", 5672)
}; try {
// 开启/关闭连接自动恢复,默认是开启状态
factory.setAutomaticRecoveryEnabled(true); // 设置每100毫秒尝试恢复一次,默认是5秒:com.rabbitmq.client.ConnectionFactory.DEFAULT_NETWORK_RECOVERY_INTERVAL
factory.setNetworkRecoveryInterval(100); factory.setTopologyRecoveryEnabled(false); // 4、使用连接集合里面的地址获取连接
connection = factory.newConnection(addresses, "生产者"); // 添加重连监听器
((Recoverable) connection).addRecoveryListener(new RecoveryListener() {
/**
* 重连成功后的回调
* @param recoverable
*/
public void handleRecovery(Recoverable recoverable) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 已重新建立连接!");
} /**
* 开始重连时的回调
* @param recoverable
*/
public void handleRecoveryStarted(Recoverable recoverable) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 开始尝试重连!");
}
}); // 5、从链接中创建通道
channel = connection.createChannel(); /**
* 6、声明(创建)队列
* 如果队列不存在,才会创建
* RabbitMQ 不允许声明两个队列名相同,属性不同的队列,否则会报错
*
* queueDeclare参数说明:
* @param queue 队列名称
* @param durable 队列是否持久化
* @param exclusive 是否排他,即是否为私有的,如果为true,会对当前队列加锁,其它通道不能访问,并且在连接关闭时会自动删除,不受持久化和自动删除的属性控制
* @param autoDelete 是否自动删除,当最后一个消费者断开连接之后是否自动删除
* @param arguments 队列参数,设置队列的有效期、消息最大长度、队列中所有消息的生命周期等等
*/
channel.exchangeDeclare("test-exchange", "fanout");
channel.queueDeclare("queue1", false, false, false, null);
channel.queueBind("queue1", "test-exchange", "xxoo");
for (int i = 0; i < 100; i++) {
// 消息内容
String message = "Hello World " + i;
try {
// 7、发送消息
channel.basicPublish("test-exchange", "queue1", null, message.getBytes());
} catch (AlreadyClosedException e) {
// 可能连接已关闭,等待重连
System.out.println("消息 " + message + " 发送失败!");
i--;
TimeUnit.SECONDS.sleep(2);
continue;
}
System.out.println("消息 " + i + " 已发送!");
TimeUnit.SECONDS.sleep(2);
} } catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 8、关闭通道
if (channel != null && channel.isOpen()) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
} // 9、关闭连接
if (connection != null && connection.isOpen()) {
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class VirtualHosts {
public static void main(String[] args) {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置连接属性
factory.setUsername("order-user");
factory.setPassword("order-user");
factory.setVirtualHost("v1"); Connection connection = null;
Channel prducerChannel = null;
Channel consumerChannel = null; // 3、设置每个节点的链接地址和端口
Address[] addresses = new Address[]{
new Address("192.168.0.1", 5672),
new Address("192.168.0.2", 5672)
}; try {
// 4、从连接工厂获取连接
connection = factory.newConnection(addresses, "消费者"); // 5、从链接中创建通道
prducerChannel = connection.createChannel(); prducerChannel.exchangeDeclare("test-exchange", "fanout");
prducerChannel.queueDeclare("queue1", false, false, true, null);
prducerChannel.queueBind("queue1", "test-exchange", "xxoo");
// 消息内容
String message = "Hello A";
prducerChannel.basicPublish("test-exchange", "c1", null, message.getBytes()); consumerChannel = connection.createChannel();
// 创建一个消费者对象
Consumer consumer = new DefaultConsumer(consumerChannel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("收到消息:" + new String(body, "UTF-8"));
}
};
consumerChannel.basicConsume("queue1", true, consumer); System.out.println("等待接收消息");
System.in.read();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
// 9、关闭通道
if (prducerChannel != null && prducerChannel.isOpen()) {
try {
prducerChannel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
} // 10、关闭连接
if (connection != null && connection.isOpen()) {
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

2.3、集群连接恢复

官方资料:https://www.rabbitmq.com/api-guide.html#connection-recovery;根据官方文档说明可知:
  • 通过 factory.setAutomaticRecoveryEnabled(true); 可以设置连接自动恢复的开关,默认已开启
  • 通过 factory.setNetworkRecoveryInterval(10000); 可以设置间隔多长时间尝试恢复一次,默认是5秒: com.rabbitmq.client.ConnectionFactory.DEFAULT_NETWORK_RECOVERY_INTERVAL
  • 如果启用了自动连接恢复,将由以下事件触发:
    • 连接的I/O循环中抛出IOExceiption
    • 读取Socket套接字超时
    • 检测不到服务器心跳
    • 在连接的I/O循环中引发任何其他异常
  • 如果客户端第一次连接失败,不会自动恢复连接。需要我们自己负责重试连接、记录失败的尝试、实现重试次数的限制等等。
ConnectionFactory factory = new ConnectionFactory();
// configure various connection settings try {
Connection conn = factory.newConnection();
} catch (java.net.ConnectException e) {
Thread.sleep(5000);
// apply retry logic
}
    • 如果程序中调用了 Connection.Close ,也不会自动恢复连接。
    • 如果是 Channel-level 的异常,也不会自动恢复连接,因为这些异常通常是应用程序中存在语义问题(例如试图从不存在的队列消费)。
  • 在Connection和Channel上,可以设置重新连接的监听器,开始重连和重连成功时,会触发监听器。添加和移除监听,需要将Connection或Channel强制转换成Recoverable接口。
((Recoverable) connection).addRecoveryListener() 
((Recoverable) connection).removeRecoveryListener()

git源码:https://gitee.com/TongHuaShuShuoWoDeJieJu/rabbit.git

RabbitMQ的web页面介绍(三)的更多相关文章

  1. RabbitMQ 在 web 页面 创建 exchange, queue, routing key

    这里只是为了展示, 在实际开发中一般在消费端通过 注解来自动创建 消费端: https://www.cnblogs.com/huanggy/p/9695934.html 1, 创建 Exchange ...

  2. web页面的加载顺序

    1.页面顺序 一个典型的web页面由于三个部分组成:html.css和JS.执行的顺序是: 在构造完HTML的dom结构时.触发DOMContentLoaded事件. 整个执行过程安装html的顺序来 ...

  3. Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群

    Redis总结(五)缓存雪崩和缓存穿透等问题   前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...

  4. web页面相关的一些常见可用字符介绍

    首先是一张图片,是一张一些字符以及想对应的HTML实体表示的对照图片.如下: 一.引号模样或内心的些字符 请选择该表格要呈现的字体: 字符以及HTML实体 描述以及说明 " " 这 ...

  5. web页面相关的一些常见可用字符介绍——张鑫旭

    by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1623 正文开始之前先 ...

  6. IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(三)

    IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(三) 后台服务用户与认证 新建一个空的.net core web项目Demo.Chat,端口配置为 ...

  7. 打印web页面指定区域的三种方法

    本文和大家分享一下web页面实现指定区域打印功能的三种方法,一起来看下吧. 第一种方法:使用CSS 定义一 个.noprint的class,将不打印的内容放入这个class内. 代码如下: <s ...

  8. (转)Django学习之 第三章:动态Web页面基础

    上一章我们解释了怎样开始一个Django项目和运行Django服务器 当然了,这个站点实际上什么也没有做------除了显示了"It worked"这条信息以外. 这一章我们介绍怎 ...

  9. [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设

    [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设 敲黑板!! <q>元素添加短引用,<blockquote>添加长引用 在段落里添加引用就使用< ...

随机推荐

  1. 关于对String中intern方法的理解

    在java的String中有个一直被我们忽视了的方法intern方法:它的官方解释是:一个初始时为空的字符串池,它由类 String 私有地维护. 当调用 intern 方法时,如果池已经包含一个等于 ...

  2. JDBC基础篇(MYSQL)——使用CallabeStatement调用存储过程

    注意:其中的JdbcUtil是我自定义的连接工具类:代码例子链接: package day04_callable; import java.sql.CallableStatement; import ...

  3. 分治算法:Tromino谜题,L型覆盖

    1 public class Tromino { 2 3 static int num = 2; 4 //x 对应 第二维 5 //y 对应 第一维 6 static int[][] panel = ...

  4. Ubuntu16.04 + OpenCV源码 + Qt5.10 安装、配置

    在VMWare中配置安装Ubuntu16.04.没有什么特别的地方,正常安装即可. 安装最新版qt,此时5.10.按照普通QT教程安装(需要勾选gcc),无须sudo,此时不用管OpenCV.地址:h ...

  5. Java并发之AQS原理解读(三)

    上一篇:Java并发之AQS原理解读(二) 前言 本文从源码角度分析AQS共享锁工作原理,并介绍下使用共享锁的子类如何工作的. 共享锁工作原理 共享锁与独占锁的不同之处在于,获取锁和释放锁成功后,都会 ...

  6. Centos7部署Open-falcon 0.2.0

    官方和github上都有教程,但是对于我来说有的部署内容较为陌生,有点错误官方也未在教程中说明,故在此记录方便以后快速部署,本文部署的时间是2018/10/10. 虽然open-falcon是采用了前 ...

  7. 洛谷P1083 借教室 题解

    题目 [NOIP2012 提高组] 借教室 题解 这道题是几周之前做到的一道题,本来不想讲的,因为这道题也是用到了二分答案的方法,这类题目之前已经发布过两篇题解了.但这道题还运用了差分数组这个思想,所 ...

  8. Django——Auth模块(用户认证模块)

    1.Auth模块简介 auth模块是对登录认证方法的一种封装,之前我们获取用户输入的用户名及密码后需要自己从user表里查询有没有用户名和密码符合的对象. 而有了auth模块之后就可以很轻松的去验证用 ...

  9. Docker(23)- 注册 docker hub 的账号

    如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 前言 Docker Hub 是 ...

  10. python库--flashtext--大规模数据清洗利器

    flashtext.keyword (flashtext) 类/方法 返回值 参数 说明 .KeywordProcessor() 对象kp case_sensitive=False 是否区分大小写 添 ...