消息中间件是什么(非常详细)
MQ(Message Queue)是应用程序与应用程序之间的通信方法,应用程序通过一定规则进行写入队列和读取某队列的消息来实现它们之间的通信。
消息是消息队列中的最小概念,本质上就是一段数据,被一个或者多个应用程序读取,是应用程序之间传递信息的载体。消息队列中涉及 AMQP(Advanced Message Queuing Protocol,高级消息队列协议),AMQF 是一个应用层协议的开发标准,主要是面向消息中间件设计的,具有可靠性和安全性。
消息中间件是分布式系统中的重要组件,主要解决应用解耦、异步消息、流量削峰等问题,实现高性能、高可用、可伸缩和最终一致性架构,主要具有以下特性:
消息中间件何时何地使用、如何使用都是值得思考和实践的,胡乱使用消息中间件不仅会增加系统的复杂度,出问题时还可能导致整个分布式系统瘫痪。
下面将从异步处理、应用解耦、流量削峰和消息通信四个方面介绍消息队列在实际应用中的常用场景。
传统做法有串行和并行两种:
1) 串行方式:将用户注册会员信息成功写入数据库之后,发送系统消息提醒,再发送邮件告知,以上三个步骤全部完成之后将注册结果返回给客户端,如下图所示:
2) 并行方式:将用户注册会员信息成功写入数据库之后,发送系统消息的同时发送邮件告知,以上三个任务完成之后返回给客户端,如下图所示。
3) 引入消息队列中间件:引入消息中间件之后,用户响应时间约为注册会员信息写入数据库的时间,也就是 500ms。因为会员信息入库成功后,将发送系统消息和发送邮件两个任务写入消息队列即可直接返回,写入消息队列速度很快(5ms),基本可忽略,因此用户响应时间约为 500ms,如下图所示:
通过以上分析可知,串行方式完成会员注册功能耗时 1500ms,并行方式耗时 1000ms,所以从一定程度上讲并行方式可以提高任务处理速度。引入中间件之后,系统架构发生改变,响应速度直接提升为 500ms(约数),即业务处理速率大概比串行快 3 倍、比并行快 2 倍。
传统方式导致订单系统和库存系统耦合,如果库存系统异常,导致请求无法访问,则库存更新失败,从而导致用户下单失败,如下图所示。
当系统中引入消息中间件,用户下单,将订单信息写入数据库后,会将该订单任务写入消息队列中,直接返回给用户下单成功。至于库存系统,根据设定的规则从消息队列中读取用户订单信息,然后进行库存更新的业务操作。
即使用户在下单时库存系统异常,无法正常使用,也不会影响用户下单,因为订单的信息已经写入消息队列中,当被对应的消费者消费时该消息才会被移除队列,这样就实现了订单系统和库存系统之间的解耦,如下图所示。
为了解决这个问题,一般会选择在决堤的业务应用之前增加一个消息中间件。当服务器接收到用户下单请求时先将这些请求写入消息队列中,订单系统再从消息队列中读取用户请求信息,有条不紊地进行业务处理,这样就可以控制同时访问订单系统的人数,起到缓存削峰的作用,如下图所示。
目前使用较多的消息中间件有 RabbitMQ、ActiveMQ、Kafka、RocketMQ,下面简要介绍一下这四款产品:
消息是消息队列中的最小概念,本质上就是一段数据,被一个或者多个应用程序读取,是应用程序之间传递信息的载体。消息队列中涉及 AMQP(Advanced Message Queuing Protocol,高级消息队列协议),AMQF 是一个应用层协议的开发标准,主要是面向消息中间件设计的,具有可靠性和安全性。
消息中间件是分布式系统中的重要组件,主要解决应用解耦、异步消息、流量削峰等问题,实现高性能、高可用、可伸缩和最终一致性架构,主要具有以下特性:
- 可靠传输:对于应用系统来说,只要成功把消息提交给消息中间件,关于数据可靠传输的问题就可以交给消息中间件来解决;
- 不重复传输:也就是断点续传的功能,特别适合网络不稳定的环境,节约网络资源;
- 异步传输:发布和接收消息的双方应用不必同时在线,具有脱机能力和安全性;
- 消息驱动:当队列接收到消息后,会主动通知消息接收方;
- 支持事务:目前消息队列也被广泛应用于分布式事务的同步。
消息中间件何时何地使用、如何使用都是值得思考和实践的,胡乱使用消息中间件不仅会增加系统的复杂度,出问题时还可能导致整个分布式系统瘫痪。
下面将从异步处理、应用解耦、流量削峰和消息通信四个方面介绍消息队列在实际应用中的常用场景。
异步处理
假设一个用户需要注册某应用的会员,当注册成功后发送应用的系统消息和邮件告知用户已经注册成功。传统做法有串行和并行两种:
1) 串行方式:将用户注册会员信息成功写入数据库之后,发送系统消息提醒,再发送邮件告知,以上三个步骤全部完成之后将注册结果返回给客户端,如下图所示:

