消息中间件之RabbitMQ

市面上的消息队列产品有很多,如老牌的 ActiveMQ、RabbitMQ ,目前我看最火的 Kafka ,还有 ZeroMQ ,去年底阿里巴巴捐赠给 Apache 的 RocketMQ ,连redis 这样的 NoSQL 数据库也支持 MQ 功能。总之这块知名的产品就有十几种,本文讲一下RabbitMQ。

 

消息中间件

消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。

消息队列(Message Queue)又叫消息中间件,是一种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息的可靠传递。消息发布者只管把消息发布到 MQ 中而不用管谁来取,消息使用者只管从 MQ 中取消息而不管是谁发布的。这样发布者和使用者都不用知道对方的存在。

消息队列中间件,一般有两种传递模式:点对点(P2P) 模式和发布/订阅(Pub/Sub)模式:

  1. 点对点模式时基于队列的,消息生产者发送消息到队列,消息消费者从队列中接收消息,队列的存在使得消息的异步传输成为可能。

  2. 发布订阅模式定义了如何像一个内容节点发布和订阅消息,该内容节点称为主题(topic) 主题可以认为是消息传递的中介,消息发布者将消息发布到中介,消息订阅者从主题中订阅消息。主题使得订阅者、发布者独立。

 

为何用消息中间件

从上面的描述中可以看出消息中间件是一种应用间的异步协作机制,那什么时候需要使用 MQ 呢?

针对异步任务实现

以常见的订单系统为例,用户点击【下单】按钮之后的业务逻辑可能包括:扣减库存、生成相应单据、发红包、发短信通知。在业务发展初期这些逻辑可能放在一起同步执行,随着业务的发展订单量增长,需要提升系统服务的性能,这时可以将一些不需要立即生效的操作拆分出来异步执行,比如发放红包、发短信通知等。这种场景下就可以用 MQ ,在下单的主流程(比如扣减库存、生成相应单据)完成之后发送一条消息到 MQ 让主流程快速完结,而由另外的单独线程拉取MQ的消息(或者由 MQ 推送消息),当发现 MQ 中有发红包或发短信之类的消息时,执行相应的业务逻辑。

以上是用于业务解耦的情况,其它常见场景包括最终一致性、广播、错峰流控、缓冲等等。

 

关于python的queue介绍

关于python的队列,内置的有两种,一种是线程queue,另一种是进程queue,但是这两种queue都是只能在同一个进程下的线程间或者父进程与子进程之间进行队列通讯,并不能进行程序与程序之间的信息交换,这时候我们就需要一个中间件,来实现程序之间的通讯。

 

RabbitMQ

RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现,可做到热插拔(无需重启)。

AMQP :Advanced Message Queue,高级消息队列协议。它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。

RabbitMQ 最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。具体特点包括:

  1. 可靠性(Reliability)
    RabbitMQ 使用一些机制来保证可靠性,如持久化、传输确认、发布确认。

  2. 灵活的路由(Flexible Routing)
    在消息进入队列之前,通过 Exchange 来路由消息的。对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对更复杂的路由功能,可以将多个 Exchange 绑定在一起,也通过插件机制实现自己的 Exchange 。

  3. 消息集群(Clustering)
    多个 RabbitMQ 服务器可以组成一个集群,形成一个逻辑 Broker 。

  4. 高可用(Highly Available Queues)
    队列可以在集群中的机器上进行镜像,使得在部分节点出问题的情况下队列仍然可用。

  5. 多种协议(Multi-protocol)
    RabbitMQ 支持多种消息队列协议,比如 STOMP、MQTT 等等。

  6. 多语言客户端(Many Clients)
    RabbitMQ 几乎支持所有常用语言,比如 Java、.NET、Ruby 等等。

  7. 管理界面(Management UI)
    RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。

  8. 跟踪机制(Tracing)
    如果消息异常,RabbitMQ 提供了消息跟踪机制,使用者可以找出发生了什么。

  9. 插件机制(Plugin System)
    RabbitMQ 提供了许多插件,来从多方面进行扩展,也可以编写自己的插件。

 

RabbitMQ 中的概念介绍

RabbitMQ整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。可以把消息传递的过程想象成:包裹送到邮局,邮局暂存并最终通过邮递员送到收件人手上。RabbitMQ好比邮局、邮箱和邮递员组成的一个系统,从计算机层面来说,RabbitMQ 模型更像是一种交换机模型。

RabbitMQ整体模型架构:

 

