11.RabbitMQ单机集群
RabbitMQ集群设计用于完成两个目标:允许消费者和生产者在RabbitMQ节点崩溃的情况下继续运行,以及通过添加更多的节点来扩展消息通信的吞吐量。
RabbitMQ会始终记录以下四种类型的内部元数据:
1. 队列元数据-队列的名称和它们的属性(是否持久化,是否自动删除)
2. 交换器元数据-交换器类型、名称和属性(可持久化等)
3. 绑定元数据-一张简单的表格展示了如何将消息路由到队列
4. vhost元数据-为vhost内的队列、交换器和绑定提供命名空间和安全属性
在单一节点内,RabbitMQ会将所有这些信息存储在内存中,同时将那些标记为可持久化的队列和交换器(以及它们的绑定)存储到硬盘上。当你引入集群时,RabbitMQ需要追踪新的元数据类型:集群节点位置,以及节点与已记录的其他类型元数据的关系。集群提供了选择:将元数据存储到磁盘上,或者存储在内存中。
Erlang Cookie
Erlang Cookie是保证不同节点可以相互通信的密钥,要保证集群中的不同节点相互通信必须共享相同的Erlang Cookie。具体的目录存放在/var/lib/rabbitmq/.erlang.cookie。
说明: 这就要从rabbitmqctl命令的工作原理说起,RabbitMQ底层是通过Erlang架构来实现的,所以rabbitmqctl会启动Erlang节点,并基于Erlang节点来使用Erlang系统连接RabbitMQ节点,在连接过程中需要正确的Erlang Cookie和节点名称,Erlang节点通过交换Erlang Cookie以获得认证。
镜像队列
功能和原理
RabbitMQ的Cluster集群模式一般分为两种,普通模式和镜像模式。
普通模式:默认的集群模式,以两个节点(rabbit01、rabbit02)为例来进行说明。对于Queue来说,消息实体只存在于其中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02两个节点仅有相同的元数据,即队列的结构。当消息进入rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01、rabbit02间进行消息传输,把A中的消息实体取出并经过B发送给consumer。所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会产生瓶颈。当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
镜像模式:将需要消费的队列变为镜像队列,存在于多个节点,这样就可以实现RabbitMQ的HA高可用性。作用就是消息实体会主动在镜像节点之间实现同步,而不是像普通模式那样,在consumer消费数据时临时读取。缺点就是,集群内部的同步通讯会占用大量的网络带宽。
内存节点和磁盘节点
每个RabbitMQ节点,要么是内存节点(ram
node),要么是磁盘节点(disk
node)。内存节点将所有的队列、交换器、绑定、用户、权限和vhost的元数据定义都仅存在内存中。而磁盘节点则将元数据存储在磁盘中。
内存节点的效率更高,内存节点唯一存储到磁盘上的是磁盘节点的地址。
RabbitMQ要求集群中至少有一个磁盘节点。当节点加入或者离开集群时,它们必须要将该变更通知到至少一个磁盘节点。如果只有一个磁盘节点,而且不凑巧的是它又崩溃了,那么集群可以继续路由消息,但是不能做以下操作了:
1.
创建队列
2.
创建交换器
3.
创建绑定
4.
添加用户
5.
更改权限
单机环境搭建多节点群集
1、禁用管理后台插件rabbitmq-plugins disable
rabbitmq_management
2、创建三个Shell文件
rabbitmq1.sh
#!/bin/bash
export
RABBITMQ_NODE_PORT=5672
export
RABBITMQ_NODENAME=rabbit
rabbitmq-server
rabbitmq2.sh
#!/bin/bash
export
RABBITMQ_NODE_PORT=5673
export
RABBITMQ_NODENAME=rabbit2
rabbitmq-server
rabbitmq3.sh
#!/bin/bash
export
RABBITMQ_NODE_PORT=5674
export
RABBITMQ_NODENAME=rabbit3
rabbitmq-server
3、停止在Erlang节点上运行的节点2和节点3
RabbitMQ Server 并清空(重置)它们的元数据
rabbitmqctl -n rabbit1@localhost
stop_app
rabbitmqctl -n rabbit2@localhost
stop_app
rabbitmqctl -n rabbit1@localhost
reset
rabbitmqctl -n rabbit2@localhost
reset
4、将节点2作为磁盘节点加入集群并启动应用
rabbitmqctl -n rabbit1@localhost
join_cluster rabbit@localhost
rabbitmqctl -n rabbit1@localhost
start_app
5、将节点3作为内存节点加入集群并启动应用
rabbitmqctl -n rabbit2@localhost
join_cluster --ram rabbit@localhost
rabbitmqctl -n rabbit2@localhost
start_app
6、运行命令rabbitmqctl cluster_status查看集群状态
Cluster status of node
rabbit@localhost ...
[{nodes,[{disc,[rabbit1@localhost,rabbit@localhost]},
{ram,[rabbit2@localhost]}]},
{running_nodes,[rabbit2@localhost,rabbit1@localhost,rabbit@localhost]},
{cluster_name,<<"rabbit@localhost">>},
{partitions,[]},
{alarms,[{rabbit2@localhost,[]},
{rabbit1@localhost,[]},
{rabbit@localhost,[]}]}]
集群安装成功,这时候java客户端可以连接任何一个RabbitMQ
Server的端口来访问集群了。
7、镜像队列
在声明队列时,可以通过参数"x-ha-policy"设置为"all"来把消息发送到集群的所有节点上。
Map
arg =
new HashMap();
arg.put("x-ha-policy",
"all");
channel.queueDeclare(queueName,
false,
false,
false,
arg);
客户端发送代码
package
com.test.cluster;
import
com.rabbitmq.client.*;
import
java.io.IOException;
import
java.lang.String;
import
java.lang.System;
import
java.util.HashMap;
import
java.util.Map;
import
java.util.Scanner;
public class
Producer {
public static void main(String[] args) throws
Exception {
//使用默认端口连接MQ
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("admin");
factory.setPassword("admin");
factory.setHost("192.168.169.142"); //使用默认端口5672
Connection
conn = factory.newConnection(); //声明一个连接
Channel
channel = conn.createChannel(); //声明消息通道
String
exchangeName = "TestEXG";//交换机名称
String
routingKey = "RouteKey1";//RoutingKey关键字
channel.exchangeDeclare(exchangeName, "direct",
true);//定义声明交换机
String
queueName = "ClusterQueue";//队列名称
Map arg =
new HashMap();
arg.put("x-ha-policy", "all");
channel.queueDeclare(queueName, false, false, false,
arg);
channel.queueBind(queueName, exchangeName,
routingKey);//定义声明对象
byte[]
messageBodyBytes = "Hello, world!".getBytes();//消息内容
channel.basicPublish(exchangeName, routingKey, null,
messageBodyBytes);//发布消息
//关闭通道和连接
channel.close();
conn.close();
}
}
消费者代码
package
com.test.cluster;
import
com.rabbitmq.client.Channel;
import
com.rabbitmq.client.Connection;
import
com.rabbitmq.client.ConnectionFactory;
import
com.rabbitmq.client.QueueingConsumer;
import
java.io.IOException;
import
java.util.HashMap;
import
java.util.Map;
//通过channel.basicAck向服务器发送回执,删除服务上的消息
public class
Consumer {
public static void main(String[] args) throws
IOException, InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("admin");
factory.setPassword("admin");
factory.setHost("192.168.169.142"); //使用默认端口5672
factory.setPort(5672);
Connection
conn = factory.newConnection(); //声明一个连接
Channel
channel = conn.createChannel(); //声明消息通道
String
exchangeName = "TestEXG";//交换机名称
String
queueName = "ClusterQueue";//队列名称
channel.exchangeDeclare(exchangeName, "direct",
true);//定义声明交换机
channel.queueBind(queueName, exchangeName, "RouteKey1");
channel.basicQos(1); //server push消息时的队列长度
//用来缓存服务器推送过来的消息
QueueingConsumer consumer = new
QueueingConsumer(channel);
channel.basicConsume(queueName, false, consumer);
while
(true) {
QueueingConsumer.Delivery
delivery = consumer.nextDelivery();
System.out.println("Received
" + new String(delivery.getBody()));
//回复ack包,如果不回复,消息不会在服务器删除
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),
false);
}
}
}
11.RabbitMQ单机集群的更多相关文章
- RabbitMQ入门教程(十四):RabbitMQ单机集群搭建
原文:RabbitMQ入门教程(十四):RabbitMQ单机集群搭建 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://b ...
- RabbitMQ单机集群搭建出现Error: unable to perform an operation on node 'rabbit1@ClusterNode1'
参考链接:https://www.cnblogs.com/daryl/archive/2017/10/13/7645749.html 全部步骤和参考链接相同. 前八部都正常,在第九步会报错Error: ...
- RabbitMQ (十三) 集群+单机搭建(window)
拜读了网上很多前辈的文章,对RabbitMQ的集群有了一点点认识. 好多文章都说到,RabbitMQ的集群分为普通集群和镜像集群,有的还加了两种:单机集群和主从集群. 我看来看去,看了半天,怎么感觉, ...
- 关于RabbitMQ分布式集群架构
RabbitMQ分布式集群架构和高可用性(HA) (一) 功能和原理 设计集群的目的 允许消费者和生产者在RabbitMQ节点崩溃的情况下继续运行 通过增加更多的节点来扩展消息通信的吞吐量 1 集群配 ...
- 阿里云构建Kafka单机集群环境
简介 在一台ECS阿里云服务器上构建Kafa单个集群环境需要如下的几个步骤: 服务器环境 JDK的安装 ZooKeeper的安装 Kafka的安装 1. 服务器环境 CPU: 1核 内存: 2048 ...
- 部署rabbitMQ镜像集群实战测试
部署rabbitMQ镜像集群 版本信息 rabbit MQ: 3.8.5 Erlang: 官方建议最低21.3 推荐22.x 这里用的是23 环境准备 主机规划 主机 节点 172.16.14.3 磁 ...
- 玩转nodeJS系列:使用原生API实现简单灵活高效的路由功能(支持nodeJs单机集群),nodeJS本就应该这样轻快
前言: 使用nodeJS原生API实现快速灵活路由,方便与其他库/框架进行整合: 1.原生API,简洁高效的轻度封装,加速路由解析,nodeJS本就应该这样轻快 2.不包含任何第三方库/框架,可以灵活 ...
- zookeeper单机集群搭建
1. 下载zookeeper 参考官方文档下载一节:https://zookeeper.apache.org/doc/current/zookeeperStarted.html#sc_Download ...
- Rabbitmq关于集群节点功能的读书笔记
消息和队列可以指定是否持久化,如果指定持久化则会保存到硬盘上 ,不然只在内存里 普通集群模式下持久化的队列不能重建了 内存节点和磁盘节点的区别就是将元数据放在了内存还是硬盘,仅此而已,当在集群中声明队 ...
随机推荐
- Unity Document
{ https://docs.unity3d.com/ScriptReference/Events.UnityEventTools.html }
- PHP ftp_close() 函数
定义和用法 ftp_close() 函数关闭 FTP 连接. 语法 ftp_close(ftp_connection) 参数 描述 ftp_connection 必需.规定要关闭的 FTP 连接. 实 ...
- Shiro学习(19)动态URL权限限制
用过spring Security的朋友应该比较熟悉对URL进行全局的权限控制,即访问URL时进行权限匹配:如果没有权限直接跳到相应的错误页面.Shiro也支持类似的机制,不过需要稍微改造下来满足实际 ...
- HBase与Sqoop集成案例
HBase与Sqoop集成 案例:将RDBMS中的数据抽取到HBase中 Step1.配置sqoop-env.sh如下: Step2.在Mysql中创建一张数据库library,一张表book CRE ...
- delphi基础篇之数据类型概论
delphi基础篇之数据类型概论 Object Pascal 语言提供了非常丰富的数据类型,即简单类型(Simple).字符串类型(String).结构类型(Struct).指针类型(Pointer) ...
- normal use for autotools
1. remove temporary files, only used for test purpose. ls | sed -e rm -rf 2. edit autogen.sh echo &q ...
- Linux初始化的汇编代码
1. 内核文件布局 首先看一下arch/x86/boot/Setup.ld文件,它定义了链接后的内核文件布局. 1: /* 2: * setup.ld 3: * 4: * Linker script ...
- 【Java多线程系列随笔一】浅析 Java Thread.join()
一.在研究join的用法之前,先明确两件事情. 1.join方法定义在Thread类中,则调用者必须是一个线程, 例如: Thread t = new CustomThread(); //这里一般是自 ...
- Netty 源码学习——客户端流程分析
Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...
- 集合 HashMap 的原理,与 Hashtable、ConcurrentHashMap 的区别
一.HashMap 的原理 1.HashMap简介 简单来讲,HashMap底层是由数组+链表的形式实现,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表 ...