2) 并行方式:将用户注册会员信息成功写入数据库之后,发送系统消息的同时发送邮件告知,以上三个任务完成之后返回给客户端,如下图所示。

3) 引入消息队列中间件:引入消息中间件之后,用户响应时间约为注册会员信息写入数据库的时间,也就是 500ms。因为会员信息入库成功后,将发送系统消息和发送邮件两个任务写入消息队列即可直接返回,写入消息队列速度很快(5ms),基本可忽略,因此用户响应时间约为 500ms,如下图所示:

通过以上分析可知,串行方式完成会员注册功能耗时 1500ms,并行方式耗时 1000ms,所以从一定程度上讲并行方式可以提高任务处理速度。引入中间件之后,系统架构发生改变,响应速度直接提升为 500ms(约数),即业务处理速率大概比串行快 3 倍、比并行快 2 倍。
应用解耦
假设一个商城系统采用分布式架构,即订单、库存、会员等模块为单独系统,当用户下单后会更新订单系统,订单系统再通知库存系统更新该物品的库存信息。传统方式导致订单系统和库存系统耦合,如果库存系统异常,导致请求无法访问,则库存更新失败,从而导致用户下单失败,如下图所示。

当系统中引入消息中间件,用户下单,将订单信息写入数据库后,会将该订单任务写入消息队列中,直接返回给用户下单成功。至于库存系统,根据设定的规则从消息队列中读取用户订单信息,然后进行库存更新的业务操作。
即使用户在下单时库存系统异常,无法正常使用,也不会影响用户下单,因为订单的信息已经写入消息队列中,当被对应的消费者消费时该消息才会被移除队列,这样就实现了订单系统和库存系统之间的解耦,如下图所示。

流量削峰
流量削峰是消息中间件的常用场景,一般用来削减大量请求给系统造成的压力,起到缓存的作用,减轻下游业务系统的压力,比如我们熟知的直播间秒杀活动或双十一淘宝的秒杀活动等。当大量用户在同一时间下单时,用户请求数量短时间内剧增,应用系统很容易挂掉。为了解决这个问题,一般会选择在决堤的业务应用之前增加一个消息中间件。当服务器接收到用户下单请求时先将这些请求写入消息队列中,订单系统再从消息队列中读取用户请求信息,有条不紊地进行业务处理,这样就可以控制同时访问订单系统的人数,起到缓存削峰的作用,如下图所示。

消息通信
消息中间件一般都内置了高效的通信机制,因此可以实现点对点、聊天室和广播等消息通信。1) 点对点通信
客户端 A 和客户端 B 使用同一队列,进行消息通信。如下图所示,客户端 A 向消息队列发布消息,客户端 B 可以直接根据配置的规则获取到客户端 A 发布的消息。
2) 聊天室通信
如下图所示,客户端 A 和客户端 B 同时订阅一个主题,进行消息的发布和接收,实现聊天室的效果。
3) 广播通信
如下图所示,客户端 B、C、D 均订阅某一主题,都能读取到客户端 A 发布的消息。
目前使用较多的消息中间件有 RabbitMQ、ActiveMQ、Kafka、RocketMQ,下面简要介绍一下这四款产品:
- RabbitMQ 是使用 Erlang 编写的一个开源的消息队列,本身支持很多的协议,包括 AMQP、XMPP、SMTP 和 STOMP。正是如此,它的重量级很大,更适合于企业级的开发。同时,它实现了一个经纪人(Broker)构架,意味着消息在发送给客户端时先在中心队列排队,对路由(Routing)、负载均衡(Load balance)或者数据持久化都有很好的支持,是高可用的主从架构。另外,它还支持常用的多种语言客户端,比如 C++、Java、.Net、Python、PHP、Ruby 等。
- ActiviteMQ 是 Apache 下的一个子项目,类似于 ZeroMQ,能够以代理人和点对点的技术实现队列;同时也类似于 RabbitMQ,用少量的代码就可以高效地实现高级应用场景。它也支持常用的多种语言客户端,比如 C++、Java、.Net、Python、PHP、Ruby等。
- Kafka 是 Apache 下的一个子项目,是一个高性能跨语言分布式 Publish/Subscribe 消息队列系统。Jafka 是在 Kafka 之上孵化而来的,即 Kafka 的一个升级版,具有快速持久化、高吞吐、分布式系统自动实现负载均衡、支持 Hadoop 数据并行加载等特性。
- RcoketMQ 是一款低延迟、高可靠、可伸缩、易于使用的消息中间件,支持多种消息协议,如 JMS、MQTT 等,而且支持发布/订阅(Pub/Sub)和点对点(P2P)消息模型。单一的消息队列具备支持百万消息的堆积能力。另外,其还提供 Docker 镜像,用于隔离测试和云集群部署。RcoketMQ 是一款具备非常高的可用性的分布式架构产品。