消费端的手工ACK和NACK

  消费端进行消费的时候,如果由于业务异常我们可以进行日志的记录,然后进行补偿。

  如果由于服务器宕机等严重问题,那么我们就需要手工进行ACK保障消费端成功。

消费端重回队列

  为了对没有处理成功的消息,把消息重新回递给Broker。

  一般我们在实际应用中,都会关闭重回队列,也就是设置为false。

  1. //生产端代码
  2. ConnectionFactory connectionFactory = new ConnectionFactory();
  3. connectionFactory.setHost("127.0.0.1");
  4. connectionFactory.setPort(5672);
  5. connectionFactory.setVirtualHost("/");
  6.  
  7. Connection connection = connectionFactory.newConnection();
  8. Channel channel = connection.createChannel();
  9.  
  10. String exchange = "test_ack_exchange";
  11. String routingKey = "ack.save";
  12.  
  13. for(int i =0; i<5; i ++){
  14.  
  15. Map<String, Object> headers = new HashMap<String, Object>();
  16. headers.put("num", i);
  17.  
  18. AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
  19. .deliveryMode(2)
  20. .contentEncoding("UTF-8")
  21. .headers(headers)
  22. .build();
  23. String msg = "Hello RabbitMQ ACK Message " + i;
  24. channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes());
  25. }
  1. //消费端代码
  2. ConnectionFactory connectionFactory = new ConnectionFactory();
  3. connectionFactory.setHost("127.0.0.1");
  4. connectionFactory.setPort(5672);
  5. connectionFactory.setVirtualHost("/");
  6.  
  7. Connection connection = connectionFactory.newConnection();
  8. Channel channel = connection.createChannel();
  9.  
  10. String exchangeName = "test_ack_exchange";
  11. String queueName = "test_ack_queue";
  12. String routingKey = "ack.#";
  13.  
  14. channel.exchangeDeclare(exchangeName, "topic", true, false, null);
  15. channel.queueDeclare(queueName, true, false, false, null);
  16. channel.queueBind(queueName, exchangeName, routingKey);
  17.  
  18. // 手工签收 必须要关闭 autoAck = false
  19. channel.basicConsume(queueName, false, new MyConsumer(channel));
  1. //自定义消费者
  2. private Channel channel ;
  3.  
  4. public MyConsumer(Channel channel) {
  5. super(channel);
  6. this.channel = channel;
  7. }
  8.  
  9. @Override
  10. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  11. System.err.println("-----------consume message----------");
  12. System.err.println("body: " + new String(body));
  13. try {
  14. Thread.sleep(2000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. if((Integer)properties.getHeaders().get("num") == 0) {
  19. channel.basicNack(envelope.getDeliveryTag(), false, true);
  20. } else {
  21. channel.basicAck(envelope.getDeliveryTag(), false);
  22. }
  23.  
  24. }

TTL队列/消息

  TTL是time to live的缩写,也就是生存时间

  RabbitMQ支持消息的过期时间,在消息发送时可以进行指定

  RabbitMQ支持队列的过期时间,从消息入队列开始计算,只要超过了队列的超过时间配置,那么消息会自动的清除。

  

  消息10s过期,TTL是队列过期时间。

DLX死信队列

  DLX,Dead-Letter-Exchange

  利用DLX,当消息在一个队列中变成死信之后,它能够被重新publish到另一个exchange,这个exchange就是DLX。

消息变成死信情况

  消息被拒绝(basic.reject/basic.nack)并且request=false

  消息TTL过期

  队列达到最大的长度

DLX也是一个正常的exchange,和一般的exchange没有区别,他能在任何的队列上被指定,实际上就是设置某个队列的属性。

当这个队列中有死信时,RabbitMQ就会自动的将这个消息重新发布到设置的exchange上去,进而被路由到另一个队列。 

可以监听这个队列中消息做相应的处理,这个特性可以弥补RabbitMQ3.0以前支持的immediate参数的功能。 

死信队列设置:

  首先要设置死信队列的exchange和queue,然后进行绑定:

  Exchange:dlx.exchange

  Queue:dlx.queue

  RoutingKey:#

  然后我们进行正常声明交换机,队列,绑定,只不过我们需要在队列加上一个参数:arguments.put("x-dead-letter-exchange","dlx.exchange");

  这样消息在过期、request、队列子啊达到最大长度时, 消息就可以直接路由到死信队列。 

  1. //生产者端代码
  2. ConnectionFactory connectionFactory = new ConnectionFactory();
  3. connectionFactory.setHost("127.0.0.1");
  4. connectionFactory.setPort(5672);
  5. connectionFactory.setVirtualHost("/");
  6.  
  7. Connection connection = connectionFactory.newConnection();
  8. Channel channel = connection.createChannel();
  9.  
  10. String exchange = "test_dlx_exchange";
  11. String routingKey = "dlx.save";
  12.  
  13. String msg = "Hello RabbitMQ DLX Message";
  14.  
  15. for(int i =0; i<1; i ++){
  16.  
  17. AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
  18. .deliveryMode(2)
  19. .contentEncoding("UTF-8")
  20. .expiration("10000")
  21. .build();
  22. channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes());
  23. }
  1. //消费者端代码
  2. ConnectionFactory connectionFactory = new ConnectionFactory();
  3. connectionFactory.setHost("127.0.0.1");
  4. connectionFactory.setPort(5672);
  5. connectionFactory.setVirtualHost("/");
  6.  
  7. Connection connection = connectionFactory.newConnection();
  8. Channel channel = connection.createChannel();
  9.  
  10. // 这就是一个普通的交换机 和 队列 以及路由
  11. String exchangeName = "test_dlx_exchange";
  12. String routingKey = "dlx.#";
  13. String queueName = "test_dlx_queue";
  14.  
  15. channel.exchangeDeclare(exchangeName, "topic", true, false, null);
  16.  
  17. Map<String, Object> agruments = new HashMap<String, Object>();
  18. agruments.put("x-dead-letter-exchange", "dlx.exchange");
  19. //这个agruments属性,要设置到声明队列上
  20. channel.queueDeclare(queueName, true, false, false, agruments);
  21. channel.queueBind(queueName, exchangeName, routingKey);
  22.  
  23. //要进行死信队列的声明:
  24. channel.exchangeDeclare("dlx.exchange", "topic", true, false, null);
  25. channel.queueDeclare("dlx.queue", true, false, false, null);
  26. channel.queueBind("dlx.queue", "dlx.exchange", "#");
  27.  
  28. channel.basicConsume(queueName, true, new MyConsumer(channel));
  1. //自定义消费者
  2. public MyConsumer(Channel channel) {
  3. super(channel);
  4. }
  5.  
  6. @Override
  7. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  8. System.err.println("-----------consume message----------");
  9. System.err.println("consumerTag: " + consumerTag);
  10. System.err.println("envelope: " + envelope);
  11. System.err.println("properties: " + properties);
  12. System.err.println("body: " + new String(body));
  13. }

