RabbitMQ解决了什么问题?
解耦降低服务间的耦合性。同步变异步,如电商的订单服务,短信服务,邮件服务。流量削峰。
AMQP
是一个网络协议。客户端和消息中间件代理之间的通信。了解协议的操作方法而不是只停留在弄懂特定客户端的库
连接
AMQP连接是长连接,使用TCP的应用层协议。
构成
AMQP由许多操作构成。
消息确认
消费者用它来确认消息已经被接收或者处理。如果一个应用崩溃掉(此时连接会断掉,所以AMQP代理亦会得知),而且消息的确认回执功能已经被开启,但是消息代理尚未获得确认回执,那么消息会被重新放入队列(在还有其他消费者存在于此队列的前提下,立即投递给另外一个消费者)。
消息属性和消息主体
消息带有属性,含有一个有效载荷(消息实际携带的数据),消息可以只包含属性而不携带数据,数据通常使用类似JSON序列化格式数据,消息可以持久化,但是对性能会造成一些影响。
预取消息
指定每个消费者在收到下一个确认回执前一次可以接受多少条消息,在批量发布消息的时候起到简单的负载均衡和提高消息吞吐量的作用。
拒绝消息
一个消费者处理消息失败或成功,应用可以向消息代理表明失败与否,拒绝消息时应用可以告诉消息代理如何处理这条消息,注:如果队列中只用一个消费者时,应该确认不要因为拒绝消息而重新放入队列从而导致无限循环。在AMQP中,ba方法用来执行拒绝消息的操作。它有个限制,不能使用它
RabbitMQ
类比现实中的邮局
消息如何到队列?
首先创建消息,并设定路由键,然后发布到交换器通过队列路由键,把队列绑定到交换器上。消息到达交换器,RabbitMQ把消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则),如果能够匹配到队列,就把消息投递到相应的队列中;如果没有匹配任何队列,则消息称之为死信。
交换器类型有哪些?
direct:根据路由键匹配相应的队列,匹配则投递消息fanout:交换器收到消息将广播到所有绑定到它的队列。topic:主题交换器,可以使来自不同源头的消息能够到达同一个队列,路由键必须以.隔开的一系列的标识符组成。
如何保证消息正确的发送到RabbitMQ?
RabbitMQ使用发送确认模式来保证消息正确发送,一旦消息被投递到目的队列后,信道会发送一个确认给生产者(包含消息唯一ID),如果消息丢失,会发送一条nack(未确认)消息,发送确认模式是异步的。
如果确保消息接收方消费了消息?
接收确认机制:消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作),只有消费者确认了消息,RabbitMQ才会安全的把消息从队列中删除,且这里没有使用超时机制,RabbitMQ通过Consumer的连接状态来判断是否重新发送消息,如果连接不中断,会一直等待消费者确认该消息已经被消费。
如何避免消息重复投递或重复消费?
在生产消息时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据;在消息消费时,要求消息体中必须要有一个bizld作为去重和幂等的依据。
如何解决丢数据的问题?
1.生产者数据丢失MQ提供transaction和confirm模式来确保生产者不丢失消息。transaction机制:发送消息前,开启事务,然后发送消息,如果发送过程中出现什么异常,事务就会回滚,如果发送成功则提交事务,缺点就是吞吐量下降。confirm:所有在该信道上面发布的消息都会有一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,mq会发送一个ACK给生产者(包含消息的唯一ID),这可以让生产者确认消息到达队列,如果mq没有处理该消息,则会发送一个NAck消息给你,你可以进行重试操作。
消息队列丢失数据
持久化消息队列,设置durable为true。
消费者丢数据
启用手动确认模式自动确认模式消费者挂掉,待ack的消息回归到队列中。消费者抛出异常,消息会不断的被重发,直到处理成功。不会丢失消息,即便服务挂掉,没有处理完成的消息会重回队列,但是异常会让消息不断重试。手动确认模式如果消费者来不及处理就死掉时,没有响应ack时会重复发送一条信息给其他消费者;如果监听程序处理异常了,且未对异常进行捕获,会一直重复接收消息,然后一直抛异常;如果对异常进行了捕获,但是没有在finally里ack,也会一直重复发送消息(重试机制)。不确认模式acknowledge="none" 不使用确认机制,只要消息发送完成会立即在队列移除,无论客户端异常还是断开,只要发送完就移除,不会重发。
RabbitMQ的弊端?
系统可用性降低
系统复杂性增加