RabbitMQ 内部结构

  1. Message
    消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。
  2. Publisher
    消息的生产者,也是一个向交换器发布消息的客户端应用程序。
  3. Exchange
    交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。
  4. Binding
    绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
  5. Queue
    消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。
  6. Connection
    网络连接,比如一个TCP连接。
  7. Channel
    信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内地虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。
  8. Consumer
    消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。
  9. Virtual Host
    虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。
  10. Broker
    表示消息队列服务器实体。

 

消息队列的运转过程

首先生产者将业务数据进行可能的包装,之后封装成消息,发送到Broker, 消费者订阅并接受消息,经过可能的解包处理得到原始的数据,之后再进行业务处理逻辑。这个业务处理逻辑并不一定需要和接受消息的逻辑使用同一个线程。消费者进程可以使用一个线程去接收消息,存入到内存中。这会进一步解耦,提高整个应用的处理效率。

 

RabbitMQ中概念的详解:

Queue

Queue(队列)是RabbitMQ的内部对象,用于存储消息,用下图表示。

RabbitMQ中的消息都只能存储在Queue中,生产者(下图中的P)生产消息并最终投递到Queue中,消费者(下图中的C)可以从Queue中获取消息并消费。

多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

 

Exchange

在上一节我们看到生产者将消息投递到Queue中,实际上这在RabbitMQ中这种事情永远都不会发生。实际的情况是,生产者将消息发送到Exchange(交换器,下图中的X),由Exchange将消息路由到一个或多个Queue中(或者丢弃)。

Exchange是按照什么逻辑将消息路由到Queue的?这个将在下面的Binding中介绍。

RabbitMQ中的Exchange有四种类型,不同的类型有着不同的路由策略,这将在下面的Exchange Types中介绍。

 

routing key

生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。

在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里。RabbitMQ为routing key设定的长度限制为255 bytes。

 

Binding

RabbitMQ中通过Binding将Exchange与Queue关联起来,这样RabbitMQ就知道如何正确地将消息路由到指定的Queue了。

Binding key

  • 在绑定(Binding)Exchange与Queue的同时,一般会指定一个binding key;消费者将消息发送给Exchange时,一般会指定一个routing key;当binding key与routing key相匹配时,消息将会被路由到对应的Queue中。这个将在Exchange Types章节会列举实际的例子加以说明。
  • 在绑定多个Queue到同一个Exchange的时候,这些Binding允许使用相同的binding key。
  • binding key 并不是在所有情况下都生效,它依赖于Exchange Type,比如fanout类型的Exchange就会无视binding key,而是将消息路由到所有绑定到该Exchange的Queue。

 

Exchange Types

RabbitMQ常用的Exchange Type有fanout、direct、topic、headers这四种(AMQP规范里还提到两种Exchange Type,分别为system与自定义,这里不予以描述),下面分别进行介绍。

1. fanout

  • fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。

  • 上图中,生产者(P)发送到Exchange(X)的所有消息都会路由到图中的两个Queue,并最终被两个消费者(C1与C2)消费。

 

2. direct

  • direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。

  • 以上图的配置为例,我们以routingKey=”error”发送消息到Exchange,则消息会路由到Queue1(amqp.gen-S9b…,这是由RabbitMQ自动生成的Queue名称)和Queue2(amqp.gen-Agl…);如果我们以routingKey=”info”或routingKey=”warning”来发送消息,则消息只会路由到Queue2。如果我们以其他routingKey发送消息,则消息不会路由到这两个Queue中。

 

3. topic

  • 前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同,它约定:
  • routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
  • binding key与routing key一样也是句点号“. ”分隔的字符串。
  • binding key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)。

  • 以上图中的配置为例,routingKey=”quick.orange.rabbit”的消息会同时路由到Q1与Q2,routingKey=”lazy.orange.fox”的消息会路由到Q1与Q2,routingKey=”lazy.brown.fox”的消息会路由到Q2,routingKey=”lazy.pink.rabbit”的消息会路由到Q2(只会投递给Q2一次,虽然这个routingKey与Q2的两个bindingKey都匹配);routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的消息将会被丢弃,因为它们没有匹配任何bindingKey。

 

4. headers

  • headers类型的Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
  • 在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。
  • 该类型的Exchange没有用到过(不过也应该很有用武之地),所以不做介绍。

 

RPC

MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)。

但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。在RabbitMQ中也支持RPC。

RabbitMQ中实现RPC的机制是:

  • 客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14中properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败);

