场景分析
在单应用情况下,同一个进程中,我们可以使用阻塞队列+线程池来实现生产者消费者模式。
比如说在一个应用中,A方法调用B方法去执行一些任务处理。我们可以同步调用。但是如果这个时候请求比较多的情况下,同步调用比较耗时会导致请求阻塞。我们会使用阻塞队列加线程池来实现异步任务的处理。
那么,问题来了,如果是在分布式系统中,两个服务之间需要通过这种异步队列的方式来处理任务,那单进程级别的队列就无法解决这个问题了。
因此,引入了消息中间件,也就是把消息处理交给第三方的服务,这个服务能够实现数据的存储以及传输,使得在分布式架构下实现跨进程的远程消息通信。
所以,简单来说: 消息中间件是指利用高效可靠的消息传输机制进行平台无关的数据交流,并且基于数据通信来进行分布式系统的集成。
消息中间件发展过程
实际上消息中间件的发展也是挺有意思的,我们知道任何一个技术的出现都是为了解决实际问题,这个问题是 通过一种通用的软件“总线”也就是一种通信系统,解决应用程序之间繁重的信息通信工作。最早的小白鼠就是金融交易领域,因为在当时这个领域中,交易员需要通过不同的终端完成交易,每台终端显示不同的信息。如果接入消息总线,那么交易员只需要在一台终端上操作,然后订阅其他终端感兴趣的消息。于是就诞生了发布订阅模型(pubsub),同时诞生了世界上第一个现代消息队列软件(TIB)The information Bus, TIB允许开发者建立一系列规则去描述消息内容,只要消息按照这些规则发布出去,任何消费者应用都能订阅感兴趣的消息。随着TIB带来的甜头被广泛应用在各大领域,IBM也开始研究开发自己的消息中间件,3年后IBM的消息队列IBM MQ产品系列发布,之后的一段时间MQ系列进化成了WebSphere MQ统治商业消息队列平台市场。
包括后期微软也研发了自己的消息队列(MSMQ)
各大厂商纷纷研究自己的MQ,但是他们是以商业化模式运营自己的MQ软件,商业MQ想要解决的是应用互通的问题,而不是创建标准接口来允许不同MQ产品互通。所以有些大型的金融公司可能会使用来自多个供应商的MQ产品,来服务企业内部不同的应用。那么问题来了,如果应用已经订阅了TIB MQ的消息然后突然需要消费IBM MQ的消息,那么整个实现过程会很麻烦。为了解决这个问题,在2001年诞生了 Java Message Service(JMS),JMS通过提供公共的Java API方式,隐藏单独MQ产品供应商的实现接口,从而跨越了不同MQ消费和解决互通问题。从技术层面来说,Java应用程序只需要针对JMS API编程,选择合适的MQ驱动即可。JMS会处理其他部分。这种方案实际上是通过单独标准化接口来整合很多不同的接口,效果还是不错的**,但是碰到了互用性的问题。两套使用两种不同编程语言的程序如何通过它们的异步消息传递机制相互通信呢。这个时候就需要定义一个异步消息传递的通用标准**
所以AMQP(Advanced Message Queuing Protocol)高级消息队列协议产生了,它使用了一套标准的底层协议,加入了许多其他特征来支持互用性,为现代应用丰富了消息传递需求,针对标准编码的任何人都可以和任意AMQP供应商提供的MQ服务器进行交互。
除了JMS和AMQP规范以外,还有一种MQTT(Message Queueing Telemetry[特莱米缺] Transport),它是专门为小设备设计的。因为计算性能不高的设备不能适应AMQP上的复杂操作,它们需要一种简单而且可互用的方式进行通信。这是MQTT的基本要求,而如今,MQTT是物联网(IOT)生态系统中主要成分之一
消息中间件能做什么
消息中间件主要解决的就是分布式系统之间消息传递的问题,它能够屏蔽各种平台以及协议之间的特性,实现应用程序之间的协同。举个非常简单的例子,就拿一个电商平台的注册功能来简单分析下,用户注册这一个服务,不单单只是insert一条数据到数据库里面就完事了,还需要发送激活邮件、发送新人红包或者积分、发送营销短信等一系列操作。假如说这里面的每一个操作,都需要消耗1s,那么整个注册过程就需要耗时4s才能响应给用户。
但是我们从注册这个服务可以看到,每一个子操作都是相对独立的,同时,基于领域划分以后,发送激活邮件、发送营销短信、赠送积分及红包都属于不同的子域。所以我们可以对这些子操作进行来实现异步化执行,类似于多线程并行处理的概念。
如何实现异步化呢?用多线程能实现吗?多线程当然可以实现,只是,消息的持久化、消息的重发这些条件,多线程并不能满足。所以需要借助一些开源中间件来解决。而分布式消息队列就是一个非常好的解决办法,引入分布式消息队列以后,架构图就变成这样了(下图是异步消息队列的场景)。通过引入分布式队列,就能够大大提升程序的处理效率,并且还解决了各个模块之间的耦合问题
Ø 这个是分布式消息队列的第一个解决场景异步处理
我们再来展开一种场景,通过分布式消息队列来实现流量整形,比如在电商平台的秒杀场景下,流量会非常大。通过消息队列的方式可以很好的缓解高流量的问题
Ø 用户提交过来的请求,先写入到消息队列。消息队列是有长度的,如果消息队列长度超过指定长度,直接抛弃
Ø 秒杀的具体核心处理业务,接收消息队列中消息进行处理,这里的消息处理能力取决于消费端本身的吞吐量
当然,消息中间件还有更多应用场景,比如在弱一致性事务模型中,可以采用分布式消息队列的实现最
大能力通知方式来实现数据的最终一致性等等
思考一下消息中间件的设计
可以先从基本的需求开始思考
- 最基本的是要能支持消息的发送和接收,需要涉及到网络通信就一定会涉及到NIO
- 消息中心的消息存储(持久化/非持久化)
- 消息的序列化和反序列化
- 是否跨语言
- 消息的确认机制,如何避免消息重发
高级功能
- 消息的有序性
- 是否支持事务消息
- 消息收发的性能,对高并发大数据量的支持
- 是否支持集群
- 集群节点的数据同步机制
- 消息的可靠性存储
- 是否支持多协议