RabbitMQ 是使用 Erlang 语言开发的消息中间件, 其遵循了高级消息队列协议(Advanced Message Queuing Protocol, AMQP)。

与 Kafka 等消息队列相比,RabbitMQ 最大的优势在于其较高的可靠性:

  • 提供确认(ACK)和重传机制保证消息完成消费, 消费者异常不会导致消息丢失

  • 提供消息持久化机制, broker 崩溃不会导致消息丢失

  • 集群模式下工作, 保证高可用

因为具有较高可靠性和一致性, RabbitMQ 可以胜任订单处理、秒杀等一致性要求较高的业务场景。

RabbitMQ 概念与机制

RabbitMQ 中的概念模型:

  • Broker: 消息中间件实例, 可能是单个节点也可能是运行在多节点集群上的逻辑实体
  • 消息(Message): 消息由消息头和消息体两部分组成。消息头中包括routing-key、priority等标准消息头以及其它自定义消息头,用于定义RabbitMQ对消息行为。消息体是字节流,包含消息内容。
  • 连接(Connection): 客户端与 Broker 之间的 TCP连接
  • 信道(Channel): Channel 是建立在 TCP 连接上的逻辑(虚拟)连接。多个 Channel 复用同一个 TCP 连接, 以避免建立 TCP 连接的巨大开销。 RabbitMQ 官方要求每个线程使用独立的 Channel, 禁止多个线程共用 Channel。
  • 生产者(Publisher): 发送消息的客户端线程
  • 消费者(Consumer): 处理消息的客户端线程
  • 交换机(Exchange): 交换机负责将消息投递到相应的队列
  • 队列(Queue): 接收并保存交换机投递的消息,直至被消费者成功消费。逻辑结构遵循先进先出FIFO。
  • 绑定(Binding): 将队列(Queue)注册到交换机(Exchange)的路由表
  • 虚拟主机(Vhost): 每个Broker下可建立多个vhost, 每个 vhost 可建立独立的 Exchange、Queue、绑定及权限系统。同一个 Broker 下的 vhost 共享 Connection、Channel 和 用户系统,就是说可以使用同一个用户身份使用同一个 Channel 访问不同 vhost。

交换机(Exchange)

生产者发送的消息会首先送到交换机(Exchange), 交换机根据自身类型和消息的 routing-key 等信息将消息投递到绑定的消息队列中。

RabbitMQ中的四种标准交换机:

  • direct: 如果消息的 routing-key 与队列的 binding-key 完全相同,direct类型的交换机则会将消息投递到该队列中。

    • 多个队列可以使用相同的 binding-key 绑定到同一个 direct 交换机,direct 交换机会把消息投递到所有 binding-key 与消息 routing-key 相同的队列
  • topic: 允许队列的 binding-key 中包含通配符*#, topic 交换机会将消息投递到 binding-key 与 routing-key 匹配的队列中。
    • 通配符按照关键字进行匹配,如news.cn.a中的关键字是newscna,即关键字按照.分割
    • #通配符匹配0个或多个关键字, news.#.a可以匹配news.a, news.cn.anews.asia.cn.a
    • *通配符匹配一个关键字, news.*.a匹配news.cn.a不匹配news.anews.asia.cn.a
  • fanout: fanout 交换机不进行任何匹配, 将消息投递到所有绑定的队列
  • header: header 交换机根据消息头进行投递,现在已较少使用

我们可以使用 RabbitMQ 的插件机制使用第三方交换机或自行开发交换机。如实现延时投递的delayed-message-exchange

消息头中的delivery-mode可以设置为 persistent(持久化) 或者 transient(易失)。 Exchange 和 Queue 在处理持久化的消息时都会先将消息写入磁盘中再进行下一步处理, 即使 RabbitMQ 崩溃也不会丢失。

消费者客户端通常使用的channel.basicConsume使用推(push)模式投递消息, 即当有新消息时 Broker 通过 channel 主动向客户端发送消息。客户端也可以使用channel.basicGet从 Broker 拉取消息。