服务器端收到消息并处理;

  • 服务器端处理完消息后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性;
  • 客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理。

 

 

RabbitMQ运转流程

了解了RabbitMQ架构模型及相关术语后,再回顾整个消息队列的使用过程。

最初状态下,生产者发送消息:

  1. 生产者连接到RabbitMQ Broker, 建立一个连接(Connection) , 开启一个信道 (Channel)
  2. 生产者声明一个交换器,并设置相关属性,比如交换机类型,是否持久化等。
  3. 生产者声明一个队列并设置相关属性,比如是否排他,是否持久化,是否自动删除等。
  4. 生产者通过路由键将交换器和队列绑定起来。
  5. 生产者发送消息至RabbitMQ Broker, 其中包含路由键,交换器等信息。
  6. 相应的交换器根据收到的路由键查找匹配的队列。
  7. 找到,则将生产者发送过来的消息存入相应队列。
  8. 未找到,则根据生产者配置的属性选择丢弃还是回退给生产者。
  9. 关闭信道。
  10. 关闭连接。

消费者接收消息的过程:

  1. 消费者连接到RabbitMQ Broker, 建立一个连接 (Connection) , 开启一个信道(Channel)。
  2. 消费者向RabbitMQ Broker 请求消费相应队列中的消息,可能会设置相应的回调函数,以及做一些准备工作。
  3. 等待RabbitMQ Broker 回应并投递相应队列中的消息,消费者接收消息。
  4. 消费者确认(ack) 接收到消息。
  5. RabbitMQ 从队列中删除相应的已经被确认的消息。
  6. 关闭信道。

上面介绍运转过程中引入了:Connection 和 Channel.

无论生产者还是消费者,都需要和RabbitMQ Broker 建立连接, 这个连接就是一条TCP连接, 也就是Connection。一旦TCP连接建立起来, 客户端紧接着可以建立一个AMQP信道(Channel) ,每个信道都会被职派一个唯一的ID。 信道是建立再Connection之上的虚拟连接, RabbitMQ处理的每条AMQP命令都是通过信道完成。

完全可以使用Connection就能完成信道的工作,之所以引入信道,是应对如下场景:

一个应用程序中有多个线程需要从RabbitMQ中消费消息,或者生产信息,那么必然要建立多个Connection, 也就是多个TCP连接,对操作系统来说,建立和销毁TCP连接时非常昂贵的开销,如果遇到使用高峰,性能瓶颈也随之显现。RabbitMQ采用类型NIO(Non-blocking I/O) 的做法,选择TCP连接复用,减少性能开销同时便于管理。

每个线程把握一个信道,所以信道复用了Connection的TCP连接,同时RabbitMQ可以确保每个线程的私密性,就像拥有独立的连接一样。

 

RabbitMQ 安装

一般来说安装 RabbitMQ 之前要安装 Erlang ,可以去Erlang官网下载。接着去RabbitMQ官网下载安装包,之后解压缩即可。根据操作系统不同官网提供了相应的安装说明:WindowsDebian / UbuntuRPM-based LinuxMac

Python 使用rabbitMQ需要 pika

pip install pika
or
源码  
https://pypi.python.org/pypi/pika

RabbitMQ设置远程链接账号密码

启动rabbitmq web服务:

远程访问rabbitmq:自己增加一个用户,步骤如下:

  • 1. 创建一个admin用户:sudo rabbitmqctl add_user admin 123123

  • 2. 设置该用户为administrator角色:sudo rabbitmqctl set_user_tags admin administrator

  • 3. 设置权限:sudo rabbitmqctl set_permissions -p '/' admin '.' '.' '.'

  • 4. 重启rabbitmq服务:sudo service rabbitmq-server restart

之后就能用admin用户远程连接rabbitmq server了。

生产者:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
Channel = connection.channel()

# 声明queue
Channel.queue_declare(queue='hello')

# rabbitmq 不能直接发送至队列,需要exchange
Channel.basic_publish(exchange='',routing_key = 'hello', body = 'Hello World')

print("[x] sent 'hello world'")
connection.close()

发送后,可以查看MQ中的对列状态:

 [root@localhost ~]# rabbitmqctl list_queues

  Listing queues ...

  hello    1


消费者:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
Channel = connection.channel()

# 或许你会讶异,不是已经声明了队列了,咋还来?
# 是的,我们假设之前声明的队列依然存在,但假设我们发送一个消费请求,但是你并不知道哪个程序先执行。
# 所以最好是两个程序都声明一下。
Channel.queue_declare(queue='hello')

