RabbitMQ消息队列(一)

277 阅读16分钟

一、RabbitMQ 基础知识

1、端口

服务的默认启动端口是 5672,其中可视化界面使用端口是 15672。对于 15672 可视化端口,可适用 nginx80 端口代理流量。

2、用户

默认用户是 guest,guest 用户不允许远程登陆,通过创建新用户,实现控制台的远程访问。

(一)应用需求

  1. 模块间耦合度过高,导致一个模块宕机后,系统对外服务中断
  2. 同步通信时间成本过高

二、RabbitMQ 使用流程

1、生产者建立 Connection

生产者(客户端)与 RabbitMQ 虚拟主机(Virtual Host)建立连接

2、生产者建立 Channel

生产者(客户端)与 RabbitMQ 交换机(exchange)建立管道

3、在虚拟主机内部指定路由信息
4、消费者建立 Connection

消费者(客户端)与 RabbitMQ 虚拟主机(Virtual Host)建立连接

5、消费者建立 Channel

消费者(客户端)与 RabbitMQ 队列(Queue)建立管道

三、RabbitMQ 通信方式

生产者的 channel 连接 exchange;消费者的 channel 连接 queue

(一)Hello world

一个生产者,一个默认交换机,一个队列,一个消费者。

1、生产者

1. 创建connection
2. 创建channel
3. 发布消息到exchange,同时指定路由规则
    exchange为空串时,表示使用默认值
    routingKey为路由规则
    props指传递消息所携带的属性值
​
4. 释放资源

2、消费者

1. 创建connection
2. 创建channel
3. 声明所使用的queue
    queue为队列名称
    durable为当前队列是否需要持久化
    pexclusive为当前队列是否排外(如果是true,则当前队列在连接关闭时自动删除,并且只允许一个消费者)
    autoDelete表示如果当前队列没有消费者,则自动删除
    arguments表示队列其它附加信息
4. 开启监听queue
    queue为队列名称
    autoAck表示是否自动确认
    consumer为消费回调对象
5. 释放资源

(二)Work queues

一个生产者,一个默认交换机,两个队列,一个消费者。

消费者当采用自动确认时,消费者平均分配消息。

如果希望消费者差异化分配消息,只需在消费者端添加 Qos 能力以及更改为手动 Ack 即可。

(三)Publish/Subscribe

如果不指定路由规则,exchange 的消息会复制到不同的队列中,重复消费。

(四)Routing

(五)Topics

(六)Publisher confirms

四、消息的可靠性

(一)理论模块

1、RabbitMQ 服务宕机

RabbitMQ 队列有持久化机制,在服务重启后未消费的消息会自动加入队列中,消息不会发生丢失。当消息到达 exchange 却没有到达 queue 时,服务器发生意外宕机,RabbitMQ 通过 return 机制保证消息可靠传输。

2、消费者(客户端)宕机

消费者有手动 ACK 机制,只有客户端主动向 RabbitMQ 发送确认信息,RabbitMQ 服务器才将对应的消息移除,因此手动 ACK 机制保证了消费者端的可靠性。

3、网络问题

生产者发送消息时,由于网络问题,导致消息没有发送到 RabbitMQ 服务器:RabbitMQ 提供了事务和 confirm 确认机制保证消息可靠传输

事务可以保证消息 100%传递,但效率太低;confirm 确认机制比事务效率要高,分为普通 confirm、批量 confirm、异步 confirm。

(二)代码实现

1、编辑主配置文件

在配置文件中添加消息 confirm 和 return 配置

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

    #启用confirm和return机制
    publisher-confirm-type: simple
    publisher-returns: true
2、创建 confirm 和 return 配置类
@Component
public class PublisherConfirmAndReturnConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {
​
    @Autowired
    private RabbitTemplate rabbitTemplate;
​
    /**
     * 类初始化的时候调用此方法
     */
    @PostConstruct
    public void initMethod(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }
    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        if(b){
            System.out.println("消息已经送达exchange");
        }else{
            System.out.println("消息未送达exchange");
        }
    }
​
    @Override
    public void returnedMessage(Message message, int i, String s, String s1, String s2) {
        System.out.println("消息未到达queue");
    }
}

生产者和消费者部分代码保持不变,启动程序即可。