ACK机制

RabbitMQ 提供了确认送达(acknowledge)机制保证消息被正确处理不会丢失。

确认送达的回执有三种:

  • ACK: 消息已被成功处理
  • NACK: 消息处理异常, 需要重新投递
  • REJECT: 消息非法, 丢弃消息

RabbitMQ 的 Queue 可以设置 no_ack=true, 则消息被投递后即删除不等待回执。

channel.basicConsume 可以指定auto_ack模式,若auto_ack=true当客户端收到完整消息后即会自动发出ACK回执,否则必须显式的发出回执。

Java 代码示例

首先安装并启动RabbitMQ实例, Mac用户可以使用 Homebrew 进行安装:

brew install rabbitmq

启动服务:

brew services start rabbitmq

或者使用官方docker镜像:

docker run -d --hostname my-rabbit --name some-rabbit rabbitmq:3-management

RabbitMQ官网提供了Ubuntu、RPM以及Windows等多种平台安装方式。

RabbitMQ默认TCP端口为5672, Web控制台默认端口15672。

在Maven中添加依赖:

<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.5.1</version>
</dependency>

编写生产者:

package rabbit;

import java.io.IOException;
import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; /**
* @author finley
*/
public class RabbitProducer { public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("guest");
factory.setPassword("guest");
factory.setHost("localhost");
try (Connection conn = factory.newConnection();
Channel channel = conn.createChannel()) {
String exchangeName = "test-exchange";
channel.exchangeDeclare(exchangeName, "direct", true); String routingKey = "hello"; byte[] msg = "hello world".getBytes();
AMQP.BasicProperties.Builder propsBuilder = new AMQP.BasicProperties.Builder();
propsBuilder.deliveryMode(2); // persistent
propsBuilder.priority(0); // normal
propsBuilder.contentType("text/plain");
channel.basicPublish(exchangeName, routingKey, propsBuilder.build(), msg);
}
}
}

编写消费者:

package rabbit;

import java.io.IOException;
import java.util.concurrent.TimeoutException; import com.rabbitmq.client.*; /**
* @author finley
*/
public class RabbitConsumer { public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("guest");
factory.setPassword("guest");
factory.setHost("localhost");
try (Connection conn = factory.newConnection();
Channel channel = conn.createChannel()) {
String exchangeName = "test-exchange";
channel.exchangeDeclare(exchangeName, "direct", true); String queueName = channel.queueDeclare().getQueue();
String bindingKey = "hello";
channel.queueBind(queueName, exchangeName, bindingKey); while(true) {
channel.basicConsume(queueName, false, "", new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String routingKey = envelope.getRoutingKey();
String contentType = properties.getContentType();
String bodyStr = new String(body, "UTF-8");
System.out.println("routingKey: " + routingKey + ", contentType: " + contentType + ", body: " + bodyStr);
long deliveryTag = envelope.getDeliveryTag();
channel.basicAck(deliveryTag, false);
}
});
}
}
} }

RabbitMQ 的消息为字节, 可以将 Java 对象序列化后作为消息体发送。

