RabbitMQ简介
AMQP(Advanced Message Queuing Protocol)高级消息队列协议,Rabbitmq是实现AMQP协议的。由于RabbitMQ是采用Erlang编写的,因此需要先安装该语言库,以便运行代理服务器。RabbitMQ在应用程序和服务器之间扮演者路由器的角色,使用一种“发后即忘”(fire and forget)单向通信方式。 生产者到消费者的消息流整体框图
整体框图连接和信道
Every application that uses AMQP needs to establish a connection with the AMQP broker. By default, RabbitMQ (as well as any other AMQP broker up to version 1.0) works over TCP as a reliable transport protocol on port 5672, that is, the IANA-assigned port.要和消息代理Rabbit通信,首先需要连接到Rabbit,才能消费或者发布消息。在应用程序和Rabbit代理服务器之间创建一条TCP连接,一旦TCP连接打开(通过了认证),应用程序可以创建一条AMQP信道。信道是建立在“真实”的TCP连接内的虚拟连接。AMQP命令都是通过信道发送出去的(All the operations that need interactions with the broker are carried out through channels)。每条信道都会被指派一个唯一ID(AMQP库会帮你记住ID的)。不论是发布信息,订阅队列或者接收信息,这些动作都是通过信道完成。既然已经通过TCP和代理连接了,为什么还要使用信道发送AMQP命令?主要原因是对操作系统来说建立和销毁TCP会话是非常昂贵的开销。假设应用程序从队列消费消息,并根据服务需求合理调度线程。假设你只进行TCP连接,那么每个线程都需要自行连接到Rabbit。也就是说高峰期有每秒成百上千的链接,这不仅造成TCP链接的巨大浪费,而且操作系统每秒也就是只能建立这点数量的链接,因为你可能会快就碰到性能瓶颈了。如果我们为所有线程只使用一条TCP链接以满足性能方面的要求,但又能确保每一个线程的私密性,就像拥有独立链接一样的话,所以就引入了信道。线程启动后,会在现成的链接上创建一个信道,也就获得了链接到Rabbit上的私密通信路径,而不会给操作系统的TCP栈造成额外负担。你可以每秒创建很多信道而不会影响操作系统,在一条TCP链接上创建多少信道是没有限制的,如下图所示: 连接与信道虚拟主机virtual host
Virtual hosts are administrative containers; they allow to confgure many logically independent brokers hosts within one single RabbitMQ instance, to let many different independent applications share the same RabbitMQ server. Each virtual host can be confgured with its independent set of permissions, exchanges, and queues and will work
in a logically separated environment.每一个RabbitMQ服务器都能创建虚拟消息服务器,叫虚拟主机(vhost)。每一个vhost本质上是一个mini版的RabbitMQ服务器,拥有自己的队列,交换器和绑定,更重要的有自己的权限控制。vhost之于Rabbit就像虚拟机之于物理服务器一样,通过在各个实例间提供逻辑上的分离,允许你为不同应用程序安全保密地允许数据。vhost是AMQP概念的基础,你必须在连接时进行指定。使用Rabbitmqctl add_vhost / delete_vhost/list_vhosts命令。
binding 绑定
绑定决定了消息如何从交换器到特定的队列 rabbitmqRabbitMQ:虚拟主机,交换器,绑定和队列之间的关系
当你将消息投递到队列时,通过把消息发送给交换器来完成,然后根据确定的规则,RabbitMQ将会决定消息该投递到哪个队列,这些规则被称为路由键(routing key),队列通过路由键绑定到交换器。
exchage 交换器
类型有:
-
fanout
fanout交换器消息流 -
direct
direct交换器消息流 -
topic
topic交换器消息流
消息确认ACK
A message is stored in a queue until one consumer gets the message and sends the ackback to the broker.If you don't send the ack back, the consumer continues to fetch subsequent messages; however, when you disconnect the consumer, all the messages will still be in the queue. Messages are not consumed until RabbitMQ receives the corresponding ack.消费者接收到每一条信息都要进行确认。
channel transactions
With the AQMP transactions you can be sure that the message won't be lost.The transactions can reduce the application's performance, because the broker doesn't cache the messages and the tx operations are synchronous.
unroutable message
An unroutable message is a message without a destination. For example, a message sent to an exchange without any bound queue.Unroutable messages are not similar to dead letter messages; the frst are messages sent to an exchange without any suitable queue destination. The latter, on the other hand, reach a queue but are rejected because of an explicit consumer decision, expired TTL, or exceeded queue length limit. An unroutable message is redirected to an internal queue. The HandlingReturnListener class will handle such messages using handleReturn().
消息的消费
如果有一个消费者订阅了队列,则消息会立即发送给订阅的消费者,但是如果消息到达了无人订阅的队列,消息会在队列中等待,一旦有消费者订阅该队列,那么队列上的消息会发送给消费者;如果有多个消费者订阅到同一个队列,队列收到的消息将以循环(round-robin)的方式发送给消费者,每条消息只发送给一个订阅的消费者。消费者对接收到的每一条消息都要进行确认,如果忘记确认的话,Rabbit将不会给该消费者发送更多的消息,这是因为在上一条消息被确认之前,Rabbit会认为这个消费者并没有准备好接收下一条消息(这个功能可以用在处理消息非常耗时,而你的应用程序可以延迟确认该消息,直到消息处理完成,这样防止Rabbit持续不断的消息涌向你的应用而导致过载)。在收到消息后,消费者可以明确拒绝(消息有问题等情况),则队列将此消息从队列中删除。
Erlang节点
节点描述的是一个Rrlang节点运行着一个Erlang应用程序,对于RabbitMQ来说,节点指的是RabbitMQ服务器实例。
Erlang节点
RabbitMQ节点管理使用命令:
// 应用程序和及节点同时关闭
rabbitmqctl -n 节点名称 stop
RabbitMQ节点应用程序使用命令
// 仅仅开启和关闭节点应用程序
rabbitmqctl -n 节点名称 stop_app
rabbitmqctl -n 节点名称 start_app
RabbitMQ-server同时开启了节点和应用程序,因为它把RabbitMQ应用程序预先配置成了独立运行模式,为了把节点加入现有的集群当中,你需要先停止应用程序,把节点重置为原始状态,这样节点就准备好加入集群了。
Mnesia数据库
RabbitMQ中的每个队列,交换器和绑定的元数据(除了消息的内容)都是保存到Mnesia的,Mnesia是内建在Erlang的非SQL型数据库。Mnesia通过将RabbitMQ元数据首先写入一个仅限追加的日志文件,以确保其完整性,然后,它再定期将日志内容转储到真实的Mnesia数据库文件中。
.erlang.cookie文件
Erlang Cookie是保证不同节点可以相互通信的密钥,要保证集群中的不同节点相互通信必须共享相同的Erlang Cookie。
这两个文件的内容要一致,否则执行rabbitmqctl的时候报如下错误:
Error: unable to perform an operation on node 'rabbit@DESKTOP-7DN8E16'. Please see diagnostics information and suggestions below.
Most common reasons for this are:
* Target node is unreachable (e.g. due to hostname resolution, TCP connection or firewall issues)
* CLI tool fails to authenticate with the server (e.g. due to CLI tool's Erlang cookie not matching that of the server)
* Target node is not running
In addition to the diagnostics info below:
* See the CLI, clustering and networking guides on http://rabbitmq.com/documentation.html to learn more
* Consult server logs on node rabbit@DESKTOP-7DN8E16
DIAGNOSTICS
===========
attempted to contact: ['rabbit@DESKTOP-7DN8E16']
rabbit@DESKTOP-7DN8E16:
* connected to epmd (port 4369) on DESKTOP-7DN8E16
* epmd reports node 'rabbit' uses port 25672 for inter-node and CLI tool traffic
* TCP connection succeeded but Erlang distribution failed
* Authentication failed (rejected by the remote node), please check the Erlang cookie
Current node details:
* node name: 'rabbitmqcli76@DESKTOP-7DN8E16'
* effective user's home directory: C:\Users\lenovo
* Erlang cookie hash: 0rVZh7WgaAP8H8hmZPiGLA==
rabbitmqctl命令
- 用户管理
rabbitmqctl add_user 用户名 密码
rabbitmqctl delete_user 用户名
rabbitmqctl change_password 用户名 修改的密码
- 权限管理
有三个粒度控制权限分别是配置,写,读权限
rabbitmqctl set_permissions -p vhost名称 用户名称 配置权限 写权限 读权限
rabbitmqctl list_permissions -p vhost名称
rabbitmqctl clear_permissions -p vhost名称 用户名称
rabbitmqctl list_user_permissions 用户名
- 队列管理
rabbitmqctl list_queues -p vhost名称 -n 节点名称
- 交换器管理
rabbitmqctl list_exchanges -p vhost名称 -n 节点名称
- 绑定器管理
rabbitmqctl list_bindings -p vhost名称 -n 节点名称
- 插件管理
rabbitmq-plugins.bat enable 插件名称 -p vhost名称 -n 节点名称
rabbitmq-plugins.bat disable 插件名称 -p vhost名称 -n 节点名称
rabbitmq-plugins.bat list -p vhost名称 -n 节点名称
如:rabbitmq-plugins.bat disable rabbitmq_management
插件rabbitmq_management(http://127.0.0.1:15672/),web管理界面如下图所示:
rabbitmq_management插件web管理界面
set RABBITMQ_NODE_PORT=6001
set RABBITMQ_NODENAME=rabbit1
set RABBITMQ_SERVICE_NAME=rabbit1
set RABBITMQ_SERVER_START_ARGS=-rabbitmq_management listener [{port,15672}]
call rabbitmq-server -detached
set RABBITMQ_NODE_PORT=6002
set RABBITMQ_NODENAME=rabbit2
set RABBITMQ_SERVICE_NAME=rabbit2
// 注意:没有引号
set RABBITMQ_SERVER_START_ARGS=-rabbitmq_management listener [{port,15673}]
call rabbitmq-server -detached
call rabbitmqctl -n rabbit2 stop_app
// 重设节点对应的元数据(队列元数据,绑定器元数据等)
call rabbitmqctl -n rabbit2 reset
call rabbitmqctl -n rabbit2 join_cluster rabbit1@PC044
call rabbitmqctl -n rabbit2 start_app
call rabbitmqctl -n rabbit1 set_policy ha-all "^.*" "{""ha-mode"":""all""}"
集群模式:普通模式(rabbitmq默认的集群模式)和镜像模式(把需要的队列做成镜像队列,存在于多个节点,属于RabbitMQ的HA方案)。
RabbitMQ集群中节点包括内存节点、磁盘节点。内存节点就是将所有数据放在内存,磁盘节点将数据放在磁盘上。集群中的节点disc表示为磁盘模式,ram表示为内存模式。为了使队列称为镜像队列,你将会创建一个策略来匹配队列,设置策略有两个键“ha-mode和 ha-params(可选)”。ha-params根据ha-mode设置不同的值,下面表格说明这些key的选项,如下表所示:
ha-mode | ha-params | 结果 |
---|---|---|
all | queue被mirror到cluster中所有节点。cluster中新添加节点,queue也会被mirror到该节点。 | |
exactly | count | queue被mirror到指定数目的节点。 count大于cluster中节点数则queue被mirror到所有节点。若count小于cluster中节点数,在包含mirror的某节点down后不会在其他节点建新的mirror(为避免cluster中queue migrating) |
nodes | node names | queue被mirror到指定名字的节点。若任一名称在cluster中不存在并不会引发错误。若指定的任何节点在queue声明时都不在线则queue在被连接到的节点创建。 |
网友评论