五、消息的重复消费

幂等性业务操作不用考虑重复消费的问题,只有在非幂等性业务操作的场景下才考虑重复消费带来的问题,重复消费的原因是消费者因为各种原因没有给 RabbitMQ 确认 ACK。

六、命令行管理

(一)用户管理

# {username} 表示用户名; {password}表示用户密码
# 该命令将创建一个 non-administrative 用户
rabbitmqctl add_user {username} {password}
​
# 表示删除一个用户,该命令将指示RabbitMQ broker去删除指定的用户
rabbitmqctl delete_user {username}
​
# 表示修改指定的用户的密码
rabbitmqctl change_password {username} {newpassword}
​
​
# 表示清除指定用户的密码
# 执行此操作后的用户,将不能用密码登录,但是可能通过已经配置的SASL EXTERNAL的方式登录。
rabbitmqctl clear_password {username}
​
# 表示指引RabbitMQ broker认证该用户和密码
rabbitmqctl authenticate_user {username} {password}
​
# 表示设置用户的角色,{tag}可以是零个,一个,或者是多个。并且已经存在的tag也将会被移除。
# rabbitmqctl set_user_tags tonyg administrator 该命令表示指示RabbitMQ broker确保用户tonyg为一个管理员角色。
# 上述命令在用户通过AMQP方式登录时,不会有任何影响;但是如果通过其他方式,例如管理插件方式登录时,就可以去管理用户、vhost 和权限。
rabbitmqctl set_user_tags {username} {tag ...}
​
# 表示列出所有用户名信息
rabbitmqctl list_users

(二)虚拟主机管理

# {vhost} 表示待创建的虚拟主机项的名称
rabbitmqctl add_vhost {vhost}
​
# 表示删除一个vhost。删除一个vhost将会删除该vhost的所有exchange、queue、binding、用户权限、参数和策略。
rabbitmqctl delete_vhost {vhost}
​
​
# 表示列出所有的vhost。其中 {vhostinfoitem} 表示要展示的vhost的字段信息,展示的结果将按照 {vhostinfoitem} 指定的字段顺序展示。这些字段包括: name(名称) 和 tracing (是否为此vhost启动跟踪)。
# 如果没有指定具体的字段项,那么将展示vhost的名称。
rabbitmqctl list_vhosts {vhostinfoitem ...}
​
​
# 表示设置用户权限。 {vhost} 表示待授权用户访问的vhost名称,默认为 "/"; {user} 表示待授权反问特定vhost的用户名称; {conf}表示待授权用户的配置权限,是一个匹配资源名称的正则表达式; {write} 表示待授权用户的写权限,是一个匹配资源名称的正则表达式; {read}表示待授权用户的读权限,是一个资源名称的正则表达式。
# rabbitmqctl set_permissions -p myvhost tonyg "^tonyg-.*" ".*" ".*"
# 例如上面例子,表示授权给用户 "tonyg" 在vhost为 `myvhost` 下有资源名称以 "tonyg-" 开头的 配置权限;所有资源的写权限和读权限。
rabbitmqctl set_permissions [-p vhost] {user} {conf} {write} {read}
​
# 表示设置用户拒绝访问指定指定的vhost,vhost默认值为 "/"
rabbitmqctl clear_permissions [-p vhost] {username}
​
# 表示列出具有权限访问指定vhost的所有用户、对vhost中的资源具有的操作权限。默认vhost为 "/"
# 注意,空字符串表示没有任何权限。
rabbitmqctl list_permissions [-p vhost]
​
# 表示列出指定用户的权限vhost,和在该vhost上的资源可操作权限。
rabbitmqctl list_user_permissions {username}

(三)队列管理

