【RabbitMQ】工作流程详解

生产者发送消息的流程

1. 生产者连接 RabbitMQ ,建立 TCP 连接 ( Connection) ,开启信道/通道( Channel
2. 生产者声明一个 Exchange (交换器),并设置相关属性,比如交换器类型、是否持久化等
3. 生产者声明一个队列井设置相关属性,比如是否排他、是否持久化、是否自动删除等
4. 生产者通过 bindingKey (绑定 Key )将交换器和队列绑定( binding )起来
5. 生产者发送消息至 RabbitMQ Broker ,其中包含 routingKey (路由键)、交换器等信息
6. 相应的交换器根据接收到的 routingKey 查找相匹配的队列。
7. 如果找到,则将从生产者发送过来的消息存入相应的队列中。 如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者
8. 关闭信道。
9. 关闭连接。

消费者获取消息的过程

1. 消费者连接到RabbitMQ Broker,建立一个连接(Connection ),开启一个信道(Channel)

2. 消费者向 RabbitMQ Broker 请求消费相应队列中的消息,可能会设置相应的回调函数,以及 做一些准备工作
3. 等待 RabbitMQ Broker 回应并投递相应队列中的消息, 消费者接收消息。
4. 消费者确认 ( ack) 接收到的消息。
5. RabbitMQ 从队列中删除相应己经被确认的消息。
6. 关闭信道。
7. 关闭连接。

Connection和Channel 

在上面提到的流程里面频繁频繁在第一步出现Connection和Channel,所以这里讲一下这两者有啥用,有啥关系

关系

生产者和消费者,需要Connection与RabbitMQ Broker建立起TCP连接,一旦连接建立起来之后,客户端会随之创建一个AMQP通道,也就是Channel,每个通道都会被标记上一个唯一的ID,通道是建立在Connection之上的虚拟连接,所以说,RabbitMQ处理的每一条AMQP指令都是通过通道Channel完成的

疑问

上面关系中提到,会建立TCP连接,那为什么后面不用TCP而是用通道进行连接呢?

解答

因为RabbitMQ采用了NIO的做法,复用TCP连接,从而减少性能的开销,而且便于管理,

1、当每个通道的流量不是特别大的时候,使用复用技术,复用单一的Connection可以在产生性能瓶颈的情况下节省TCP连接资源

2、如果当通道的流量很大的时候,一个Connection就会产生性能瓶颈,流量就会被限制,这个时候就需要建立多个Connection,分摊通道,具体怎么分摊,就看业务需求了

代码体验

万物皆可Hello World,我们举一个Hello World的代码案例

1、消息生产者

public class HelloWorldProducer {
    private static String QUEUE_NAME = "hello";

    public static void main(String[] args) {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        factory.setVirtualHost("/");
        factory.setUsername("guest");
        factory.setPassword("guest");
        factory.setPort(5672);
        try (Connection conn = factory.newConnection();
            Channel channel = conn.createChannel()) {
            channel.queueDeclare(QUEUE_NAME, false, false, true, null);
            String message = "Hello World!";
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            System.out.println(" Send '" + message + "'");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2、消息消费者

public class HelloWorldConsumer {
    private final static String QUEUE_NAME = "hello";

    public static void main(String[] argv) throws Exception {
        // 连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        // 设置服务器主机名或IP地址
        factory.setHost("127.0.0.1");
        // 设置Erlang的虚拟主机名称
        factory.setVirtualHost("/");
        // 设置用户名
        factory.setUsername("guest");
        // 设置密码
        factory.setPassword("guest");
        // 设置客户端与服务器的通信端口,默认值为5672
        factory.setPort(5672);
        // 获取连接
        Connection connection = factory.newConnection();

        // 从连接获取通道
        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, true, null);
        // 消息的推送回调函数
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(message);
        };
        /*使用服务器生成的consumerTag启动本地,非排他的使用者。
        启动一个 仅提供了basic.deliver和basic.cancel AMQP方法(对大多数情形够用了)
        第一个参数:队列名称 autoAck – true 只要服务器发送了消息就表示消息已经被消费者确认;
        false服务 端等待客户端显式地发送确认消息 deliverCallback – 服务端推送过来的消息回调函数
        cancelCallback – 客户端忽略该消息的回调方法 Returns: 服务端生成的consumerTag */
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
    }
}

3、启动生产者,然后再启动消费者,就会发现,消费者的控制台会输出生产者发送的数据

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值