目录
- 概念
- RabbitMQ的五种消息模型
- 消息确认机制
参考:
概念
AMQP 和 JMS
AMQP:即Advanced Message Queuing Protocol,是一个应用层标准高级消息队列协议,提供统一消息服务。是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。
JMS:即Java消息服务(Java Message Service)应用程序接口,由sun公司提出,并且sun公司定义好了接口。包括create、send、recieve。只要想使用它,就得实现它定义的接口。 消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。不好的地方是语言层面的限制,只能为JAVA,这其实稍微有点和微服务的观点相违背。要求语言只能是JAVA,而不能是py等。
常见MQ产品
ActiveMQ:基于JMS,Apache
RocketMQ:(Rocket,火箭)阿里巴巴的产品,基于JMS,目前由Apache基于会维护
Kafka:分布式消息系统,亮点:吞吐量超级高,没秒中数十万的并发。
RabbitMQ:(Rabbit,兔子)由erlang语言开发,基于AMQP协议,在erlang语言特性的加持下,RabbitMQ稳定性要比其他的MQ产品好一些,而且erlang语言本身是面向高并发的编程的语言,所以RabbitMQ速度也非常快。且它基于AMQP协议,对分布式、微服务更友好。
virtual host
可以通过MySQL和MySQL中的数据库来理解RabbitMQ和virtual host的关系。
MySQL大家都不陌生,经常会出现多个业务线混用一个MySQL数据库的情况,就像下图这样,每个业务线都在MySQL中创建自己的数据库,使用时各自往各自的数据库中存储数据,彼此相互不干涉。
RabbitMQ和virtual host的关系也差不多,可以让多个业务线同时使用一个RabbitMQ,只要为业务线各个业务线绑定上不同的virtual host即可:
RabbitMQ的五种消息模型
RabbitMQ支持以下五种消息模型,第六种RPC本质上是服务调用,所以不算做服务通信消息模型。
Hello World
P(producer/ publisher):生产者,发送消息的服务
C(consumer):消费者,接收消息的服务
红色区域就是MQ中的Queue,可以把它理解成一个邮箱
- 首先信件来了不强求必须马上马去拿
- 其次,它是有最大容量的(受主机和磁盘的限制,是一个缓存区)
- 允许多个消费者监听同一个队列,争抢消息
Worker模型
Worker模型中也只有一个工作队列。但它是一种竞争消费模式。可以看到同一个队列我们绑定上了多个消费者,消费者争抢着消费消息,这可以有效的避免消息堆积。
比如对于短信微服务集群来说就可以使用这种消息模型,来了请求大家抢着消费掉。
如何实现这种架构:对于上面的HelloWorld这其实就是相同的服务我们启动了多次罢了,自然就是这种架构。
订阅模型
订阅模型借助一个新的概念:Exchange(交换机)实现,不同的订阅模型本质上是根据交换机(Exchange)的类型划分的。
订阅模型有三种
- Fanout(广播模型): 将消息发送给绑定给交换机的所有队列(因为他们使用的是同一个RoutingKey)。
- Direct(定向): 把消息发送给拥有指定Routing Key (路由键)的队列。
- Topic(通配符): 把消息传递给拥有 符合Routing Patten(路由模式)的队列。
订阅之Fanout模型
这个模型的特点就是它在发送消息的时候,并没有指明Rounting Key , 或者说他指定了Routing Key,但是所有的消费者都知道,大家都能接收到消息,就像听广播。
订阅之Direct模型
P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。
X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列
C1:消费者,其所在队列指定了需要routing key 为 error 的消息
C2:消费者,其所在队列指定了需要routing key 为 info、error、warning 的消息
拥有不同的RoutingKey的消费者,会收到来自交换机的不同信息,而不是大家都使用同一个Routing Key 和广播模型区分开来。
订阅之Topic模型
类似于Direct模型。区别是Topic的Routing Key支持通配符。
消息确认机制
ACK机制
所谓的ACK确认机制:
自动ACK:消费者接收到消息后自动发送ACK给RabbitMQ。
手动ACK:我们手动控制消费者接收到并成功消息后发送ACK给RabbitMQ。
你可以看上图:如果使用自动ACK,当消息者将消息从channel中取出后,RabbitMQ随即将消息给删除。接着不幸的是,消费者没来得及处理消息就挂了。那也就意味着消息其实丢失了。
你可能会说:会不会存在重复消费的情况呢?这其实就不是MQ的问题了。你完全可以在你代码的逻辑层面上进行诸如去重、插入前先检查是否已存在等逻辑规避重复消费问题。