RabbitMQ 消息中间件的更多相关文章

  1. spring boot / cloud (九) 使用rabbitmq消息中间件

    spring boot / cloud (九) 使用rabbitmq消息中间件 前言 rabbitmq介绍: RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.它可以用于大型软件系统 ...

  2. CentOS6.8搭建rabbitmq消息中间件

    参考资料:http://blog.csdn.net/yunfeng482/article/details/72853983 一.rabbitmq简介 MQ全称为Message Queue, 消息队列( ...

  3. python中使用rabbitmq消息中间件

    上周一直在研究zeromq,并且也实现了了zeromq在python和ruby之间的通信,但是如果是一个大型的企业级应用,对消息中间件的要求比较高,比如消息的持久化机制以及系统崩溃恢复等等需求,这个时 ...

  4. RabbitMQ消息中间件的用法

    1.什么是RabbitMQ RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消 ...

  5. Linux(Centos平台)RabbitMQ消息中间件服务器搭建

    本篇结合接口测试平台部署来讲,不了解的请先查看我的另一篇文档,HttpRunnerManager接口测试平台部署在服务器上(Centos + python3.6 + Mysql5.7 + uwsgi ...

  6. RabbitMQ消息中间件极速入门与实战

    1:初识RabbitMQ RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AM ...

  7. rabbitmq消息中间件读后感

    1:RabbitMQ是一个开源的消息代理和队列服务器,可以通过基本协议在完全不同的应用之间共享数据,使用Erlang语言开发的,是基于AMQP(高级消息队列协议)协议,Erlang主要用于交换机的开发 ...

  8. Laravel框架安装RabbitMQ消息中间件步骤

    Laravel5.6 整合 RabbitMQ 消息队列 简介: Laravel 队列为不同的后台队列服务提供了统一的 API,例如 Beanstalk,Amazon SQS,Redis,甚至其他基于关 ...

  9. springcloud 连接docker中运行的RabbitMQ消息中间件。

    参考:https://blog.51cto.com/zero01/2173288 主要是记录几个坑: 第一个坑:开始订单服务中配置文件是: #配置rabbitmq 2019.5.17 added by ...

随机推荐

  1. MySQL数据库(一)

    一:MySQL的简单介绍 MySQL属于关系型数据库,数据是以行和列的形式去存储(表),表中的每一行叫一条记录,表中的每一列叫一个字段,表和表之间的逻辑关联叫关系. 二:MySQL的基本操作 (一)M ...

  2. Python开发——8.模块

    一.模块 1.模块 (1)定义:一个.py文件就是一个模块 (2)原因:为了防止程序代码越来越长,对函数进行分组放到不同的文件夹里. (3)优点:提高代码的可维护性:模块编写完毕可以被别人引用,也可以 ...

  3. selenium自动化打开浏览器不受信任解决办法

    之前在用selenium(火狐浏览器)打开一个https网站时,总是弹出不受信任,修改配置后,每次加载的浏览器都是还原了配置,无法加载出页面,这里给出解决办法:让浏览器去加载我们修改后的配置,具体如下 ...

  4. display:inline-block; 在css中是什么意思?

    inline-block主要的用处是用来处理行内非替换元素的高宽问题的!行内非替换元素,比如span.a等标签,正常情况下士不能设置宽高的,加上该属性之后,就可以触发让这类标签表现得如块级元素一样,可 ...

  5. HC-05蓝牙模块配置与使用

    蓝牙模块BT-HC05模块是一款高性能的蓝牙串口模块. 1.可用于各种带蓝牙功能的电脑.蓝牙主机.手机.PDA.PSP等智能终端配对. 2.宽波特率范围4800~1382400,并且模块兼容单片机系统 ...

  6. java基础0615

    1. 1)2)   1)输出:Base  2)编译成功,但没有输出. 2. 编译成功,但没有输出. 3. 只有12行的话,不会新建文件.需要create~~ 4. public static void ...

  7. 架构(二)Maven安装以及Nexus配置

    一 Maven安装配置 1.1 下载 http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.5.4/binaries/apache-ma ...

  8. Kali学习笔记18:OpenVAS使用

    上一篇讲了什么是OpenVAS以及如何安装: https://www.cnblogs.com/xuyiqing/p/9690373.html 接下来就是使用: 我先打开一台Metasploitable ...

  9. [Swift-2019力扣杯春季初赛]2. 校园自行车分配

    在由 2D 网格表示的校园里有 n 位工人(worker)和 m 辆自行车(bike),n <= m.所有工人和自行车的位置都用网格上的 2D 坐标表示. 我们需要为每位工人分配一辆自行车.在所 ...

  10. Mysql实现树形递归查询

    最近在做项目迁移,Oracle版本的迁到Mysql版本,遇到有些oracle的函数,mysql并没有,所以就只好想自定义函数或者找到替换函数的方法进行改造. Oracle递归查询 oracle实现递归 ...