RabbitMQ消费端ACK与重回队列机制,TTL,死信队列详解(十一)的更多相关文章

  1. 消费端ACK和重回队列

    使用场景 消费端ACK和重回队列 消费端ACK使用场景: 1.消费端进行消费的时候,如果由于业务异常我们可以进行日志记录,然后进行补偿. 2.由于服务器宕机等严重问题,那我们就需要手工进行ACK保障消 ...

  2. RabbitMQ 消费端限流、TTL、死信队列

    目录 消费端限流 1. 为什么要对消费端限流 2.限流的 api 讲解 3.如何对消费端进行限流 TTL 1.消息的 TTL 2.队列的 TTL 死信队列 实现死信队列步骤 总结 消费端限流 1. 为 ...

  3. RabbitMQ 入门系列:9、扩展内容:死信队列:真不适合当延时队列。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  4. python中利用队列asyncio.Queue进行通讯详解

    python中利用队列asyncio.Queue进行通讯详解 本文主要给大家介绍了关于python用队列asyncio.Queue通讯的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细 ...

  5. 服务端捡起或丢弃指定物品ID触发详解

    传奇服务端捡起或丢弃指定物品ID触发详解: @PickUpItemsX X是物品数据库中对应的IDX@DropItemsX X是物品数据库中对应的IDX@H.PickUpItemsX X是物品数据库中 ...

  6. RabbitMQ消费端消息的获取方式(.Net Core)

    1[短链接]:BasicGet(String queue, Boolean autoAck) 通过request的方式独自去获取消息,断开式,一次次获取,如果返回null,则说明队列中没有消息. 隐患 ...

  7. RabbitMQ消费端限流策略(十)

    消费端限流: 什么是消费端限流? 场景: 我们RabbitMQ服务器有上万条未处理的消息,我们随便打开一个消费者客户端,会出现下面情况: 巨量的消息瞬间全部推送过来,但是我们单个客户端无法同时处理这么 ...

  8. RabbitMQ消费端自定义监听(九)

    场景: 我们一般在代码中编写while循环,进行consumer.nextDelivery方法进行获取下一条消息,然后进行消费处理. 实际环境: 我们使用自定义的Consumer更加的方便,解耦性更强 ...

  9. RabbitMQ与.net core(四) 消息的优先级 与 死信队列

    1.消息的优先级 假如现在有个需求,我们需要让一些优先级最高的通知推送到客户端,我们可以使用redis的sortedset,也可以使用我们今天要说的rabbit的消息优先级属性 Producer代码 ...

