总结:
1.rabbitMQ生产者生产的消息是有序进入任务队列的;但多个消费者的情况下无论是否ack,都是无序的,不考虑任务时长;
2.rabbitMQ分发消息的时候采用round-robin模式,依次分配,并非一个一个分配;
3.rabbitMQ为防止重复消费,必须实现幂等型,即每个消费者必须能够查询到任务的执行状态
4.rabbitMQ要想顺序消费,必须一个任务队列只有一个消费者,必要时需要拆分任务队列
5.rabbitMQ防止消息丢失,必须把交换机和任务队列以及对应的类型消息进行持久化
6.rabbitMQ通过设置每个消费者同时处理消息的最大个数,来进行负载均衡
7.rabbitMQ通过设置消息的存活时间(TTL),超时后,就会被发送到队列的死信交换机,被再次路由,此时再次路由到的队列就被称为死信队列(Dead Letter Queue)。需要注意,死信交换机和死信交换机都是基于其用途来描述的,它们实际上也是普通的交换机和普通的队列。如果队列没有指定DLX或者无法被路由到一个DLQ,则队列中过期的消息会被直接丢弃(特殊场景,订单15分钟后未付款,就关闭)
8.rabbitMQ消息分发有轮训模式和公平模式,对于金融行情的使用需要用轮训模式,保证每个消费者消费的数据都一样
9.rabbitMQ在connection上面抽象出来很多channel
10.
RabbitMQ中,所有生产者提交的消息都由Exchange来接受,然后Exchange按照特定的策略转发到Queue进行存储
RabbitMQ提供了四种Exchange:fanout,direct,topic,header
header模式在实际使用中较少,本文只对前三种模式进行比较。
性能排序:fanout > direct >> topic。比例大约为11:10:6
rabbitMq交换机简介中介绍了rabbitMq的四种类型交换机;rabbitMq生产者角度一篇从生产者角度介绍如何保证消息被正确发送到服务器,如果未正确发送如何处理;本篇博客将从消费者角度介绍三个问题:队列分发消息到消费者的规则、如何确保消息一定被正确接受并处理了、如何保证多个消费者负载均衡。
一 、消息分发
官网的示例中介绍了默认情况下rabbitMqRabbitMQ会一个一个的发送信息给下一个消费者(consumer),而不考虑每个任务的时长等等,且是一次性分配,并非一个一个分配。平均的每个消费者将会获得相等数量的消息。这样分发消息的方式叫做round-robin。这可以表示为下图:
二、消息应答-保证消息被正确接受并处理
结合上面的分发图说明,默认情况下消费者C1接收到消息1无论是否正常接受和处理都会立即应答rabbit服务器,然后消息1就会从队列中被删除,假如C1突然出现异常状况导致消息1没有被处理完毕,那么消息1就处理失败了,也不会有其他消费者去处理消息1。事实上我们希望的是消息1如果没有被C1正确处理完毕,那么就发送给其他消费者处理,为了达到这个目的,只需要做两件事情,第一关闭rabbitMq的自动应答机制,第二消费者正确处理完消息后手动应答。
核心代码展示
//第二个参数autoAck设置成false表示关闭自动应答
channel.basicConsume(QUEUE_NAME, false, consumer);
while (true)
{
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(hashCode + " [x] Received '" + message + "'");
doWork(message);
System.out.println(hashCode + " [x] Done");
//手动应答,第二个参数multiple表示是否批量应答,很明显现在不是批量应答
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false );
}
1
2
3
4
5
6
7
8
9
10
11
12
三、消费者负载均衡
默认情况下rabitMq会把队列里面的消息立即发送到消费者,无论该消费者有多少消息没有应答,也就是说即使发现消费者来不及处理,新的消费者加入进来也没有办法处理已经堆积的消息,因为那些消息已经被发送给老消费者了。
chanel.basicQos(prefetchCount)
prefetchCount:会告诉RabbitMQ不要同时给一个消费者推送多于N个消息,即一旦有N个消息还没有ack,则该consumer将block掉,直到有消息ack。
这样做的好处是,如果系统处于高峰期,消费者来不及处理,消息会堆积在队列中,新启动的消费者可以马上从队列中取到消息开始工作。
图示:
上图描述了这样一个过程:刚启动时消费者C1、C2、C3均为空闲状态,且它们的channel都设置了prefetch=1,队列中有消息1~N。下面按照各消费者收到消息的时间顺序说明整个过程。
C1收到消息1开始处理。
C2收到消息2开始处理。
C3收到消息3开始处理。
C2处理完消息2并产生应答,可以看到图中消息2从队列中移除了。
C2收到消息4开始处理,可以看到图中消息4被标记为已发送状态。
C3处理完消息3并产生应答,可以看到图中消息3从队列中移除了。
C3收到消息5开始处理,可以看到消息5被标记为已发送状态。
上图反应的就是直到C3收到消息5并处理时的整个队列中所有消息的状态。
————————————————
版权声明:本文为CSDN博主「ni0224」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014045580/article/details/70432576