AMQP协议?
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。 AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
AMQP三层协议:
Module Layer:协议最高层,主要定义了一些客户端调用的命令,客户端可以用这些命令实现自己的业务逻辑。
Session Layer:中间层,主要负责客户端命会发送给服务器,再将服务端应答返回客户端,提供可靠性同步机制和错误处理。
TransportLayer:最底层,主要传输二进制数据流,提供帧的处理、信道服用、错误检测和数据表示等。
AMQP组件:
交换器(Exchange):消息代理服务器中用于把消息路由到队列的组件。
队列(queue):用来存储消息的数据结构,位于硬盘或内存中。
绑定(Binding):一套规则,告知交换器消息应该将消息投递给哪个队列。
RabbitMQ包含哪些要素?
- 生产者:消息队列创建者,发送消息到MQ
- 消费者:连接到RabbitMQ,订阅到队列上,消费消息,持续订阅和单条订阅
- 消息:包含有效载荷和标签,有效载荷指要传输的数据,标签描述了有效载荷,并且RabbitMQ用它来决定谁获得消息,消费者只能拿到有效载荷,并不知道生产者是谁
RabbitMQ各个部分的概念?
信道
是生产者、消费者与RabbitMQ通信的渠道,生产者publish或是消费者subscribe 一个队列都是通过信道来通信的。
信道是建立在TCP连接上的虚拟连接,就是说RabbitMQ在一条TCP上建立成百上千个信道来达到多个线程处理,这个TCP被多个线程共享,每个线程对应一个信道,信道在RabbitMQ都有一个唯一的ID,保证了信道私有性,对应上唯一的线程使用。
Broker
broker是指一个或多个erlang node的逻辑分组,且node上运行着RabbitMQ应用程序。
Cluster
cluster是在broker的基础之上,増加了node之间共享元数据的约束。
Exchange
生产者将消息发送到交换器,有交换器将消息路由到一个或者多个队中。当路由不到时,或返回给生产者或直接丟弃。
RoutingKey
生产者将消息发送给交换器的时候,会指定一个RoutingKey,用来指定这个消息的路由规则,这个RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。
Binding
通过绑定将交换器和队列关联起来,一般会指定一个BindingKey,这样RabbitMq就知道如何正确路由消息到队列了。
死信队列
当消息被RabbitMQ server投递到consumer后,但consumer却通过 Basic.Reject进行了拒绝时(同时设置requeue=false),那么该消息会被放入死信队列中。该 queue 可用于排查 message 被 reject 或 undeliver 的原因。
vhost
vhost可以理解为虚拟broker,即mini-RabbitMQ server。其内部均含有独立的queue、exchange和binding等,但最最、重要的是,其拥有独立的权限系统,可以做到vhost范围的用户控制。当然,从RabbitMQ的全局角度,vhost可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的vhost中)。
RabbitMQ的routing key和binding key的最大长度是多少?
255字节。
RabbitMQ中消息可能有的几种状态?
- alpha:消息内容(包括消息体、属性和headers)和消息索引都存储在内存
- beta:消息内容保存在磁盘中,消息索引保存在内存中
- gamma:消息内容保存在磁盘中,消息索引在磁盘和内存中都有
- delta:消息内容和索引都在磁盘中
RabbitMQ的消息传输保证层级?
At most once:最多一次。消息可能会丢失,但不会重复传递
At least once:最少一次。消息绝不会丟失,但可能会重夏传输
Exactly once:恰好一次。每条消息肯定仅传输一次
RabbitMQ的工作模式?
simple模式(即最简单的收发模式)
消息产生消息,将消息放入队列
消息的消费者监听消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除(隐患消息可能没有被消费者正确处理,已经从队列中消失了,造成消息的丢失,这里可以设置成手动的ack,但如果设置成手动ack,处理完后要及时发送ack消息给队列,否则会造成内存溢出)。
work工作模式(资源的竞争)
消息产生者将消息放入队列消费者可以有多个,消费者1,消费者2同时监听同一个队列,消息被消费。C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息(隐患:高并发情况下,默认会产生某一个消息被多个消费者共同使用,可以设置一个开关[syncronize]保证一条消息只能被一个消费者使用)。
publish/subscribe发布订阅(共享资源)
每个消费者监听自己的队列。
生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息。
routing路由模式
消息生产者将消息发送给交换机按照路由判断,路由是字符串(info)当前产生的消息携带路由字符(对象的方法),交换机根据路由的key,只能匹配上路由key对应的消息队列,对应的消费者才能消费消息。
topic主题模式(路由模式的一种)
为路由功能添加模糊匹配,消息产生者产生消息,把消息交给交换机,交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费。
发送消息的过程?
生产者将消息发布到一个或多个交换器(Exchange)中。交换器的作用是根据路由键(Routing Key)将消息分配给特定的队列(Queue)。
交换器通过路由键将消息路由到一个或多个队列。如果路由键为空,消息会被分配给所有绑定到该交换器的队列。
消息进入队列,等待被消费者接收。在队列中,消息会被存储在持久化存储中,以防服务器崩溃或重启时数据丢失。
消费者从队列中获取消息并进行处理。消费者可以通过订阅一个或多个队列来接收消息。一旦消息被消费者接收,它将从队列中移除。
为什么要使用RabbitMQ?
在分布式系统下具备异步,削峰,负载均衡等一系列高级功能
拥有持久化的机制,进程消息,队列中的信息也可以保存下来
实现消费者和生产者之间的解耦
对于高并发场景下,利用消息队列可以使得同步访问变为串行访问达到一定量的限流,利于数据库的操作
可以使用消息队列达到异步下单的效果,排队中,后台进行逻辑下单
RabbitMQ缺点?
复杂性:RabbitMQ 需要一定的学习和理解成本,特别是在配置、管理和监控方面。
可靠性:RabbitMQ 的可靠性依赖于其配置和管理,需要进行合理的配置和监控,否则可能会出现消息丢失或重复传递等问题。
性能:RabbitMQ 的性能与其配置和使用方式密切相关,如果配置不当或使用不当,可能会导致性能问题。
成本:RabbitMQ 需要一定的硬件和软件资源支持,特别是在高并发和大规模应用场景下,需要投入更多的资源。
可扩展性:RabbitMQ 的可扩展性有一定限制,如果需要支持更高的并发和吞吐量,需要进行集群部署和负载均衡等操作。
存储要求:RabbitMQ 依赖于磁盘进行消息存储,因此需要一定的存储空间,并需要定期清理过期消息。
Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优缺点?
一般的业务系统要引入 MQ,最早大家都用 ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以大家还是算了吧,我个人不推荐用这个了;
后来大家开始用 RabbitMQ,但是确实 erlang 语言阻止了大量的 Java 工程师去深入研究和掌控它,对公司而言,几乎处于不可控的状态,但是确实人家是开源的,比较稳定的支持,活跃度也高;
不过现在确实越来越多的公司会去用 RocketMQ,确实很不错,毕竟是阿里出品,但社区可能有突然黄掉的风险(目前 RocketMQ 已捐给,但 GitHub 上的活跃度其实不算高)对自己公司技术实力有绝对自信的,推荐用 RocketMQ,否则回去老老实实用 RabbitMQ 吧,人家有活跃的开源社区,绝对不会黄;
所以中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择;
大数据领域的实时计算、日志采集等场景,使用Kafka。