rabbitmq讲解

这篇博客详细介绍了RabbitMQ的五种消息模型:simple简单模式、work工作模式、publish/subscribe发布订阅、routing路由模式和topic主题模式。讨论了消息确认机制的自动ACK和手动ACK,以及在工作模式中实现任务的分发和避免消息堆积的方法。此外,还提到了消息的持久化策略,确保在MQ宕机时不会丢失消息。
摘要由CSDN通过智能技术生成

五种消息模型

RabbitMQ提供了6种消息模型,但是第6种其实是RPC,并不是MQ,因此不予学习。那么也就剩下5种。

simple简单模式

work工作模式(资源的竞争)

一个生产者,多个消费者,每个消费者获取到的消息唯一

publish/subscribe发布订阅(共享资源)

一个生产者发送的消息会被多个消费者获取。

routing路由模式

发送消息到交换机并且要指定路由key ,消费者将队列绑定到交换机时需要指定路由key

topic 主题模式(路由模式的一种)

将路由键和某模式进行匹配,此时队列需要绑定在一个模式上,“#”匹配一个词或多个词,“*”只匹配一个词。

我们通过代码工程来了解RabbitMQ的工作方式:

依赖:

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

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

连接工具类

public class ConnectionUtil {
   
    public static Connection GetRabbitConnection() throws IOException, TimeoutException {
   
        ConnectionFactory factory = new ConnectionFactory();
        factory.setUsername("guest");
        factory.setPassword("guest");
        factory.setVirtualHost("/");
        factory.setHost("192.168.70.136");
        factory.setPort(5672);
        Connection conn = null;
        return factory.newConnection();
    }
}

simple简单模式

生产者发送消息

public class RabbitmqPublisherDemo {
   
    public static void main(String[] args) throws IOException, TimeoutException {
   
        publisher();
    }
    public static void publisher() throws IOException, TimeoutException {
   
        // 创建一个连接
        Connection conn = ConnectionUtil.GetRabbitConnection();
        if (conn != null) {
   
            try {
   
                // 创建通道
                Channel channel = conn.createChannel();
                for (int i = 0; i < 10; i++) {
   
                    // 声明(创建)队列,必须声明队列才能够发送消息,我们可以把消息发送到队列中。
                    // 声明一个队列是幂等的 - 只有当它不存在时才会被创建
                    channel.queueDeclare("simple-queue", false, false, false, null);
                    String content = String.format(i+" 当前时间:%s", new Date().getTime());
                    // 发送内容
                    // 参数一:交换机名称
                    // 参数二:队列名称
                    // 参数三:消息的其他属性
                    // 参数四:消息主体
                    channel.basicPublish("", "simple-queue", null, content.getBytes("UTF-8"));
                    System.out.println("已发送消息:" + content);
                }
                // 关闭连接
                channel.close();
                conn.close();
            } catch (Exception e) {
   
                e.printStackTrace();
            }
        }
    }

}

运行

管理工具中查看消息

进入队列页面,可以看到新建了一个队列:simple_queue

点击队列名称,进入详情页,可以查看消息:

在控制台查看消息并不会将消息消费,所以消息还在。

消费者获取消息

public class RabbitmqConsumerDemo {
   
    public static void main(String[] args) throws IOException, TimeoutException {
   
        consumer();
    }

    public static void consumer() throws IOException, TimeoutException {
   
        // 创建一个连接
        Connection conn = ConnectionUtil.GetRabbitConnection();
        if (conn != null) {
   
            try {
   
                // 创建通道
                final Channel channel = conn.createChannel();
                // 声明队列【
                // 参数一:队列名称
                // 参数二:是否持久化
                // 参数三:是否独占模式
                // 参数四:消费者断开连接时是否删除队列
                // 参数五:消息其他参数
                channel.queueDeclare("demo-queue", false, false, false, null);
                // 创建订阅器,并接受消息
                channel.basicConsume("demo-queue", true, "", 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 content = new String(body, "utf-8");
                        System.out.println("消息正文:" + content);
                    }
                });

            } catch (Exception e) {
   
                e.printStackTrace();
            }
        }
    }
}

运行,然后观察浏览器界面的队列,会发现消息已经没有了,同时,消费者虽然已经获取了消息,但是程序没有停止,一直在监听队列中是否有新的消息。一旦有新的消息进入队列,就会立即打印.

消息确认机制(ACK)

在刚才的示例中,消息一旦被消费者接收,队列中的消息就会被删除。那RabbitMQ怎么知道消息被接收了呢?

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

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

  • 自动ACK:消息一旦被接收,消费者自动发送ACK
  • 手动ACK:消息接收后,不会发送ACK,需要手动调用

根据消息的重要性来选择:

  • 如果消息不太重要,丢失也没有影响,那么自动ACK会比较方便
  • 如果消息非常重要,不容丢失。那么最好在消费完成后手动ACK,否则接收消息后就自动ACK,RabbitMQ就会把消息从队列中删除。如果此时消费者宕机,那么消息就丢失了。

如果要手动ACK,需要改动我们的代码:

public class RabbitmqConsumerDemo {
   
    public static void main(String[] args) throws IOException, TimeoutException {
   
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值