RabbitMQ 交换器、持久化

 一、 交换器

  RabbitMQ交换器(Exchange)分为四种

  1.   direct       
  2.   fanout
  3.   topic
  4.   headers
  •  direct

   默认的交换器类型,消息的RoutingKey与队列的bindingKey匹配,消息就投递到相应的队列

  •  fanout

  一种发布/订阅模式的交换器,发布一条消息时,fanout把消息广播附加到fanout交换器的队列上  

  接收类(订阅): 

import com.rabbitmq.client.*;

import java.io.IOException;

public class ReceiveLogs {
  private static final String EXCHANGE_NAME = "logs";

  public static void main(String[] argv) throws Exception {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("localhost");
    Connection connection = factory.newConnection();
    Channel channel = connection.createChannel();

    channel.exchangeDeclare(EXCHANGE_NAME, "fanout");//一旦创建exchange,RabbitMQ不允许对其改变,否则报错
    String queueName = channel.queueDeclare().getQueue();
    channel.queueBind(queueName, EXCHANGE_NAME, "");//绑定是交换器与队列之间的关系,可以理解为,队列对此交换器的消息感兴趣

    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

    Consumer consumer = new DefaultConsumer(channel) {
      @Override
      public void handleDelivery(String consumerTag, Envelope envelope,
                                 AMQP.BasicProperties properties, byte[] body) throws IOException {
        String message = new String(body, "UTF-8");
        System.out.println(" [x] Received '" + message + "'");
      }
    };
    channel.basicConsume(queueName, true, consumer);
  }
}

  发布类: 

import java.io.IOException;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;

public class ReceiveLog {

    private static final String EXCHANGE_NAME = "log";

    public static void main(String[] argv)
                  throws java.io.IOException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); String message = "hi"; channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes()); System.out.println(" [x] Sent '" + message + "'"); channel.close(); connection.close(); } }
  • topic

  topic类似于fanout交换器,但更加具体化,用routingKey进行规则匹配,更灵活的匹配出用户想要接收的消息

  routingKey形如:com.company.module.demo,具体匹配规则:

    "*"与"#"可以匹配任意字符,区别是"*"只能匹配由"."分割的一段字符,而"#"可以匹配所有字符   

   发布一条"com.abc.test.push"的消息,能匹配的routingKey:

com.abc.test.*
#.test.push
#

  不能匹配的:

com.abc.*
*.test.push
*

 发布类:

  声明队列时,需要注意队列的属性,虽然队列的声明由消费者或生产者完成都可以,但如果由消费者声明,由于生产者生产消息时,可能队列还没有声明,会造成消息丢失,所以推荐由生产者声明队列

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
 
import com.rabbitmq.client.ConnectionFactory;
 
import java.io.IOException;
 
public class RabbitMqSendTest {
    private static String queue = "test_queue";
    private static String exchange = "TestExchange";
    private static String routingKey = "abc.test";
    public static void main(String[] args) {
        ConnectionFactory factory = new com.rabbitmq.client.ConnectionFactory();
        factory.setHost("172.16.67.60");
        factory.setPort(5672);
        factory.setUsername("admin");
        factory.setPassword("admin");
        Connection mqConnection = null;
        try {
            mqConnection = factory.newConnection();
            Channel mqChannel = mqConnection.createChannel();
            if (null != mqChannel && mqChannel.isOpen()) {
                mqChannel.exchangeDeclare(exchange, "topic");
//                String queueName = mqChannel.queueDeclare().getQueue();
//                mqChannel.queueBind(queueName, exchange, routingKey);
//声明队列名称与属性
//durable持久队列,mq重启队列可恢复 exclusive独占队列,仅限于声明它的连接使用操作
//autoDelete 自动删除 arguments 其他属性
                mqChannel.queueDeclare(queue, false, false, false, null);
                mqChannel.queueBind(queue, exchange, routingKey);
 
                //*******************************************
                    mqChannel.basicPublish(exchange, routingKey, null,
                            ("hello").getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
               try {
                   mqConnection.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
        }
 
    }
}

接收类

import com.rabbitmq.client.*;
import java.io.IOException;

public class ReceiveTopic {
    private static String queue = "consume_queue";
    private static String exchange = "TestExchange";
    private static String routingKey = "*.test";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("172.16.67.60");
        factory.setPort(5672);
        factory.setUsername("admin");
        factory.setPassword("admin");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

//        channel声明Exchange,名称与类型
        channel.exchangeDeclare(exchange, "topic");
//        String queuename = channel.queueDeclare().getQueue();

        channel.queueDeclare(queue, false, false, false, null);
        channel.queueBind(queue, exchange, "*.test");      //消费者指定消息队列,并选择特定的RoutingKey
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        Consumer client = new DefaultConsumer(channel) {
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)throws IOException {
                String msgString = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + msgString + "'");
            }
        };
        channel.basicConsume(queue, true,client);
        System.out.println();
    }
}

