一、什么是消息中间件
在分布式系统中,网络上的不同节点之间可以通过服务框架进行互相调用,但是会在不同的应用之间造成耦合。而消息中间件就是能够使得不同的节点通过消息进行互相关联而又不存在耦合。
二、为什么需要消息中间件
假设有一个交易管理系统,用户登录的时候,短信服务中心需要发送短信给用户进行验证,风控系统需要进行用户的登录环境核实,如果没有消息中间件,那么需要在用户登录的管理系统中主动调用不同应用的服务,而实际上用户登录模块只需要完成自己校验密码正确与否的工作即可,那么就会造成一个登录操作耦合不同的服务中心的情况。
而消息中间件的出现可以解决以上的耦合情况。当出现了消息中间件之后,以上需要主动去调用服务的情况就变成了其他的应用去订阅用户登录的消息,当其他应用收到消息的时候自己去处理逻辑,而登录模块就不需要关心什么服务需要监听用户登录的情况,代码就解耦了。
三、JMS
- JMS规范的组成
- Destination:消息的通道,定义消息从发送到接收的通道。
- ConnectionFactory:用于创建消息连接的对象,属于管理类。
- Connection:连接接口,主要用于创建Session。
- Session:会话接口。消息对象、消息的创建者、消息的消费者都是由Session会话产生。
- MessageConsumer:消息的消费者。
- MessageProducer:消息产生者。
- Message:消息
以上的数据流程为:ConnectionFactory->Connection->Session->Message
Destination+Session-> MessageProducer
Destination+Session-> MessageConsumer
JMS的消费模型
Topic模型
Topic模型指的是每个消息的订阅方都会接收到所有一模一样的消息。如下图所示:
Queue模型
队列模型指的是每个消息的订阅方共享所有的消息并集体消费。如下图所示:
四、消息中间件
A、消息发送端保证可靠性
消息的一致性指的是当消息的发送应该是应用的操作成功或者失败,有明确具体的返回结果之后消息进行发送,而当应用未进行操作的时候,消息不能被发送,当应用进行操作之后,消息必须被发送,这个称之为消息的一致性。
而当我们使用应用与消息中间件进行交互的时候,消息的一致性就变得尤其重要了,消息如果不一致容易造成业务的数据出现问题。
如何保证消息的发送的一致性,找到一个通用的消息一致性模型是非常重要。按照TopSky的书里的图如下:
从上图可以看到一条消息的发送路径如下:
- 先发送消息到消息中间件并将消息变为待处理状态存储在消息存储系统里面。(消息存储系统可以是数据库、分布式存储、内存等等存储方式)
- 返回存储成功与否的状态给应用,应用进行消息存储状态判断,如果存储成功,则触发业务操作,如果存储失败,则取消业务操作。
- 当消息存储成功,应用触发相关操作后,应用将操作的处理结果返回给消息中间件。
如果应用返回处理结果的为成功,那么将消息的状态变更为待发送。而当业务失败,则删除消息。
但是其实依旧可以看到存在一些问题,比如当应用在进行业务操作的时候迟迟未返回操作结果,那么消息是否需要发送呢?
由此可以将消息中间件被动等待应用返回结果可以变更为消息中间件主动轮询业务结果即可。如下图所示:
B、如何保证消息的可靠性
订阅方式的可靠性
消息的订阅分为两种:分别为永久订阅与非永久订阅。永久订阅指的是当订阅消息的机器下线的时候,在下线期间产生的消息会在机器重新上线的时候进行发送。而非永久订阅则在订阅消息的机器下线的时间窗口不会将该时间段产生的消息发送给消息订阅者。因此为了能收到消息,可靠的选择是永久订阅。
消息存储的可靠性
- 分布式文件存储
- 双内存+外存存储
- 数据库存储
消息发送的可靠性
消息发送的可靠性也就是消息的一致性,如上文所讲的内容。
五、消息的重复性问题
在消息的情景中,最常见的是订阅了消息,然而消息会重复进行发送消费的情况。导致消息重复发送的情况有很多种,第一种是应用重复发送消息,当应用将消息存入消息中间件的时候,消息已经存入中间件而应用未得到已经存入消息中间件的返回结果的时候。第二种是消息中间件发送消息但是未得到发送成功的返回的时候,会以为发送失败,则会尝试再次发送消息等等情况。
而在消息订阅者的角度,为了防止消息重复消费,应该增加一层幂等校验。
举一个例子:当我们需要监听一个订单更新的消息的时候,因为订单的状态很多种,比如创建订单、取消订单、订单付款等等状态,因为消息的重复发送我们如果不做幂等校验会导致插入多条数据,而消息的先后顺序会造成数据的丢失以及错乱等等。
做幂等校验有许多的方式:例如增加缓存,判断该消息是否已经消息过了。或者在进行CRUD操作的时候先判断该状态是否已经存在等等的方式做幂等。防止因为消息的重复性问题导致数据的错乱。