RabbitMq的一些概念,持久化、队列排他、自动删除、消息确认机制、消息ACK、消费消息的模式

1、队列持久化的概念

队列的声明默认是存放到内存中的,若是rabbitmq重启会丢失,若是想重启以后还存在就要使队列持久化,保存到Erlang自带的Mnesia数据库中,当rabbitmq重启以后会读取该数据库。数据库

2、排他

简单理解就是在链接关闭时是否会删除队列(不管队列中有没有消息) 性能

3、自动删除

当队列中有消息时,不管是否排他,关闭链接都不会删除队列,此时消费者消费完消息后再断开消费者,队列会被自动删除。(这里若是有多个消费者消费同一个队列,则须要全部消费者都断开后才能自动删除) 线程

4、消息确认机制 Message acknowledgment

在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其余意外)的状况,这种状况下就可能会致使消息丢失。为了不这种状况发生,咱们能够要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除;若是RabbitMQ没有收到回执并检测到消费者的RabbitMQ链接断开,则RabbitMQ会将该消息发送给其余消费者(若是存在多个消费者)进行处理。这里不存在timeout概念,一个消费者处理消息时间再长也不会致使该消息被发送给其余消费者,除非它的RabbitMQ链接断开。 这里会产生另一个问题,若是咱们的开发人员在处理完业务逻辑后,忘记发送回执给RabbitMQ,这将会致使严重的bug——Queue中堆积的消息会愈来愈多;消费者重启后会重复消费这些消息并重复执行业务逻辑…。pub message是没有ack的。接口

消息一旦被消费者接收,队列中的消息就会被删除。RabbitMQ怎么知道消息被接收了呢?rabbitmq

若是消费者领取消息后,还没执行操做就挂掉了呢?或者抛出了异常?消息消费失败,可是RabbitMQ无从得知,这样消息就丢失了!队列

所以,RabbitMQ有一个ACK机制。当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收。 内存

5、消息ACK的两种状况

  • 自动ACK
    • 消息一旦被接收,消费者自动发送ACK 若是消息不过重要,丢失也没有影响,那么自动ACK会比较方便
  • 手动ACK
    • 消息接收后,不会发送ACK,须要手动调用 若是消息很是重要,不容丢失。那么最好在消费完成后手动ACK,不然接收消息后就自动ACK,RabbitMQ就会把消息从队列中删除。若是此时消费者宕机,那么消息就丢失了。 

6、Rabbitmq消费消息的模式

rabbitmq的消费模式分为两种: 推(Push)模式和拉(Pull)模式。推模式采用Basic.Consume进行消费,而拉模式则是调用Basic.Get模式。 资源

  • Push模式

  • mq主动将消息推送给消费者(消费者需提供一个消费接口)
  • mq属于主动方,消费者属于一种被动消费,一旦有消息到达mq,会触发mq推送机制,将消息推送给消费者,无论消费者处于何种状态。
  • 优势:
    • 消费者代码较少:对于消费者来讲,只需提供一个消费接口给mq便可;mq将接收到的消息,随即推送到指定的消费接口
    • 消息实时性比较高:对于消费者来讲,消息一旦到达mq,mq会当即推送给消费者
  • 缺点:
    • 消费者属于被动方,消息量比较大时,对消费者性能要求比较高;若消费者机器资源有限,可能会致使压力过载,引起宕机的状况。
    • 对消费者可用性要求比较高:当消费者不可用时,会致使很push失败,在mq方须要考虑至少推送成功一次。
  • Pull模式 

  • 消息消费的过程:
    • 消费端采用轮询的方式,从mq服务中拉取消息进行消费
    • 消费完成通知mq删除已消费成功的消息
    • 继续拉取消息消费
  • 对于消费者来讲,是主动方,能够采用线程池的方式,根据机器的性能来增长或缩小线程池的大小,控制拉取消息的速度,能够很好的控制自身的压力。
  • 优势:
    • 消费者能够根据本身的性能主动控制消息拉去的速度,控制本身的压力,不至于把本身弄跨
    • 实时性相对于push方式会低一些
    • 消费者属于主动方,控制权更大一些
  • 缺点:
    • 消费方须要实现消息拉取的代码
    • 消费速度较慢时,可能致使mq中消息积压,消息消费延迟等。

7、消费模式的最佳实践 

  • 消费者性能较好,对实时性要求比较高的,能够采用push的方式
  • 消费者性能有限,建议采用pull的方式
  • 总体上来讲,主要在于消费者的性能,机器的性能若是没有问题,push和pull都是能够的