消息中间件(5)—— 获取消息

上节学习消息发布时的策略,本节学习获取消息时的策略

我们知道消费者会消费队列上的消息,那么消费者如何知道队列上什么时候有消息的呢

有拉取和推送两种方式

最简单的方式就是一直轮询该队列(称之为拉取),也就是while(){...}的方式

显然这种方式很消耗性能,不推荐使用,但是可以先看一下

一、拉取

1.1 消费者demo

public class GetMessageConsumer {
    public static void main(String[] argv)
            throws IOException, TimeoutException, InterruptedException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        Connection connection = factory.newConnection();
        final Channel channel = connection.createChannel();

        channel.exchangeDeclare(GetMessageProducer.EXCHANGE_NAME,"direct");
        String queueName = "focuserror";
        channel.queueDeclare(queueName,false,false,false,null);
        String routekey="error";
        channel.queueBind(queueName,GetMessageProducer.EXCHANGE_NAME, routekey);

        System.out.println(" [*] Waiting for messages......");
        //TODO 无限循环拉取
        while(true){
        	//参数2为 false表示不自动确认,需要手动确认,一般设置为true
            GetResponse getResponse = channel.basicGet(queueName, false);
            if(null!=getResponse){
                System.out.println("处理业务");
            }
            //手动确认(上面参数为true时,该语句可省略)
            channel.basicAck(0,true);
            Thread.sleep(1000);
        }
    }
}

通过basicGet方法获取队列上的消息

这里注意,在使用拉取的时候,我们设置了一个是否自动进行消息确认的参数

这里引出一个知识点

消费者获取消息之后,无论是拉取还是推送,都应该给MQ一个消息确认

消息确认后,RabbitMQ 才会从队列删除这条消息

因为RabbitMQ 不会为未确认的消息设置超时时间

它判断此消息是否需要重新投递给消费者的唯一依据是消费该消息的消费者连接是否已经断开

这么设计的原因是RabbitMQ 允许消费者消费一条消息的时间可以很久

1.2 消息确认

消息确认可分为自动确认和手动确认

自动确认:消费者在声明队列时,指定 autoAck 为true,一旦消费者接收到了消息,就视为自动确认了消息。如果消费者在处理消息的过程中,出了错,就没有什么办法重新处理这条消息,所以我们很多时候,需要在消息处理成功后,再确认消息,这就需要手动确认。

手动确认:当 autoAck=false 时,RabbitMQ 会等待消费者显式发回 ack 信号后才从内存(和磁盘,如果是持久化消息的话)中移去消息。否则,RabbitMQ 会在队列中消息被消费后立即删除它。 

当 autoAck=false 时,对于 RabbitMQ 服务器端而言,队列中的消息分成了两部分:一部分是等待投递给消费者的消息;一部分是已经投递给消费者, 但是还没有收到消费者 ack 信号的消息。如果服务器端一直没有收到消费者的 ack 信号,并且消费此消息的消费者已经断开连接,则服务器端会安排该消息重新进入队列,等待投递给下一个消费者(也可能还是原来那个消费者)

public class AckFalseConsumerB {

    public static void main(String[] argv)
            throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        Connection connection = factory.newConnection();
        final Channel channel = connection.createChannel();
        channel.exchangeDeclare(DirectProducer.EXCHANGE_NAME,"direct");
        String queueName = "focuserror";
        channel.queueDeclare(queueName,false,false,false,null);

        /*绑定,将队列和交换器通过路由键进行绑定*/
        String routekey = "error";
        channel.queueBind(queueName,DirectProducer.EXCHANGE_NAME,routekey);

        System.out.println("waiting for message........");

        /*声明了一个消费者*/
        final 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");
                //TODO 这里进行确认
                System.out.println("业务处理成功,手动确认:"+envelope.getDeliveryTag());
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        };
        /*消费者正式开始在指定队列上消费消息*/
        //这里第二个参数是自动确认参数,如果是false则是手动确认
        channel.basicConsume(queueName,false,consumer);
    }
}

二、推送

上面介绍消息确认时采用的即是推送模式

三、QOS预取模式

上面介绍都是每条消息被消费后即进行消费确认

也可以预先要求接收一定数量的消息,在处理完一定数量的消息后,批量进行确认
//预取500条消息
channel.basicQos(500,true);
/*消费者正式开始在指定队列上消费消息*/
channel.basicConsume(queueName,false,consumer);

 

 

总结

消息者获取消息的两种方式:拉取和推送

消息确认的两种方式:自动和手动

 

一共四种情况

1、拉取自动确认

GetResponse getResponse = channel.basicGet(queueName, true);

2、拉取手动确认

//采用手动确认方式

GetResponse getResponse = channel.basicGet(queueName, false);

//消费者消费完后,进行手动确认

channel.basicAck(0,true);

3、推送自动确认

//这里第二个参数是自动确认参数,如果是false则是手动确认
channel.basicConsume(queueName,true,consumer);

4、推送手动确认
 

//这里第二个参数是自动确认参数,如果是false则是手动确认
channel.basicConsume(queueName,false,consumer);

//消费者消费完成后,进行手动确认
channel.basicAck(envelope.getDeliveryTag(),false);

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ansystool手写中间件的并行框架是一种用于优化计算过程中并行执行的工具。它基于并行计算的理论和技术,结合了分布式计算、并发编程和并行算法等多种技术手段,旨在提高计算性能和效率。 这个并行框架可以将计算任务划分成多个子任务,然后并行地执行这些子任务,从而加快整个计算过程的速度。它可以根据计算需求的特点和硬件环境的情况,选择合适的并行策略和算法,使得计算任务能够得到有效地分解和并行化。 ansystool手写中间件的并行框架还提供了丰富的并行编程接口和工具,使得开发人员可以方便地利用并行计算资源,编写高效的并行代码。它支持任务调度、数据传输、同步和通信等关键操作,以及任务分配、负载均衡和故障处理等关键功能,保证了整个并行计算过程的正确性和稳定性。 此外,ansystool手写中间件的并行框架还具有良好的可扩展性和灵活性,可以根据计算任务的规模和要求,进行弹性的资源分配和管理。它可以利用现有的计算资源,也可以扩展到多个计算节点或集群,在大规模并行计算场景下,仍然能够保持高效的计算性能和吞吐量。 总之,ansystool手写中间件的并行框架是一种强大的工具,可以帮助开发人员利用并行计算的优势,提高计算性能和效率。它在分布式计算、并发编程和并行算法等领域都具有广泛的应用前景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值