【消息队列】五个问题详解消息中间件

14 篇文章 4 订阅
10 篇文章 1 订阅

1.消息中间件是什么

消息队列,又叫做消息中间件。是指用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息队列模型,可以在分布式环境下扩展进程的通信(维基百科)。

基于以上的描述(MQ是用来解决通信的问题),我们知道,MQ的几个主要特点:

  • 是一个独立运行的服务。生产者发送消息,消费者接收消费,需要先跟服务器建立连接。
  • 采用队列作为数据结构,有先进先出的特点。
  • 具有发布订阅的模型,消费者可以获取自己需要的消息。

在这里插入图片描述

可以把MQ类比成邮局和邮差,他就是提供消息存储和转发(通信)服务的。

问题:如果仅仅是解决消息消费的问题,Java里面有这么多的队列的实现,为什么不用他们呢?这个问题的答案,就跟有了 HashMap之后,为什么还要Redis 做缓存是一样的。Queue不能跨进程,不能在分布式系统中使用,并且没有持久化机制等等。

2.消息中间件设计思路

2.1 基本需求

  • 最基本的是要能支持消息的发送和接收,需要涉及到网络通信就一定会涉及到NIO
  • 消息中心的消息存储(持久化/非持久化)
  • 消息的序列化和反序列化
  • 是否跨语言
  • 消息的确认机制,如何避免消息重发

2.2 高级功能

  • 消息的有序性
  • 是否支持事务消息
  • 消息收发的性能,对高并发大数据量的支持
  • 是否支持集群
  • 消息的可靠性存储
  • 是否支持多协议

消息存储选择

从主流的几种MQ消息队列采用的存储方式来看,主要会有三种

  1. 分布式KV存储,比如ActiveMQ中采用的levelDB、Redis, 这种存储方式对于消息读写能力要求不高的情况可以使用
  2. 文件系统存储,常见的比如kafka、RocketMQ、RabbitMQ都是采用消息刷盘到所部署的机器上的文件系统来做持久化,这种方案适合对于有高吞吐量要求的消息中间件,因为消息刷盘是一种高效率,高可靠、高性能的持久化方式,除非磁盘出现故障,否则一般是不会出现无法持久化的问题
  3. 关系型数据库,比如ActiveMQ可以采用mysql作为消息存储,关系型数据库在单表数据量达到千万级的情况下IO性能会出现瓶颈,所以ActiveMQ并不适合于高吞吐量的消息队列场景。

总的来说,对于存储效率,文件系统要优于分布式KV存储,分布式KV存储要优于关系型数据库

3.消息中间件发展历程

实际上消息中间件的发展也是挺有意思的,我们知道任何一个技术的出现都是为了解决实际问题,这个问题是通过一种通用的软件“总线”也就是一种通信系统,解决应用程序之间繁重的信息通信工作。

1).TIB:最早的小白鼠就是金融交易领域,因为在当时这个领域中,交易员需要通过不同的终端完成交易,每台终端显示不同的信息。如果接入消息总线,那么交易员只需要在一台终端上操作,然后订阅其他终端感兴趣的消息。于是就诞生了发布订阅模型(pubsub),同时诞生了世界上第一个现代消息队列软件(TIB) The information Bus, TIB允许开发者建立一系列规则去描述消息内容,只要消息按照这些规则发布出去,任何消费者应用都能订阅感兴趣的消息。

在这里插入图片描述

2).WebSphere MQ:随着TIB带来的甜头被广泛应用在各大领域,IBM也开始研 究开发自己的消息中间件,3年后IBM的消息队列IBM MQ产品系列发布,之后的一段时间MQ系列进化成了WebSphere MQ统治商业消息队列平台市场。

