消息队列MessageQueue简介及RabbitMQ五大模型总结

本文详细介绍了消息队列MQ的概念,包括AMQP与JMS的区别,重点解析了RabbitMQ的使用,如最简单的生产者消费者模型、WORK Queues、Publish/Subscribe(Fanout、Direct、Topic)等五种模型。还探讨了消息持久化的重要性和实现方法,以确保消息在异常情况下不丢失。
摘要由CSDN通过智能技术生成

消息队列MessageQueue简介及RabbitMQ五大模型总结

WHAT IS MQ

消息队列,即MQ,Message Queue。

消息队列是典型的:生产者、消费者模型。生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦

AMQP与JMS

MQ是消息通信的模型,并不是具体实现。现在实现MQ的有两种主流方式:AMQP、JMS

两者间的区别和联系:

  • JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式,这点有点类似于JSON
  • JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。
  • JMS规定了两种消息模型;而AMQP的消息模型更加丰富

常见的MQ产品有:

  • ActiveMQ:基于JMS,老牌MQ产品,集群架构模式丰富
  • RocketMQ:基于JMS,阿里巴巴产品,目前交由Apache基金会,对Kafla进行了改写,对消息的可靠传输及事务性做了优化
  • Kafka:分布式消息系统,高吞吐量,对消息的重复、丢失、错误没有严格要求,适合产生大量数据的互联网服务的数据收集业务,适合数据冗余处理
  • RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好,支持事务,传输可靠

RabbitMQ

RabbitMQ是基于AMQP的一款消息管理系统

官网: http://www.rabbitmq.com/

官方教程:http://www.rabbitmq.com/getstarted.html

下载与安装详见我的RabbitMQ安装指南

RabbitMQ的官方介绍:

RabbitMQ is a message broker: it accepts and forwards messages. You can think about it as a post office: when you put the mail that you want posting in a post box, you can be sure that Mr. or Ms. Mailperson will eventually deliver the mail to your recipient. In this analogy, RabbitMQ is a post box, a post office and a postman

翻译:

RabbitMQ是一个消息代理:它接受和转发消息。 你可以把它想象成一个邮局:当你把邮件放在邮箱里时,你可以确定邮差先生最终会把邮件发送给你的收件人。 在这个比喻中,RabbitMQ是邮政信箱,邮局和邮递员。

RabbitMQ与邮局的主要区别是它不处理纸张,而是接受,存储和转发数据消息的二进制数据块

RabbitMQ的基本原理:

这是一个基本的生产者消费者模型,在RabbitMQ中,生产者把消息发送到Server中的交换机,而消费者则直接绑定到队列,获取消息即可

在交换机模式下,RabbitMQ可以轻松实现点对点传输与动态路由

RabbitMQ的几个核心角色:

P(producer/ publisher):生产者,一个发送消息的用户应用程序。

C(consumer):消费者,消费和接收有类似的意思,消费者是一个主要用来等待接收消息的用户应用程序

Queue队列(红色区域):rabbitmq内部类似于邮箱的一个概念。虽然消息流经rabbitmq和你的应用程序,但是它们只能存储在队列中。队列只受主机的内存和磁盘限制,实质上是一个大的消息缓冲区。许多生产者可以发送消息到一个队列,许多消费者可以尝试从一个队列接收数据。

总之:

生产者将消息发送到队列,消费者从队列中获取消息,队列是存储消息的缓冲区。

以下是官网给出的几大通信模型

但是第6种其实是RPC通信,并不是MQ,因此不予学习。那么也就剩下5种。

但是其实3、4、5这三种都属于订阅模型,只不过进行路由的方式不同(路由是社么?后面说到)。

最简单的生产者消费者模型

这个是大家耳熟能详的生产者消费者模型了,这个很简单,我们只需要让生产者发送消息,消费者接收到消息就行了

首先引入RabbitMQ的Java客户端依赖

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

生产者代码:

package Simple_PC;


import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 * 生产者
 */
public class Send {
   

    private final static String QUEUE_NAME = "simple_queue";

    public static void main(String[] argv) throws Exception {
   
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //设置服务地址
        factory.setHost("192.168.31.111");
        // 通过工程获取连接
        Connection connection = factory.newConnection();
        // 从连接中创建通道,使用通道才能完成消息相关的操作
        Channel channel = connection.createChannel();

        // 声明(创建)队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 消息内容
        String message = "Hello World!!";
        // 向指定的队列中发送消息
        channel.basicPublish("", QUEUE_NAME, null, message.getBytes());

        System.out.println(" [x] Sent '" + message + "'");

        //关闭通道和连接
        channel.close();
        connection.close();
    }
}

消费者代码

package Simple_PC;

import com.rabbitmq.client.*;

import java.io.IOException;


public class Recv {
   

    private final static String QUEUE_NAME = "simple_queue";

    public static void main(String[] argv) throws Exception {
   
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        /*指定ip*/
        factory.setHost("192.168.31.111");
        // 通过工程获取连接
        Connection connection = factory.newConnection();
        // 创建通道
        Channel channel = connection.createChannel();
        // 声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        //监听消息,监听到消息时自动调用
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
   
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        /*第二个参数为ACK设置,代表收到消息自动将将消息从队列中移除*/
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {
    });

    }
}

启动消费者监听消息,再启动生产者发送消息:

关于消息确认机制ACK

通过刚才的案例可以看出,消息一旦被消费者接收,队列中的消息就会被删除。

那么问题来了:RabbitMQ怎么知道消息被接收了呢?

如果消费者领取消息后,还没执行操作就挂掉了呢?或者抛出了异常?消息消费失败,但是RabbitMQ无从得知,这样消息就丢失了!

因此,RabbitMQ有一个ACK机制。当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收。不过这种回执ACK分两种情况:

  • 自动ACK:消息一旦被接收,消费者
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值