RabbitMQ(Advanced Message Queuing Protocol,高级消息队列协议)是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。
一、消息队列使用场景
1、异步通信(防止客户端阻塞)
同步通信需要双方都在线,而使用消息队列,生产者可以将数据投放到消息队列中,等消费者在线了再取数据消费。
服务在处理耗时长的请求时,可以先返回响应,告诉客户端收到请求了,正在处理。这样客户端就不会阻塞,可以做其他工作。等服务处理完请求,将处理结果投递到消息队列中,
客户端订阅消息队列就能收到处理结果,根据处理结果做相应操作。
2、解耦
耦合度高的服务一般都是需要共享数据,通过消息队列可以实现数据共享,从而实现解耦。
二、相关术语
1、生产者
消息的生产者。也是一个向交换器Exchange发送消息的应用程序。
2、信道
网络信道,是TCP里面的虚拟连接。几乎所有的操作都在Channel中进行, Channel是进行消息读写的通道。客户端可以建立多个Channel
rabbitmq中多个信道共享一个TCP连接,避免tcp连接成为性能瓶颈。
3、交换机
接收生产者发送的消息,根据路由键转发消息到绑定的队列。
4、队列
消息队列,保存消息并将它们转发给消费者。它是消息的容器,也是消息的终点。一个消息可以投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列上将其取走。
5、消费者
消息的消费者。表示一个从消息队列中取得消息的应用程序
6、BindingKey
Exchange和Queue之间的虚拟连接,binding中可以包含routing key。
一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
7、RoutingKey
路由键。一个路由规则,虚拟机可用它来确定如何路由一个特定消息。
队列通过路由键绑定到交换机。
消息发送到MQ服务器时,消息将拥有一个路由键,即便是空的。RabbitMQ也会将其和绑定使用的路由键进行匹配。
如果匹配,消息将投递到该队列;如果不匹配,消息将会进入黑洞。
三、工作流程
生产者创建与rabbitmq的tcp连接,将数据投递到交换机中,交换机根据数据的路由键找到绑定到该交换机的队列,将数据投递到该队列。
消费者订阅响应的消息队列,收到消息后rabbitmq将数据发生给消费者。
四、交换机类型
1、direct(发布与订阅,完全匹配)
消息的RoutingKey和和队列的BindingKey要完全一致,交换机才会把消息投递到该队列
2、fanout(广播)
交换机不管消息的RoutingKey,将消息投递到所有绑定到该交换机的队列中
3、topic(主题,规则匹配)
可以理解成路由模式,即根据消息的RoutingKey投递到匹配的BingdingKey队列中。
4‘、header(key-value)
根据key-value来投递消息。消息的key-value和队列的key-value相同才投递
五、常见问题
1、可靠性如何保证?
投递过程中可能存在某个过程失败导致消息丢失。大概分成三种
1.1、生产者投递过程失败导致消息丢失
生产者在投递消息过程中,由于出现网络问题或者其他原因,导致消息未能到达交换机。
如何解决:
开启生产者确认机制即confirm,只有当生产者投递消息到交换机成功后,rabbitmq发送一个confirm确认给生产者,这样才算投递完成,否则,生产者需要重复投递,直到收到confirm确认。
1.2、rabbitmq内部消息持久化失败导致消息丢失
消息交换机后,进入队列中,由于rabbitmq突然崩溃或者其他原因,消息还没持久化导致消息丢失。
如何解决:
在开启生产者确认机制confirm时,只有当消息被正确投递到队列,并且已经持久化成功了,才给生产者发送ack。
1.3、消费者接收消息失败导致消息丢失
消息从队列中取出要投递给消费者时,由于网络问题或者其他原因,导致消息未能到达消费者
如何解决:
类似于生产者确认机制,开启消费者确认机制ack。当消息被消费者收到后,消费者发送acl给rabbitmq,才算投递成功。否则rabbitmq需要重复投递,直到收到消费者的ack消息,才将消息从队列中删除。
这个过程可能存在多次消费问题,即消费者收到了消息,并且发送了ack,但是由于超时,rabbitmq没有收到ack,重新投递了消息。这种情况就会导致消费者多次消费同个消息。
要求消费者实现幂等。即消费一次和消费多次是一样的结果。