rabbitmqctl list_queues [-p vhost] [[--offline] | [--online] | [--local]] [queueinfoitem ...]
# 返回队列的详细信息。如果 "-p" 标志不存在,那么将返回默认虚拟主机的队列详细信息。"-p" 可以用来覆盖默认vhost。可以使用一下互斥选项之一,通过其状态或者位置过滤显示的队列。
# [--offline] 表示仅仅列出当前不可用的持久队列(更具体地说,他们的主节点不是)
# [--online] 表示列出当前可用的队列(他们的主节点是)
# [--local] 表示仅仅列出那些主程序在当前节点上的队列
# queueinfoitem参数用于指示要包括在结果中的哪些队列信息项。结果中的列顺序将与参数的顺序相匹配。queueinfoitem可以从以下列表中获取任何值:
# name 表示队列的名称
# durable 表示服务器重启之后,队列是否存活
# auto_delete 表示不再使用的队列是否自动被删除
# arguments 表示队列的参数
# policy 表示应用在队列中的策略名称
# pid 表示和队列相关联的Erlang进程的ID
# owner_pid 表示作为队列的排他所有者的连接的Erlang进程的ID,如果队列是非排他,则为空
# exclusive 表示队列是否是排他的,有 owner_pid 返回 True,否则返回 False
# exclusive_consumer_pid 表示排他消费者订阅该队列的频道的Erlang进程的ID,如果没有独家消费者,则为空
# exclusive_consumer_tag 表示订阅该队列的排他消费者的消费tag。如果没有排他消费者,则为空
# messages_ready 表示准备被发送到客户端的消息数量
# messages_unacknowledged 表示已经被发送到客户端但是还没有被确认的消息数量
# messages 表示准备发送和没有被确认的消息数量总和(队列深度)
# messages_ready_ram 表示驻留在 ram 里的 messages_ready 的消息数量
# messages_unacknowledged_ram 表示驻留在 ram 里的 messages_unacknowledged 的消息数量
# messages_ram 表示驻留在 ram 里的消息总数
# messages_persistent 表示队列中持久消息的总数(对于临时队列,总是为0)
# message_bytes 表示在队列中所有消息body的大小,这并不包括消息属性(包括header)或者任何开销
# message_bytes_ready 表示类似于 messge_bytes 但仅仅计算那些将发送到客户端的消息
# message_bytes_unacknowledged 表示类似于 message_bytes 但仅仅计算那些已经发送到客户还没有确认的消息
# message_bytes_ram 表示类似于 message_bytes 但仅仅计算那些驻留在ram中的消息
# message_bytes_persistent 表示类似于 message_bytes 但仅仅计算那些持久消息
# head_message_timestamp 表示队列中第一个消息的时间戳属性(如果存在)。只有处在 paged-in 状态的消息才存在时间戳。
# disk_reads 表示该队列自start起,从磁盘读取消息的次数总和
# disk_writes 表示该队列自start起,被写入磁盘消息的次数总和
# consumers 表示consumer的数量
# consumer_utilisation 表示队列能够立即将消息传递给消费者的时间分数(0.0 ~ 1.0之间),如果消费者受到网络拥塞或者预取计数的限制,该值可能小于1.0
# memory 表示和该队列相关联的Erlang进程消耗的内存字节数,包括stack/heap/内部数据结构
# slave_pids 表示该队列目前的slave的ID号(如果该队列被镜像的话)
# synchronised_slave_pids 表示如果队列被镜像,给出与主队列同步的当前slave的ID号,即可以从主队列接管而不丢失消息的slave的ID
# state 表示队列的状态,一般是 "running"; 如果队列正在同步,也可能是 "{syncing, MsgCount}"; 如果队列所处的节点当前down了,队列显示的状态为 "down"
# 如果没有指定queueinfoitem,那么将显示队列的名称(name)和深度(messages)
​
​
rabbitmqctl list_exchanges [-p vhost] [exchangeinfoitem ...]
# 返回交换器的详细信息。如果 "-p" 标志不存在,那么将返回默认虚拟主机的交换器详细信息。"-p" 可以用来覆盖默认vhost。
# exchangeinfoitem参数用于指示要包括在结果中的哪些交换器信息项。结果中的列顺序将与参数的顺序相匹配。exchangeinfoitem可以从以下列表中获取任何值:
# name 表示交换器的名称
# type 表示交换器类型(例如: direct/topic/fanout/headers)
# durable 表示服务器重启之后,交换器是否存活
# auto_delete 表示交换器不再使用时,是否被自动删除
# internal 表示交换器是否是内部的,例如不能被客户端直接发布
# arguments 表示交换器的参数
# policy 表示引用在该交换器上的策略名称
# 如果没有指定任何 exchangeinfoitem,那么该命令将显示交换器的名称(name)和类型(type
​
​
rabbitmqctl list_bindings [-p vhost] [bindinginfoitem ...]
# 返回绑定的详细信息。如果 "-p" 标志不存在,那么将返回默认虚拟主机的绑定详细信息。"-p" 可以用来覆盖默认vhost。
# bindinginfoitem参数用于指示要包括在结果中的哪些绑定信息项。结果中的列顺序将与参数的顺序相匹配。bindinginfoitem可以从以下列表中获取任何值:
# source_name 表示绑定附加到的消息源的名称
# source_kind 表示绑定附加到的消息源的类型,目前通常交换器
# destination_name 表示附加绑定到的消息目的地的名称
# destination_kind 表示附加绑定到的消息目的地的类型
# routing_key 表示绑定的routing key
# arguments 表示绑定的参数
# 如果没有指定任何的 bindinginfoitem ,那么将展示上述所有的参数
# rabbitmqctl list_bindings -p /myvhost exchange_name queue_name
# 上述命令,表示展示在 /myvhost 虚拟主机中的绑定的exchange名称和queue名称
​
​
rabbitmqctl list_connections [connectioninfoitem ...]
# 返回TCP/IP连接统计信息
# connectioninfoitem 参数用于指示要包括在结果中的哪些连接信息项,结果中的列顺序将与参数的顺序相匹配。connectioninfoitem可以从以下列表中获取任何值:
# pid 表示与该connection相关联的Erlang进程的id
# name 表示该连接的可读性名称
# port 表示服务端口
# host 表示通过反向DNS获取的服务器主机名,如果反向DNS失败或未启用,则为其IP地址
# peer_port 表示对等端口
# peer_host 表示通过反向DNS获取的对等主机名,如果反向DNS失败或未启用,则为其IP地址
# ssl 表示该连接是否使用SSL保护的bool值
# ssl_protocal 表示SSL协议(例如: tlsv1)
# ssl_key_exchange 表示SSL关键交换器算法(例如: rsa)
# ssl_cipher 表示SSL密码算法(例如: aes_256_cbc)
# ssl_hash 表示SSL哈希函数(例如: sha)
# peer_cert_issuer 表示对等体的SSL证书的颁发者,以RFC4514形式出现
# peer_cert_validity 表示对等体的SSL证书的有效期限
# state 表示连接状态(例如: starting/tuning/opening/running/flow/blocking/blocked/closing/closed)
# channels 表示正在使用连接的通道数量
# protocol 表示正在使用的AMQP的版本号。注意,如果一个客户端需要一个AMQP 0-9 连接,我们将其作为 AMQP 0-9-1
# auth_mechanism 表示使用SASL认证机制,如PLAN
# user 表示和该连接相关联的用户名
# vhost 表示vhost名称
# timeout 表示连接超时/协商心跳间隔,单位为秒
# frame_max 表示最大的frame大小(byte)
# channel_max 表示该连接上通道的最大数量
# client_properties 表示在连接建立期间,有客户端传送的消息属性
# recv_oct 表示接受到的八位字节
# recv_cnt 表示接受到的包
# send_oct 表示发送的八位字节
# send_cnt 表示发送的包
# send_pend 表示发送的队列大小
# connected_at 表示该连接被建立的日期和时间的时间戳格式
# 如果没有指定任何connectioninfoitem,那么将展示:user/peer_host/peer_port/流量控制和内存块状态之后的时间
​
​
rabbitmqctl list_channels [channelinfoitem ...]
# 返回所有当前的通道的信息,通道即一个执行大多数AMQP命令的逻辑容器。这包括由普通AMQP连接的一部分通道、由各种插件和其他扩展程序创建的通道。
# channelinfoitem 参数用于指示要包括在结果中的哪些连接信息项,结果中的列顺序将与参数的顺序相匹配。channelinfoitem 可以从以下列表中获取任何值:
# pid 表示与该连接相关联的Erlang程序的ID号
# connection 表示与通道所属连接相关联的Erlang进程的ID号
# name 表示通道的可读性名称
# number 表示通道的号码,在连接中唯一表示它
# user 表示和该通道相关联的用户名
# vhost 表示通道操作所在的vhost
# transactional 表示通道是否处于事务模式,返回 true,否则返回 false
# confirm 表示通道是否处于确认模式,返回 true, 否则返回 false
# consumer_count 表示通过通道检索消息的逻辑AMQP消费者数量
# messages_unacknowledged 表示通过通道发送过但还没收到反馈的消息的数量
# messages_uncommitted 表示尚未提交的事务中接受的消息数
# acks_uncommitted 表示尚未提交的事务中接受的确认数
# messages_unconfirmed 表示尚未确认已发布的消息数量。在不处于确认模式中的通道上,该值为0
# prefetch_count 表示新消费者的QoS预取限制,如果没有限制则为0
# global_prefetch_count 表示整个通道的QoS预取限制,如果没有限制则为0
# 如果没有指定任何 channelinfoitem 项,那么将展示 pid/user/consumer_count/messages_unacknowledged
​
​
rabbitmqctl list_consumers [-p vhost]
# 列出消费者,例如对一个队列的消息流的订阅者。每一行用tab字符分隔:
# 订阅的队列名称、创建和管理订阅的通道id、在通道中唯一标识订阅的消费者tag、消息传输到订阅者之后是否需要确认的bool值、代表预取限制的整数(0表示none)、订阅者的其他参数
​
​
rabbitmqctl status
# 展示broker的状态信息,例如在当前Erlang节点上正在运行的应用、RabbitMQ和Erlang版本号、OS名称、内存和文件描述统计信息
​
​
rabbitmqctl node_health_check
# RabbitMQ节点的健康检查,验证 Rabbit 应用正在运行,list_queues和list_channels返回,警告没有被设置
# rabbitmqctl node_health_check -n rabbit@stringer
# 上述例子,表示对RabbitMQ节点进行健康检查
​
​
rabbitmqctl environment
# 在每个正在运行的应用程序的应用程序环境中,显示每个变量的名称和值
​
​
rabbitmqctl report
# 生成服务器状态报告,其中包括用于支持目的的所有服务器状态信息的并置。当伴随支持请求时,输出应该被重定向到一个文件
# rabbitmqctl report > server_report.txt
​
​
rabbitmqctl eval {expr}
# 评估一个任务Erlang表达式
# rabbitmqctl eval 'node().'
# 上述例子,将返回 rabbitmqctl 已经连接的节点名称

