器 | 消息中间件前世今生(一)

说起消息中间件,都不会陌生,对它的称呼,平时听的最多还是消息队列。不管有没有在实际项目中用到过它,但你一定曾经见到或曾用过队列queue,说起队列,你会想到是一种数据结构,满足先进先出的原则,跟我们生活中排队场景是很相似。在队列的基础上,再去谈消息队列,一切都会容易理解的多。本篇文章会介绍消息中间件产生的历史、解决的实际工程问题、引入它带来的问题、常见消息中间件对比以及如何选型。

一、诞生的历史

故事的开始,发生在1983年的美国。一位在MIT工作搞硬件设计教育的印度小伙子Vivek Ranadivé突发奇想,能不能像主板上的总线BUS那样,设计出一种通用的软件总线,专门用来通信,把不同的软件集成起来。这位小伙行动力很强,撸起袖子就是干。

于是乎他成立了一家公司Teknekron,开发了世界上第一个消息队列软件The Information Bus(TIB)。这个公司的软件很快引起了高盛的注意,不久后,高盛作为第一批用户在金融交易中使用了Teknekron的软件。由于TIB它实现了一个发布订阅模型,信息的生产者和消费者可以实现完全解耦,只要消息按照特定的规则发布出去,任何消费者都可以订阅感兴趣的消息。这个特性引起了电信行业特别是新闻机构的注意,在1994年路透社收购了 Teknekron

随着TIB的成功,消息队列很快在行业中激起了千层浪。那个时代,业界大佬有IBM,微软等,他们很快先后依次研发了IBM MQ(IBMWesphere)MSMQ。这个时候各个产商的消息队列都是独立开发的,在技术上没有共通性,每个产品定义的协议、API都不同,这样的情况对于终端的开发者来说,实在是痛苦。那么为什么各个厂商不联合起来,制定一套协议规范呢?

当然,肯定有大佬想到了。时间来到了2001年,Sun公司敢为天下先,发布了一套JMS规范。它想要在各大厂商的MQ上面统一包装一层Java的规范,大家都只需要针对API编程就可以了,不需要关注使用了什么样的消息中间件,只要选择合适的 MQ 驱动。但可惜了,JMS只是支持java语言,而且本身只是一个API,局限性很高,没有从根本上解决问题。

后来,在2006年,AMQP(Advanced Message Queuing Protocol)规范横空出世。它是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。它是跨语言和跨平台的,真正地解决了消息队列大乱斗的混乱场面,促进了消息队列的繁荣壮大。

再后来,在不同的业务场景,规范如雨后春笋,都冒出来了。比如:

  • MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。
  • STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。
  • XMPP(可扩展消息处理现场协议,Extensible Messaging and Presence Protocol)是基于可扩展标记语言(XML)的协议,多用于即时消息(IM)以及在线现场探测
  • 其他基于TCP/IP自定义的协议

实现这些协议也产生了多式多样的消息队列,应用比较广泛的有RocketMQRabbitMQKafkaZeroMQRedisActiveMQ等。后续再详细对比它们。

二、为什么要使用消息队列?

上一部分讲到了消息队列的历史,这一部分来讲讲为什么要引入使用消息队列。引入消息队列,核心提供三种能力,分别是异步、解耦、削峰。当然,还要一些其它能力,包括顺序处理、可恢复性、可扩展性等等。

2.1 异步通信

说起异步通信,那要先来说说同步通信,同步通信就是发起调用后,除非异常或者超时,请求会一直阻塞等待结果。异步通信正好相反,发起请求调用后就直接返回了,不会一直阻塞等到结果。一般来说在调用发出后,被调用者会通过状态、通知来通知调用者,或更常见的是通过回调函数处理这个调用。

同步

同步.png

异步

异步.png

举个场景,我们用手机App购买电影票的时候,当我们支付成功,下单完成后,有时候会提示3-5分钟内出票。因为下单完成后会把出票的消息通知到消费队列就不管了。出票消费服务因为订阅了出票的消息,会依次去消费消息队列的出票通知。

所以消息队列的提供的异步通信,总的来说是允许把一个消息放到消息中间件,但是不立即处理它。想往消息队列放多少消息就放多少消息,需要的时候再去处理。

2.2 系统解耦

说到解耦,先说什么是耦合,耦合是系统内部或者系统之间存在相互作用,相互影响和相互依赖。这种具有强依赖的关系就是耦合。举个简单的例子,用户在商城购买商品完成支付后,需要通知库存服务,支付服务,订单服务等。这些服务之间操作没有绝对的前后依赖性。如果我们强制要求要先通知库存服务,再通知支付服务,这个就是耦合。如果放开限制,就是解耦。 耦合

耦合.png

解耦

解耦.png

解决系统上的解耦,除了消息队列,当然还有其它的解决办法。我们能想到的有多线程并发解决,使用这个方案去解决耦合,会有一个明显的问题,那就是线程是服务器很宝贵资源,势必要引入线程池来进行管理。还有一个问题就是使用多线程并发去解决耦合只能解决单机环境环境上的解耦。对于是引入多线程去解耦还是使用消息队列去解耦,这个要根据实际生产环境去判定,没有哪个是绝对的好。

2.3 流量削峰

很多电商的场景(比如秒杀),会有一个瞬间达到流量的顶峰,随之开始降低,趋于合理范围内的稳定。这种瞬时的高峰流量常常会导致系统的崩溃,带来一些无法想象的后果。

要解决这种峰值流量,很常见能想到的解决方案就是堆积服务器资源。确实,足够多的服务器资源是能解决问题,但是流量峰值过去以后就会出现巨大的资源浪费。并且叠加资源并不是简单的1+1=2,很多方方面面的瓶颈都需要考虑,比如数据库的连接等。

在软件层面,就可使用消息队列解决这个问题。消息队列是一个队列,满足先进先出的原则。自然我们可以通过消息队列承接所有的请求,这样的过程可以理解用蓄水池去蓄水。业务层就可以根据自己的消费速率去处理这些消息,处理之后再返回结果。就如同蓄水池的例子,蓄水池的消费方可以根据需求选择调整合适的流量。

削峰

削峰.png

三、什么场景用消息队列?

很多业务场景不是直接使用一个消息队列就能解决问题,消息队列不是万金油。引入它也会带来一些问题。在一个系统中,新引入一个服务,降低了整体可用性,增加了系统的复杂性,势必要多花人力和精力去维护它。那什么场景下使用消息队列呢?

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

所以总的来说,我们要根据实际的业务场景来选择是否要引入消息队列。不能因为MQ能帮我们解决问题拿来就直接用,要评估手上的资源,分析利弊,判断是否有更好的方式。最后分析得出结论,再抉择也不迟。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值