随机推荐

  1. vue2.0父子组件通信以及同级组件通信

    1.父向子通信 父组件为singer.vue.子组件为list-view.vue.需要把歌手的数据传给子组件.则绑定 :data = 'singers' ,singers为父组件的值.data为子组件 ...

  2. js if 判断的使用

    !DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> ...

  3. mock.js的运用

    一:概念 Mock.js是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试.提供了以下模拟功能: 根据数据模板生成模拟数据 模拟 Ajax 请求,生成并返回模拟数据 基于 H ...

  4. JAVA基础--JAVA 集合框架(泛型、file类)

    一.集合总结 集合:Collection体系.Map体系. Collection体系:单列集合的共性操作规则. List:列表,可以重复,有下标,拥有特有的迭代器ListIterator. Array ...

  5. 线性表源码分享(c++),包含顺序表、单链表、循环链表、双向链表

    ---恢复内容开始--- 我是一个c++和数据结构的初学者,本文主要是把清华大学出版社的数据结构(用面向对象方法与c++语言描述)(第2版)这本书中第二章线性表的源码抄下来,在学习的过程中有助于加深印 ...

  6. c++多线程并发学习笔记(1)

    共享数据带来的问题:条件竞争 避免恶性条件竞争的方法: 1. 对数据结构采用某种保护机制,确保只有进行修改的线程才能看到修改时的中间状态.从其他访问线程的角度来看,修改不是已经完成了,就是还没开始. ...

  7. Python 入门之编码

    Python 入门之编码 1.编码初识: (1)ASCII码 :256 个 英文1个字节,不支持中文 (2)GBK(国标) : 英文1个字节 中文两个字节 (3)unicode (万国码):英文4个字 ...

  8. numpy.random.randn()和numpy.random.rand()

    1 numpy.random.rand() (1)numpy.random.rand(d0,d1,…,dn) rand函数根据给定维度生成[0,1)之间的数据,包含0,不包含1 dn表格每个维度 返回 ...

  9. intellij idea 的快捷键方法

    1.Ctrl+N按名字搜索类 相当于eclipse的ctrl+shift+R,输入类名可以定位到这个类文件,就像idea在其它的搜索部分的表现一样,搜索类名也能对你所要搜索的内容多个部分进行匹配,而且 ...

  10. gradle上sourceSets配置&同名文件合并问题

    gradle的sourceSets可以对不同的buildType, productFlavor,buildVariant设置不同的文件路径,进行多样化处理. sourceSets{ main{ man ...