def callback(ch, method, properties, body):
     print('[x] Received %r' %body)

Channel.basic_consume(callback, queue='hello', no_ack=True)
print('[*] Waiting for message. To exit press CTRL+C')

# 启动后进入死循环,一直等待消息。
Channel.start_consuming()

 



 

RabbitMQ 运行和管理

  1. 启动
    启动很简单,找到安装后的 RabbitMQ 所在目录下的 sbin 目录,可以看到该目录下有6个以 rabbitmq 开头的可执行文件,直接执行 rabbitmq-server 即可,下面将 RabbitMQ 的安装位置以 . 代替,启动命令就是:
./sbin/rabbitmq-server

启动正常的话会看到一些启动过程信息和最后的 completed with 7 plugins,这也说明启动的时候默认加载了7个插件。

 

正常启动

  1. 后台启动
    如果想让 RabbitMQ 以守护程序的方式在后台运行,可以在启动的时候加上 -detached 参数:
sudo rabbitmq-server -detached
  1. 查询服务器状态
    sbin 目录下有个特别重要的文件叫 rabbitmqctl ,它提供了 RabbitMQ 管理需要的几乎一站式解决方案,绝大部分的运维命令它都可以提供。
    查询 RabbitMQ 服务器的状态信息可以用参数 status :
./sbin/rabbitmqctl status

该命令将输出服务器的很多信息,比如 RabbitMQ 和 Erlang 的版本、OS 名称、内存等等

  1. 关闭 RabbitMQ 节点
    我们知道 RabbitMQ 是用 Erlang 语言写的,在Erlang 中有两个概念:节点和应用程序。节点就是 Erlang 虚拟机的每个实例,而多个 Erlang 应用程序可以运行在同一个节点之上。节点之间可以进行本地通信(不管他们是不是运行在同一台服务器之上)。比如一个运行在节点A上的应用程序可以调用节点B上应用程序的方法,就好像调用本地函数一样。如果应用程序由于某些原因奔溃,Erlang 节点会自动尝试重启应用程序。
    如果要关闭整个 RabbitMQ 节点可以用参数 stop :
./sbin/rabbitmqctl stop

它会和本地节点通信并指示其干净的关闭,也可以指定关闭不同的节点,包括远程节点,只需要传入参数 -n :

./sbin/rabbitmqctl -n rabbit@server.example.com stop 

-n node 默认 node 名称是 rabbit@server ,如果你的主机名是 server.example.com ,那么 node 名称就是 rabbit@server.example.com

  1. 关闭 RabbitMQ 应用程序
    如果只想关闭应用程序,同时保持 Erlang 节点运行则可以用 stop_app:
./sbin/rabbitmqctl stop_app

这个命令在后面要讲的集群模式中将会很有用。

  1. 启动 RabbitMQ 应用程序
./sbin/rabbitmqctl start_app
  1. 重置 RabbitMQ 节点
./sbin/rabbitmqctl reset

该命令将清除所有的队列。

  1. 查看已声明的队列
./sbin/rabbitmqctl list_queues
  1. 查看交换器
./sbin/rabbitmqctl list_exchanges

该命令还可以附加参数,比如列出交换器的名称、类型、是否持久化、是否自动删除:

./sbin/rabbitmqctl list_exchanges name type durable auto_delete
  1. 查看绑定
./sbin/rabbitmqctl list_bindings

 

 

 

RabbitMQ 集群

RabbitMQ 最优秀的功能之一就是内建集群,这个功能设计的目的是允许消费者和生产者在节点崩溃的情况下继续运行,以及通过添加更多的节点来线性扩展消息通信吞吐量。RabbitMQ 内部利用 Erlang 提供的分布式通信框架 OTP 来满足上述需求,使客户端在失去一个 RabbitMQ 节点连接的情况下,还是能够重新连接到集群中的任何其他节点继续生产、消费消息。

RabbitMQ 集群中的一些概念

RabbitMQ 会始终记录以下四种类型的内部元数据:

  1. 队列元数据
    包括队列名称和它们的属性,比如是否可持久化,是否自动删除
  2. 交换器元数据
    交换器名称、类型、属性
  3. 绑定元数据
    内部是一张表格记录如何将消息路由到队列
  4. vhost 元数据
    为 vhost 内部的队列、交换器、绑定提供命名空间和安全属性

