RabbitMQ的应用场景以及基本原理介绍
发布网友
发布时间:2024-10-01 12:00
我来回答
共1个回答
热心网友
时间:2024-10-28 00:49
RabbitMQ是一个由erlang开发的AMQP(高级消息队列协议)的开源实现。
AMQP,即高级消息队列协议,是一种应用层协议的开放标准,主要用于面向消息的中间件设计。消息中间件主要用来实现组件间的解耦,使得消息的发送者无需知道消息使用者的存在,反之亦然。AMQP的主要特性包括面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。RabbitMQ作为一个开源的AMQP实现,服务器端使用Erlang语言编写,支持多种客户端,如Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,同时也支持AJAX。它用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现出色。
RabbitMQ最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。具体特点包括:
三、RabbitMQ基本概念
四、Exchange类型
Exchange分发消息时,根据类型的不同,分发策略也有所区别。目前共有四种类型:direct、fanout、topic、headers。headers匹配AMQP消息的header而不是路由键,此外headers交换器和direct交换器完全一致,但性能较差,目前几乎用不到了,所以直接看另外三种类型:
消息中的路由键(routing key)如果和Binding中的binding key一致,交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发routing key标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard”等等。它是完全匹配、单播的模式。
每个发到fanout类型交换器的消息都会分到所有绑定的队列上。fanout交换器不处理路由键,只是简单地将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout类型转发消息是最快的。
topic交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,匹配不多不少一个单词。
五、ConnectionFactory、Connection、Channel
ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。
六、任务分发机制
1、Round-robin dispatching循环分发
RabbitMQ的分发机制非常适合扩展,而且它是专门为并发程序设计的。如果现在load加重,那么只需要创建更多的Consumer来进行任务处理。
2、Message acknowledgment消息确认
在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其他意外)的情况,这种情况下就可能会导致消息丢失。为了避免这种情况发生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除;如果RabbitMQ没有收到回执并检测到消费者的RabbitMQ连接断开,则RabbitMQ会将该消息发送给其他消费者(如果存在多个消费者)进行处理。这里不存在timeout概念,一个消费者处理消息时间再长也不会导致该消息被发送给其他消费者,除非它的RabbitMQ连接断开。这里会产生另外一个问题,如果我们的开发人员在处理完业务逻辑后,忘记发送回执给RabbitMQ,这将会导致严重的bug——Queue中堆积的消息会越来越多;消费者重启后会重复消费这些消息并重复执行业务逻辑...
3、Message rability消息持久化
如果我们希望即使在RabbitMQ服务重启的情况下,也不会丢失消息,我们可以将Queue与Message都设置为可持久化的(rable),这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失。但依然解决不了小概率丢失事件的发生(比如RabbitMQ服务器已经接收到生产者的消息,但还没来得及持久化该消息时RabbitMQ服务器就断电了),如果我们需要对这种小概率事件也要管理起来,那么我们要用到事务。由于这里仅为RabbitMQ的简单介绍,所以这里将不讲解RabbitMQ相关的事务。
4、Fair dispatch公平分发
你可能也注意到了,分发机制不是那么优雅,默认状态下,RabbitMQ将第n个Message分发给第n个Consumer。n是取余后的,它不管Consumer是否还有unacked Message,只是按照这个默认的机制进行分发。那么如果有个Consumer工作比较重,那么就会导致有的Consumer基本没事可做,有的Consumer却毫无休息的机会,那么,Rabbit是如何处理这种问题呢?
前面我们讲到如果有多个消费者同时订阅同一个Queue中的消息,Queue中的消息会被平摊给多个消费者。这时如果每个消息的处理时间不同,就有可能会导致某些消费者一直在忙,而另外一些消费者很快就处理完手头工作并一直空闲的情况。我们可以通过设置prefetchCount来*Queue每次发送给每个消费者的消息数,比如我们设置prefetchCount=1,则Queue每次给每个消费者发送一条消息;消费者处理完这条消息后Queue会再给该消费者发送一条消息。
通过basic.qos方法设置prefetch_count=1,这样RabbitMQ就会使得每个Consumer在同一个时间点最多处理一个Message,换句话说,在接收到该Consumer的ack前,它不会将新的Message分发给它
channel.basic_qos(prefetch_count=1)
注意,这种方法可能会导致queue满。当然,这种情况下你可能需要添加更多的Consumer,或者创建更多的virtual Host来细化你的设计。
七、消息序列化
RabbitMQ使用ProtoBuf序列化消息,它可作为RabbitMQ的Message的数据格式进行传输,由于是结构化的数据,这样就极大地方便了Consumer的数据高效处理。当然也可以使用XML,与XML相比,ProtoBuf有以下优势:1.简单,2.size小了3-10倍,3.速度快了20-100倍,4.易于编程,6.减少了语义的歧义。ProtoBuf具有速度和空间的优势,使得它现在应用非常广泛。
八、RPC
MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)。
但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procere Call,远程过程调用)。
RabbitMQ中也支持RPC,RabbitMQ中实现RPC的机制是:客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14种properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)服务器端收到消息并处理,处理完消息后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性。客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理
九、RabbitMQ选型和对比
1、从社区活跃度
按照目前网络上的资料,RabbitMQ、ActiveM、ZeroMQ三者中,综合来看,RabbitMQ是首选。
2、持久化消息比较
ZeroMq不支持,ActiveMq和RabbitMq都支持。持久化消息主要是指我们机器在不可抗力因素等情况下挂掉了,消息不会丢失的机制。
3、综合技术实现
可靠性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件系统等等。RabbitMq/Kafka最好,ActiveMq次之,ZeroMq最差。当然ZeroMq也可以做到,不过自己必须手动写代码实现,代码量不小。尤其是可靠性中的:持久性、投递确认、发布者证实和高可用性。
4、高并发
毋庸置疑,RabbitMQ最高,原因是它的实现语言是天生具备高并发高可用的erlang语言。
5、比较关注的比较,RabbitMQ和Kafka
RabbitMq比Kafka成熟,在可用性上,稳定性上,可靠性上,RabbitMq胜于Kafka(理论上)。另外,Kafka的定位主要在日志等方面,因为Kafka设计的初衷就是处理日志的,可以看做是一个日志(消息)系统一个重要组件,针对性很强,所以如果业务方面还是建议选择RabbitMq。还有就是,Kafka的性能(吞吐量、TPS)比RabbitMq要高出来很多。选型最后总结:如果我们系统中已经有选择Kafka,或者RabbitMq,并且完全可以满足现在的业务,建议就不用重复去增加和造轮子。可以在Kafka和RabbitMq中选择一个适合自己团队和业务的,这个才是最重要的。但是毋庸置疑现阶段,综合考虑没有第三选择。