二、持久化

  RabbitMQ默认情况下重启消息服务器时,会丢失消息,为了尽量保证消息在服务器宕机时不丢失,就需要把消息持久化,但是也只是尽量不丢失,由于涉及磁盘写入,当消息量巨大时,mq性能也会被严重拉低。

 

转载于:https://www.cnblogs.com/castielangel/p/9952069.html

### RabbitMQ 持久化相关面试题及解决方案 #### 1. 如何保证消息不丢失? 为了防止消息在传输过程中丢失,RabbitMQ 提供了多种机制来保障消息的安全性和可靠性。以下是主要的措施: - **Confirm 消息确认机制 (生产者)** 生产者发送消息到 RabbitMQ 后,可以通过开启 Confirm 模式来确保消息成功到达服务器。如果消息未能投递给目标队列,则会触发回调函数通知生产者重试或采取其他补救措施[^2]。 - **消息持久化机制 (RabbitMQ 服务)** 配置消息为持久化状态可以使其存储在磁盘上而不是仅存在于内存中。即使 RabbitMQ 宕机重启后,这些消息仍然能够恢复并继续传递给消费者[^1]。 - **ACK 事务机制 (消费者)** 当消费者接收到一条消息时,在完成对该条数据的所有处理之后才向 Broker 发送 ACK 确认信号表示已接收完毕;如果没有返回 ACK 或者发生异常断开连接等情况,则该未被确认的消息会被重新放回原队列等待再次分配给新的客户端实例去消费它。 #### 2. 哪些组件支持持久化RabbitMQ持久化功能不仅限于消息本身,还包括以下几个方面: - **交换器(Exchange)** 和 **队列(Queue)** 可以设置成 durable 属性以便它们能够在 broker 节点崩溃后再次启动起来的时候依然存在而不消失掉。 示例代码如下所示: ```python channel.exchange_declare(exchange='my_durable_exchange', exchange_type='direct', durable=True) channel.queue_declare(queue='my_durable_queue', durable=True) ``` - **绑定关系(Binding)** 不需要单独声明其是否具备耐用特性,默认情况下当关联双方均为持久实体时此链接也会保持不变直至显式解除为止。 #### 3. 如果遇到大量积压待处理的数据怎么办? 针对可能出现的大规模未读记录现象可以从多个角度出发寻找对策: - **提高并发能力** - 添加更多工作线程或者进程参与到任务执行当中从而加快整体进度; - 对现有程序内部结构加以改进使得每次循环迭代所耗费时间更少一些比如通过批量提交请求等方式减少频繁交互带来的额外负担[^4]。 - **启用 prefetch count 参数限制每台机器最多允许获取多少尚未反馈成功的项目数以此平衡负载压力避免某些节点因过度占用资源而陷入瘫痪状态无法正常运作下去^. - **引入优先级概念让重要程度较高的指令先得到响应机会进而缓解紧急状况下的延迟问题同时兼顾公平原则给予低权重对象合理安排轮候顺序的机会.** --- ### 总结 综上所述,通过对 RabbitMQ 进行适当调整以及采用科学合理的运维手段完全可以有效应对各种复杂场景下产生的挑战达到预期效果即最大程度降低丢包率的同时还能维持高效稳定运行环境满足实际需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值