消息队列---RabbitMQ的学习(八)

 只想学习补充自己的呆头鹅

自述

   该篇文章属于额外篇,主要描述RabbitMQ提供的消息确认,这也是倒数第二篇文章了,最后一篇文章将对RabbitMQ进行总结,敬请期待吧!
在这里插入图片描述

发布确认

   发布者确认是实现可靠发布的RabbiMQ扩展,当在通道上启用发布者确认时,客户端发布的消息由代理异步确认,这也就意味着它们已经在服务器端得到处理。

//开启消息确认
channel.confirmSelect();
//判断是否开启消息确认
channel.waitForConfirms();

单独发布

   单独发布和往常我们的普通队列类型,只不过通过通道设置消息确认,实现简单,但会影响吞吐量,每次发布消息都会进行消息确认,会降低发布速度。
 ConfirmSend.java

/**
 * confirm 生产者
 * 单条
 */
public class ConfirmSend {
    //exchangename
    private static final String EX_CHANGE_NAME = "ex_yunk";

    public static void main(String[] args) {
        try {
            //1.connection
            Connection connection = ConnectionUtil.getConnection();
            //2.channel
            Channel channel = connection.createChannel();
            //3.create exchange
            channel.exchangeDeclare(EX_CHANGE_NAME, "fanout");
            //4.msg confirm --开启消息确认
            channel.confirmSelect();
            //5.msg
            String msg = "msg success";
            //增量
            int size = 0;
            //begin
            long begin = System.currentTimeMillis();
            //6.publish
            while (size < 5000) {
                size++;
                //发送
                channel.basicPublish(EX_CHANGE_NAME, "", null, msg.getBytes());
                //5秒内确认
                channel.waitForConfirmsOrDie(5000);
            }
            System.out.println("消息发送成功" + (System.currentTimeMillis() - begin));
            //close
            ConnectionUtil.closeConnection(connection, channel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

批量发布

   批量发布见名知意,批量的确认消息,提高吞吐量,但唯一不足点:当批量确认时如遇到问题也无法定位到问题所在。
 ConfirmSend2.java

/**
 * confirm 生产者
 * 批量
 */
public class ConfirmSend2 {
    //exchangename
    private static final String EX_CHANGE_NAME = "ex_yunk";

    public static void main(String[] args) {
        try {
            //1.connection
            Connection connection = ConnectionUtil.getConnection();
            //2.channel
            Channel channel = connection.createChannel();
            //3.create exchange
            channel.exchangeDeclare(EX_CHANGE_NAME, "fanout");
            //4.msg confirm --开启消息确认
            channel.confirmSelect();
            //5.msg
            String msg = "msg success";
            //消息数量
            int outmsgcount = 0;
            //100/1 每100条发一次
            int batchSize = 100;
            //增量
            int size = 0;
            //begin
            long begin = System.currentTimeMillis();
            //6.publish
            while (size < 5000) {
                size++;
                outmsgcount++;
                channel.basicPublish(EX_CHANGE_NAME, "", null, msg.getBytes());
                //批量消息确认
                if (outmsgcount == batchSize) {
                    channel.waitForConfirmsOrDie(5000);
                    outmsgcount = 0;
                }
            }
            //谨防疏漏的消息确认
            if (outmsgcount > 0) {
                channel.waitForConfirmsOrDie(5_000);
            }
            System.out.println("消息发送成功" + (System.currentTimeMillis() - begin));
            //close
            ConnectionUtil.closeConnection(connection, channel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

异步处理发布者

   异步处理发布者确认是有点麻烦的,具体步骤如下:①提供一种将发布序列号与消息相关联的方法。②在通道上注册监听器,方便对消息确认或nack-ed进行相对应的处理,注: 无论是消息确认后或nack-ed,都需要将相关条目消息进行删除。
 ConfirmSend3.java

/**
 * confirm 生产者
 * 异步 aysn
 */
public class ConfirmSend3 {
    //exchangename
    private static final String EX_CHANGE_NAME = "ex_yunk";

    public static void main(String[] args) {
        try {
            //1.connection
            Connection connection = ConnectionUtil.getConnection();
            //2.channel
            Channel channel = connection.createChannel();
            //3.create exchange
            channel.exchangeDeclare(EX_CHANGE_NAME, "fanout");
            //4.msg confirm  --开启消息确认
            channel.confirmSelect();
            //5.msg
            String msg = "msg success";
            //将序列号与消息绑定到一起
            ConcurrentNavigableMap<Long, String> outstandingConfirms = new ConcurrentSkipListMap<>();
            //asyntype
            //methodone:消息确认回调
            //methodtwo:消息未确认回调
            //②不管是消息确认或nack,最终都要将映射的消息删除
            channel.addConfirmListener(new ConfirmListener() {
                @Override
                public void handleAck(long sequence, boolean multiple) throws IOException {
                    if (multiple) {
                        //返回小于等于该序列号的消息--前提是inclusive参数需设为true
                        ConcurrentNavigableMap<Long, String> confirmed = outstandingConfirms.headMap(sequence, true);
                        //删除所有映射
                        confirmed.clear();
                    } else {
                        //删除指定的映射
                        outstandingConfirms.remove(sequence);
                    }
                }

                @Override
                public void handleNack(long sequence, boolean multiple) throws IOException {
                    //获取指定key的消息
                    String msg = outstandingConfirms.get(sequence);
                    //执行重复操作
                    handleAck(sequence, multiple);
                }
            });
            //begin
            long begin = System.currentTimeMillis();
            int size = 0;
            while (size < 5000) {
                size++;
                //获取序列号
                long nextPublishSeqNo = channel.getNextPublishSeqNo();
                //①将序列号与消息进行绑定
                outstandingConfirms.put(nextPublishSeqNo, msg);
                //发送消息
                channel.basicPublish(EX_CHANGE_NAME, "", null, msg.getBytes());
            }
            System.out.println("消息发送成功" + (System.currentTimeMillis() - begin));
            //close
            ConnectionUtil.closeConnection(connection, channel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

消费者

   普通消费者。

/**
 * confirms 消费者
 */
public class ConfirmRecv {
    //exchangename
    private static final String EX_CHANGE_NAME = "ex_yunk";

    public static void main(String[] args) {
        try {
            //1.connection
            Connection connection = ConnectionUtil.getConnection();
            //2.channel
            Channel channel = connection.createChannel();
            //3.create exchange
            channel.exchangeDeclare(EX_CHANGE_NAME, "fanout");
            //4.queue
            String queue = channel.queueDeclare().getQueue();
            //5.biding
            channel.queueBind(queue, EX_CHANGE_NAME, "");
            //6.callback
            DeliverCallback deliverCallback = new DeliverCallback() {
                @Override
                public void handle(String s, Delivery delivery) throws IOException {
                    System.out.println("获取的消息=====" + new String(delivery.getBody()));
                }
            };
            //7.consumer  ---autoack
            channel.basicConsume(queue, true, deliverCallback, cancel -> {
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

性能测试

条数时间(ms)类型
50002193单条
5000653批量
5000760异步

总结

   单独发布:同步等待消息确认,实现简单,但吞吐量下降(tps)。
   批量发布:同步等待消息确认,批量消息确认,吞吐量提升,但批量消息确认时如出现问题无法定位问题关键所在。
   异步发布:异步等待消息确认,最佳性能和资源使用,错误情况下的良好控制,但实现复杂,难理解。

Ending

   good night!
小jio

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值