1 初识 MQ
MQ,Message Queue,也被称为消息队列。它是一种进程间通信或同一进程的不同线程间的通信方式,软件的贮列用来处理一系列的输入,通常是来自用户。消息队列提供了异步的通信协议,每一个贮列中的纪录包含详细说明的数据,包含发生的时间,输入设备的种类,以及特定的输入参数,也就是说:消息的发送者和接收者不需要同时与消息队列互交。消息会保存在队列中,直到接收者取回它。
事实上,我们可以把 MQ 理解为一个存放消息的容器。
2 架构模型
看了上面的解释,感觉还是有点难以理解,那我们上一个架构模型吧,相信这次必定可以一目了然。
- Producer:消息生产者,负责产生和发送消息到 Broker
- Broker:消息处理中心。负责消息存储、确认、重试等,一般其中会包含多个 queue
- Consumer:消息消费者,负责从 Broker 中获取消息,并进行相应处理
3 我们为什么要学习 MQ?
如题,又或者换个说法,学习 MQ 能干什么?如果我们学习知识,却不知道能用它干什么,那学习效率必然是十分低下的。
3.1 消息队列通可以过异步处理提高系统性能。
若不使用消息队列,我们就会把用户请求直接写入数据库,在高并发环境下数据库压力将会很大,响应速度也会随之变慢。使用消息队列之后,我们不再需要将用户请求写入数据库,而是写入消息队列即可,随后让消息队列中的消费者进程去队列中获取数据,并异步写入数据库,这将导致响应速度大大提升。
事实上,消息队列还具有削峰作用,通过异步处理,我们可以将短时间高并发产生的事务消息存储在消息队列中,以此削平高峰期的并发事务。
3.2 降低系统耦合性
如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,系统的可扩展性也会更好。
消息队列使利用发布-订阅模式工作,生产者发布消息,一个或多个消费者订阅消息。 事实上生产者与消费者并没有直接耦合。生产者将消息发送到消息队列就结束了对消息的处理,而消费者并不知道消息从何而来,如果存在新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计。(注意,消息队列不仅仅只有发布-订阅模式,其实还存在其他模式)
4 消息队列带来的问题
有利必有弊,我们之前已经分析过了消息队列的优势,现在我们再来看看消息队列的缺点吧。
4.1 系统可用性降低
引入 MQ 之后,我们需要考虑消息丢失或者 MQ 挂掉等各种情况,这会导致系统可用性降低。
4.2 系统复杂性提高
消息有没有被重复消费呢?消息丢失我们应该怎样处理呢?我们应该如何保证消息传递的顺序性呢?这些我们都是需要认真考虑的。
4.3 一致性问题
消息队列实现了异步,提高了响应速度。但如果消费者消费消息失败怎么办?这将会导致一致性问题。
5 JMS 和 AMQP
5.1 JMS 的介绍
JMS,即 Java MessageService,就是一个 API。JMS 是由 Sun 公司早期提出的消息标准,旨在为java应用提供统一的消息操作。从使用角度看,JMS 和 JDBC 担任差不多的角色,用户都是根据相应的接口可以和实现了JMS的服务进行通信,进行相关的操作。
5.1.1 peer-2-peer(点对点)模型
点对点模型使用队列作为消息通信载体,满足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。
5.1.2 publish-subscribe(发布-订阅)模型
发布订阅模型使用主题作为消息通信载体,发布者发布一条消息,该消息会通过主题传递给所有的订阅者。
5.2 AMQP 的介绍
AMQP,即 advanced message queuing protocol,是一种协议。其实我们可以使用 HTTP 来类比 AMQP,跨语言跨平台,只要按照相应的数据格式去发送报文请求,不同语言的 client 均可以和不同语言的 server 链接。
我们今天故事的主角 – RabbitMQ 就是基于 AMQP 协议实现的。