AMQP 协议及 RabbitMQ 的 Java 用例

AMQP 协议

架构及相关概念

amqp架构

  • Producer 消息生产者,封装消息内容和消息属性
  • Connection 网络连接,一般底层为TCP连接
  • Channel 使用通道来复用网络连接,避免不断的建立连接和销毁连接,这样做系统开销比较大
  • Virtual Host 虚拟主机,拥有自己的消息队列、交换器、绑定和权限机制
  • Exchange 交换器,接收来自生产者发送的消息并按照路由表路由消息队列
  • Binding 绑定,用于消息队列交换机之间的关联;保存路由规则,相当于路由表。
  • Queue 消息队列,用于存储消息实体
  • Consumer 消费者

Exchange类型

  1. 简单模式
生产者
消息队列
消费者
  1. Work 消息模型
生产者
消息队列
消费者1
消费者2
  • 生产者客户端
try (Connection conn = ConnectionUtils.getConnection(); Channel channel = conn.createChannel()) {
    // 声明并创建一个队列;如果队列已存在,则使用这个队列
    // 第一个参数:队列名称ID
    // 第二个参数:是否持久化,false对应不持久化数据,MQ停掉数据就会丢失
    // 第三个参数:是否队列私有化,false则代表所有消费者都可以访问,true代表只有第一次拥有它的消费者才能一直使用,其他消费者不让访问
    // 第四个参数:是否自动删除,false代表连接停掉后不自动删除掉这个队列
    channel.queueDeclare("queue1", false, false, false, null);
    channel.basicPublish("", "queue1", null, "helloworld".getBytes());
}
  • 消费者客户端
Connection conn = ConnectionUtils.getConnection();
Channel channel = conn.createChannel();
//如果不写basicQos(1),则自动MQ会将所有请求平均发送给所有消费者
//basicQos, MQ不再对消费者一次发送多个请求,而是消费者处理完一个消息后(确认后),在从队列中获取一个新的
channel.basicQos(1);//处理完一个取一个
//第一个参数:队列名
//第二个参数:代表是否自动确认收到消息,false代表手动编程来确认消息,这是MQ的推荐做法
//第三个参数:DefaultConsumer的实现类
channel.basicConsume("queue1", false, new DefaultConsumer(channel) {
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println(" 消息id:" + envelope.getDeliveryTag() + " 消息内容:" + new String(body));
        //false只确认签收当前的消息,设置为true的时候则代表签收该消费者所有未签收的消息
        getChannel().basicAck(envelope.getDeliveryTag(), false);
    }
});

通过 BasicQos 方法设置prefetchCount = 1。
这样RabbitMQ就会使得每个Consumer在同一个时间点最多处理1个Message。
换句话说,在接收到该Consumer的ack前,他它不会将新的Message分发给它。
相反,它会将其分派给不是仍然忙碌的下一个Consumer。
值得注意的是:prefetchCount在手动ack的情况下才生效,自动ack不生效。

  1. Publish/subscribe 模型
生产者
转发器
消息队列1
消息队列2
消费者1
消费者2

每个队列都需要绑定到交换机上

Exchange(交换机)只负责转发消息,不具备存储消息的能力,
因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!

Exchange类型

  • Fanout:广播,将消息交给所有绑定到交换机的队列
  • Direct:定向,把消息交给符合指定routing key 的队列
  • Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列
  • Header:header模式取消routingkey,使用header中的 key/value(键值对)匹配队列。
Fanout:广播
// 消费者1
channel.queueDeclare("queue1", false, false, false, null);
channel.exchangeDeclare("exchange1", BuiltinExchangeType.FANOUT);
//queueBind用于将队列与交换机绑定
//参数1:队列名 参数2:交互机名  参数三:路由key(暂时用不到)
channel.queueBind("queue1", "exchange1", "");
channel.basicQos(1);
channel.basicConsume("queue1", false, new DefaultConsumer(channel) {
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("消费者1信息:" + new String(body));
        channel.basicAck(envelope.getDeliveryTag(), false);
    }
});

// 消费者2
channel.queueDeclare("queue2", false, false, false, null);
channel.queueBind("queue2", "exchange1", "");
channel.basicQos(1);
channel.basicConsume("queue2", false, new DefaultConsumer(channel) {
    // 同上
});

// 生产者
channel.basicPublish("exchange1", "", null, "hello world".getBytes());
Direct:定向
// 消费者1
channel.queueDeclare("queue3", false, false, false, null);
channel.exchangeDeclare("exchange3", BuiltinExchangeType.DIRECT);
channel.queueBind("queue3", "exchange3", "debug");
channel.queueBind("queue3", "exchange3", "info");
channel.basicQos(1);
channel.basicConsume("queue3", false, new DefaultConsumer(channel) {}
// 消费者2
channel.queueDeclare("queue4", false, false, false, null);
channel.queueBind("queue4", "exchange3", "warn");
channel.queueBind("queue4", "exchange3", "error");
channel.basicQos(1);
channel.basicConsume("queue4", false, new DefaultConsumer(channel) {}
// 生产者
List<String> keys = Arrays.asList("debug", "info", "warn", "error", "hello");
try (Connection connection = ConnectionUtils.getConnection();
        Channel channel = connection.createChannel();) {
    for (int i = 0; i < 10; i++) {
        channel.basicPublish("exchange3", keys.get(i % keys.size()), null, keys.get(i % keys.size()).getBytes());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AMQP(高级消息队列协议)是一种开放的网络协议,用于在分布式系统中传递和存储消息。它广泛应用于各种实时通讯、物联网、金融交易等领域。 AMQP定义了消息的格式和交换方式,并提供了强大的消息路由和可靠性机制,确保消息的可靠传输和处理。它可实现多对多的通信模式,支持消息的分发、过滤、排序等高级特性。 RabbitMQ是一个基于AMQP协议的开源消息中间件。它提供了一个可靠的、灵活的、可扩展的消息分发系统。RabbitMQ基于可插拔的插件机制,可以在不同的场景中灵活配置和扩展其功能。它具有高可用性、可靠性和可伸缩性,在分布式系统中被广泛应用。 RabbitMQ的核心概念包括生产者、消息队列和消费者。生产者负责产生消息并将其发送到RabbitMQ的消息队列中。消息队列是RabbitMQ的核心组件,用于存储消息,并根据一定的规则将消息分发给消费者。消费者则从消息队列中订阅并接收消息进行处理。 RabbitMQ还支持多种消息模型,如发布-订阅模型、工作队列模型和路由模型等。它可以根据不同的业务需求和场景,选择合适的消息模型来实现消息的可靠传输和处理。 总之,AMQP是一种用于分布式系统的高级消息队列协议,而RabbitMQ是基于AMQP的开源消息中间件。它们通过提供消息的格式、交换方式和路由规则等机制,实现了可靠的、灵活的消息传输和处理,极大地方便了分布式系统的开发和部署。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值