(四)图形化界面

关闭图形化界面后,http://localhost:15672将不能访问。

# 启用图形化界面
rabbitmq-plugins enable rabbitmq_management
​
# 停用图形化界面
rabbitmq-plugins disable rabbitmq_management

(五)进程管理

# 以前台进程的方式启动RabbitMQ
rabbitmq-server
# 以后台进程的方式启动RabbitMQ
rabbitmq-server -detached
​
# 查看并杀死进程
ps -ef | grep erlang
# 查看服务是否启动
lsof -i:5672# 查看服务的详细状态
rabbitmqctl status

委托给 Supervisor 服务管理,请查看 Supervisor 使用手册

(六)常见命令

rabbitmqctl list_users
rabbitmqctl list_vhosts
rabbitmqctl list_queues
rabbitmqctl list_exchanges
rabbitmqctl list_bindings
rabbitmqctl list_connections
rabbitmqctl list_channels
rabbitmqctl list_consumers
rabbitmqctl status
1、概念
ItemComment
Exchange消息交换机,它指定消息按什么规则,路由到哪个队列
Queue消息队列,每个消息都会被投入到一个或多个队列
Binding绑定,它的作用就是把 exchange 和 queue 按照路由规则绑定起来
Routing Key路由关键字,exchange 根据这个关键字进行消息投递
Vhost虚拟主机,可以开设多个 vhost,用作不同用户的权限分离
Producer消息生产者,就是投递消息的程序
Consumer消息消费者,就是接受消息的程序
Channel消息通道,在客户端的每个连接里,可建立多个 channel,每个 channel 代表一个会话任务
2、投递过程

消息队列的使用过程大概如下:

  • 1.客户端连接到消息队列服务器,打开一个 channel
  • 2.客户端声明一个 exchange,并设置相关属性
  • 3.客户端声明一个 queue,并设置相关属性
  • 4.客户端使用 routing key,在 exchange 和 queue 之间建立好绑定关系
  • 5.客户端投递消息到 exchange
  • 6.客户端从指定的 queue 中消费信息

后续持续更新。。。。