概念与原理

  订单系统中,用户点击【下单】按钮之后的业务逻辑可能包括:扣减库存、生成相应单据、发红包、发短信通知。在业务发展初期,这些逻辑可能放在一起同步执行,随着业务的发展订单量增长,需要提升系统服务的性能,可以将一些不需要立即生效的操作拆分出来异步执行,比如发放红包、发短信通知等。这种场景下就可以用 MQ ,在下单的主流程(比如扣减库存、生成相应单据)完成之后发送一条消息到 MQ 让主流程快速完结,而由另外的单独线程拉取MQ的消息(或者由 MQ 推送消息),当发现 MQ 中有发红包或发短信之类的消息时,执行相应的业务逻辑。

消息模型
  消费者(consumer)订阅某个队列。生产者(producer)创建消息,然后发布到队列(queue)中,最后将消息发送到监听的消费者。

  

   AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议

  消费者:连接到AMQP的消息中间件,订阅到队列上,进行消息的消费。分为持续订阅(basicConsumer)和单条订阅(basicGet)

  持续订阅:只要有消息就不断消费

       单条订阅:消费过一条消息以后就不再消费了,要想继续消费消息,就得重新订阅到队列上
       消息:包括有效载荷和标签。有效载荷就是要传输的数据标签描述有效载荷的属性,RabbitMQ用标签来决定谁获得当前消息。消费者只能拿到有效载荷。
  
Exchange 交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。
  Binding 绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,可以将交换器理解成一个由绑定构成的路由表。
  
Queue 消息队列,用来保存消息直到发送给消费者。消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走
  
Connection 网络连接,比如一个TCP连接

  信道: 虚拟的连接,建立在真实的TCP/IP连接之上的。信道的创建是没有限制的。AMQP所有的消息和命令都是通过信道来传输的。

  使用信道的好处:建立在TCP/IP连接上性能更高,TCP/IP的连接数是有上限的,并且还要频繁的创建连接和关闭连接,节约宝贵的TCP/IP连接资源

  AMQP 中的消息路由
  AMQP 中增加 Exchange 和 Binding 的角色。生产者把消息发布到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列。

Exchange 类型

  四种类型:directfanout、topicheaders 。headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到,所以直接看另外三种类型:

  direct

  

   消息中的路由键(routing key)和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发 routing key 标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard”等等。是完全匹配、单播的模式。

  fanout

      

  每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得一份复制的消息。fanout 类型转发消息是最快的。

  topic

  

  topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配不多不少一个单词。

  队列通过路由键(routing key,某种确定的规则)绑定到交换器,生产者把消息发送到交换器,交换器根据绑定的路由键将消息路由到特定的队列,订阅队列的消费者进行接收。
  1)如果消息达到无人订阅的队列会怎么办?
  消息会一直在队列中等待,直到内存溢出。RabbitMQ会默认队列是无限长度的。
  2)多个消费者订阅到同一队列怎么办?
  消息会轮询的方式发送给消费者,每个消息只会发送给一个消费者
  3)消息路由到了不存在的队列怎么办?
  会忽略,当消息不存在,消息丢失。

  虚拟主机

  Vhost,真实RabbitMQ服务器上的mini型虚拟的MQ服务器。有自己的权限机制。Vhost提供一个逻辑上的分离,可以区分不同客户端、避免队列的名称冲突、交换器的名称冲突。RabbitMq包含一个缺省的vhost :"/",用户名guest,口令 guest(guest用户只能在本机访问)。

  消息的确认机制

  消费者收到的每一条消息都必须进行确认,分为自动确认消费者自行确认
  消费者在声明队列时,指定autoAck参数(true:自动确认,false:自行确认),false时RabbitMQ会等到消费者显示的发回一个ack信号才会删除消息
  消息确认机制的好处:
  autoAck=false时,有足够时间让消费者处理消息,直到消费者显示调用basicAck为止。
  autoAck=false时,Rabbitmq中消息分为两部分:1、等待投递的消息;2、已经投递,但是还没有收到ack信号。如果消费者断连,服务器会把消息重新入队,投递给下一个消费者。未ack的消息是没有超时时间的
  如何明确拒绝消息
  1)消费者断连
  2)消费者使用reject命令(requeue=true,重新分发消息到其他消费者,requeue=false移除消息)
  3)nack命令(批量的拒绝,requeue=true,重新分发消息,requeue=false移除消息)
  拒绝消息是为了处理一些特殊的异常
  创建队列
  生产者和消费者可以创建队列(declareQueue)。消费者订阅了队列,不能再声明队列。相关参数(exclusive:队列是应用程序私有的,auto-delete:最后一个消费者取消订阅时,队列会自动删除,durable:当前队列是否持久化)
  

  

  

  

 

  

  

  

  

  

posted on 2020-01-01 10:43  溪水静幽  阅读(181)  评论(0)    收藏  举报