3).各种MQ:包括后期微软也研发了自己的消息队列(MSMQ) 各大厂商纷纷研究自己的MQ,但是他们是以商业化模式运营自己的MQ软件,商业MQ想要解决的是应用互通的问题,而不是创建标准接口来允许不同MQ产品互通。所以有些大型的金融公司可能会使用来自多个供应商的MQ产品,来服务企业内部不同的应用。那么问题来了,如果应用已经订阅了TIB MQ的 消息然后突然需要消费IBM MQ的消息,那么整个实现过程会很麻烦。

为什么大家不愿意去创建标准接口?根在微信里不能用支付宝支付一样(商业竞争)

4).JMS:为了解决这个问题,在2001年诞生了 Java Message Service(JMS),JMS通过提供公共的Java API方式,隐藏单独MQ产品供应商的实现 接口,从而跨越了不同MQ消费和解决互通问题。从技术层面来说,Java应用程序只需要针对JMS API编 程,选择合适的MQ驱动即可。JMS会处理其他部分。这种方案实际上是通过单独标准化接口来整合很多不同的接口,效果还是不错的,但是碰到了互用性的问题。两套使用两种不同编程语言的程序如何通过它们的异步消息传递机制相互通信呢。

5).AMQP:这个时候就需要定义一个异步消息传递的通用标准(跨平台,跨语言),所以AMQP(Advanced Message Queuing Protocol)高级消息队列协议产生了,它使用了一套标准的底层协议,加入了许多其他特征来支持互用性,为现代应用丰富了消息传递需求,针对标准编码的任 何人都可以和任意AMQP供应商提供的MQ服务器进行交互。

6).MQTT:除了JMS和AMQP规范以外,还有一种MQTT(Message Queueing Telemetry Transport),它是专门为小设备设计的。因为计算性能不高的设备不能适应AMQP上的复杂操作,它们需要一种简单而且可互用的方式进行通信。这是MQTT的基本要求,而如今,MQTT是物联网(IOT) 生态系统中主要成分之一

注:Kafka,它并没有遵循上面所说的协议规范,它是注重吞吐量,类似udp 和 tcp

4.消息中间件有什么用

消息中间件主要解决的就是分布式系统之间消息传递的问题,它能够屏蔽各种平台以及协议之间的特性,实现应用程序之间的协同

  1. 对于数据量大或者处理耗时长的操作,可以引入MQ实现异步通信,减少客户端的等待,提升响应速度。
  2. 对于改动影响大的系统之间,可以引入MQ实现解耦,减少系统之间的直接依赖。
  3. 对于会出现瞬间的流量峰值的系统,可以引入MQ实现流量削峰,达到保护应用和数据库的目的。

4.1 异步

第一个主要功能,是用来对方法异步处理

举个非常简单的例子,就拿一个电商平台的注册功能来简单分析下,用户注册这一个服务,不单单只是insert一条数据到数据库里面就完事了,还需要发送激活邮件、发送新人红包或者积分、发送营销短信等一系列操作。假如说这里面的每一个操作,都需要消耗1s,那么整个注册过程就需要耗时4s才能响应给用户。

在这里插入图片描述

但是我们从注册这个服务可以看到,每一个子操作都是相对独立的,同时,基于领域划分以后,发送激活邮件、发送营销短信、赠送积分及红包都属于不同的子域。所以我们可以对这些子操作进行来实现异步化执行,类似于多线程并行处理的概念。

如何实现异步化呢?用多线程能实现吗?多线程当然可以实现,只是,消息的持久化、消息的重发这些条件,多线程并不能满足。所以需要借助一些开源中间件来解决。而分布式消息队列就是一个非常好的解决办法,引入分布式消息队列以后,架构图就变成这样了(下图是异步消息队列的场景)

在这里插入图片描述

通过引入分布式队列,就能够大大提升程序的处理效率,并且还解决了各个模块之间的耦合问题。

4.2 解耦

第二个主要的功能,是用来实现系统解耦。