在单一节点中,RabbitMQ 会将所有这些信息存储在内存中,同时将标记为可持久化的队列、交换器、绑定存储到硬盘上。存到硬盘上可以确保队列和交换器在节点重启后能够重建。而在集群模式下同样也提供两种选择:存到硬盘上(独立节点的默认设置),存在内存中。

如果在集群中创建队列,集群只会在单个节点而不是所有节点上创建完整的队列信息(元数据、状态、内容)。结果是只有队列的所有者节点知道有关队列的所有信息,因此当集群节点崩溃时,该节点的队列和绑定就消失了,并且任何匹配该队列的绑定的新消息也丢失了。还好RabbitMQ 2.6.0之后提供了镜像队列以避免集群节点故障导致的队列内容不可用。

RabbitMQ 集群中可以共享 user、vhost、exchange等,所有的数据和状态都是必须在所有节点上复制的,例外就是上面所说的消息队列。RabbitMQ 节点可以动态的加入到集群中。

当在集群中声明队列、交换器、绑定的时候,这些操作会直到所有集群节点都成功提交元数据变更后才返回。集群中有内存节点和磁盘节点两种类型,内存节点虽然不写入磁盘,但是它的执行比磁盘节点要好。内存节点可以提供出色的性能,磁盘节点能保障配置信息在节点重启后仍然可用,那集群中如何平衡这两者呢?

RabbitMQ 只要求集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入火离开集群时,它们必须要将该变更通知到至少一个磁盘节点。如果只有一个磁盘节点,刚好又是该节点崩溃了,那么集群可以继续路由消息,但不能创建队列、创建交换器、创建绑定、添加用户、更改权限、添加或删除集群节点。换句话说集群中的唯一磁盘节点崩溃的话,集群仍然可以运行,但知道该节点恢复,否则无法更改任何东西。

RabbitMQ 集群配置和启动

如果是在一台机器上同时启动多个 RabbitMQ 节点来组建集群的话,只用上面介绍的方式启动第二、第三个节点将会因为节点名称和端口冲突导致启动失败。所以在每次调用 rabbitmq-server 命令前,设置环境变量 RABBITMQ_NODENAME 和 RABBITMQ_NODE_PORT 来明确指定唯一的节点名称和端口。下面的例子端口号从5672开始,每个新启动的节点都加1,节点也分别命名为test_rabbit_1、test_rabbit_2、test_rabbit_3。

启动第1个节点:

RABBITMQ_NODENAME=test_rabbit_1 RABBITMQ_NODE_PORT=5672 ./sbin/rabbitmq-server -detached

启动第2个节点:

RABBITMQ_NODENAME=test_rabbit_2 RABBITMQ_NODE_PORT=5673 ./sbin/rabbitmq-server -detached

启动第2个节点前建议将 RabbitMQ 默认激活的插件关掉,否则会存在使用了某个插件的端口号冲突,导致节点启动不成功。

现在第2个节点和第1个节点都是独立节点,它们并不知道其他节点的存在。集群中除第一个节点外后加入的节点需要获取集群中的元数据,所以要先停止 Erlang 节点上运行的 RabbitMQ 应用程序,并重置该节点元数据,再加入并且获取集群的元数据,最后重新启动 RabbitMQ 应用程序。

停止第2个节点的应用程序:

./sbin/rabbitmqctl -n test_rabbit_2 stop_app

重置第2个节点元数据:

./sbin/rabbitmqctl -n test_rabbit_2 reset

第2节点加入第1个节点组成的集群:

./sbin/rabbitmqctl -n test_rabbit_2 join_cluster test_rabbit_1@localhost

启动第2个节点的应用程序

./sbin/rabbitmqctl -n test_rabbit_2 start_app

第3个节点的配置过程和第2个节点类似:

RABBITMQ_NODENAME=test_rabbit_3 RABBITMQ_NODE_PORT=5674 ./sbin/rabbitmq-server -detached

./sbin/rabbitmqctl -n test_rabbit_3 stop_app

./sbin/rabbitmqctl -n test_rabbit_3 reset

./sbin/rabbitmqctl -n test_rabbit_3 join_cluster test_rabbit_1@localhost

./sbin/rabbitmqctl -n test_rabbit_3 start_app

RabbitMQ 集群运维

停止某个指定的节点,比如停止第2个节点:

RABBITMQ_NODENAME=test_rabbit_2 ./sbin/rabbitmqctl stop

查看节点3的集群状态:

./sbin/rabbitmqctl -n test_rabbit_3 cluster_status

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值