既然说到解耦,那我们要先来了解一下耦合的概念。耦合是系统内部或者系统之间存在相互作用,相互影响和相互依赖。在分布式系统中,一个业务流程涉及多个系统的时候,他们之间就会形成一个依赖关系。

在这里插入图片描述

以12306网站退票为例,在传统的通信方式中,订单系统发生了退货的动作,那么要依次调用所有下游系统的API,比如调用库存系统的API恢复库存,因为这张火车票还要释放出去给其他乘客购买;调用支付系统的API,不论是支付宝微信还是银行卡,要把手续费扣掉以后,原路退回给消费者;调用通知系统API通知用户退货成功。

// 退票的伪代码
public void returnGoods(){
	stockService.updateInventory (); // 更新库存
	payService.refund(); // 退款
	noticeService.notice(); // 发送通知
}

这个过程是串行执行的,如果在恢复库存的时候发生了异常,那么后面的代码都不会执行。由于这一系列的动作,恢复库存,资金退还,发送通知,本质上没有一个严格的先后顺序,也没有直接的依赖关系,也就是说,只要用户提交了退货的请求,后面的这些动作都是要完成的。库存有没有恢复成功,不影响资金的退还和发送通知。

如果把串行改成并行,我们有什么思路?多线程或者线程池是可以实现的,但是每一个需要并行执行的地方都引入线程,又会带来线程或者线程池的管理问题。所以,这种情况下,我们可以引入MQ实现系统之间依赖关系的解耦合

在这里插入图片描述

订单系统只需要把退货的消息发送到消息队列上,由各个下游的业务系统自己创建队列,然后监听队列消费消息。

在这种情况下订单系统里面就不需要配置其他系统的IP、端口、接口地址了,因为它不需要关心消费者在网络上的什么位置,所以下游系统改IP没有任何影响。甚至不需要关心消费者有没有消费成功,它只需要把消费发到消息队列的服务器上就可以了。

这样,我们就实现了系统之间依赖关系的解耦。

4.3 削峰

第三个主要功能,是实现流量削峰,缓解高流量的问题

在很多的电商系统里面,有一个瞬间流量达到峰值的情况,比如京东的 618,淘宝的双11,还有小米抢购。普通的硬件服务器肯定支撑不了这种百万或者千万级别的并发量。

如果通过堆硬件的方式去解决,那么在流量峰值过去以后就会出现巨大的资源浪费。那要怎么办呢?

  • 限流:如果要保护应用服务器和数据库,限流也是可以的,但是这样又会导致订单的丢失,没有达到目的
  • MQ:可以引入MQ,MQ既然是队列,一定有队列的特性:先进先出FIFO。这样就可以先把所有的流量承接下来,转换成MQ消息发送到消息队列服务器上,业务层就可以根据自己的消费速率去处理这些消息,处理之后再返回结果。就像在火车站排队一样,大家只能一个一个买票,不会因为人多就导致售票员忙不过来。如果要处理快一点,大不了多开几个窗口(增加几个消费者)

当然,消息中间件还有更多应用场景,比如在弱一致性事务模型中,可以采用分布式消息队列的实现最大能力通知方式来实现数据的最终一致性等等

5.消息中间件带来的问题

对于一些特定的业务场景,MQ 对于优化系统有很大的帮助。那么,把传统的RPC通信改成MQ通信会带来些问题呢?

  • 系统可用性降低:原来是两个节点的通信,现在还需要独立运行一个服务,如果MQ服务器或者通信网络出现问题,就会导致请求失败。
  • 系统复杂性提高: 为什么说复杂?
    • 使用者必须要理解相关的模型和概念,才能正确地配置和使用MQ。
    • 使用MQ发送消息必须要考虑消息丢失和消息重复消费的问题。一旦消息没有被正确地消费,就会带来数据一致性的问题。

所以,在做系统架构的时候一定要根据实际情况来分析,不要因为这么多MQ能解决的问题,就盲目地引入MQ。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A minor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值