(1)消息队列概述

本节介绍

从本节开始,将会开启一个新的系列MQ(消息队列),在目前微服务越来越流行的情况下,MQ的使用也越来越广泛了。在这个MQ系列博客里面,将会介绍rabbitmq的安装配置、客户端使用、几种使用方式、与spring及springboot的整合、消息可靠性传输、高可用集群搭建等。本节,会介绍一下消息队列的概念,为什么要使用消息队列,常见的MQ对比等等。

消息

消息(Message) 是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串、JSON 等,也可以很复杂,比如内嵌对象。

消息协议

要想让消息发送者跟接收者都能够知道消息承载了什么信息(消息发送者如何构造发送的消息内容,消息接收者如何解析收到的消息),它们就要按照特定的格式、遵循特定的规范,而这个规范就行消息协议。

常见的消息协议有:MQTT、XMPP、Stomp、AMQP、OpenWire等(也有自定义协议的:Kafka、RocketMQ均使用自定义的协议。),下面对这些常见的消息协议做个简单的介绍,如果您对这些协议有兴趣的话可以找资料详细学习一下。

MQTT

MQTT(Message Queue Telemerty Transport)是一种二进制协议,主要用于服务器和那些低功耗的物联网设备(IoT)之间的通信。 它位于 TCP 协议的上层,除了提供发布-订阅这一基本功能外,也提供一些其它特性:不同的消息投递保(delivery guarantee),“至少一次”和“最多一次”。通过存储最后一个被确认接受的消息来实现重连后的消息恢复。

特点:它非常轻量级,并且从设计和实现层面都适合用于不稳定的网络环境中。

应用场景:物联网(IoT)场景中更适合,支持几乎所有语言进行开发,并且浏览器也可通过 WebSocket 来发送和接收 MQTT 消息。

XMPP

XMPP的前身是Jabber,一个开源形式组织制定的网络即时通信协议。XMPP目前被IETF国际标准组织完成了标准化工作。XMPP基于XML,用于IM系统的开发。国内比较流行的XMPP服务器叫做Openfire,它使用MINA作为下层的网络IO框架(不是MINA2是MINA1);国外用的比较多的XMPP服务器叫做Tigase,它的官网号称单节点可以支撑50万用户在线,集群可以支持100万用户在线:(http://projects.tigase.org/)

优点:通用公开、兼容性强、可扩展、安全性高,但XML编码格式占用带宽大

STOMP

面向流文本的消息传输协议(STOMP,Streaming Text Oriented Messaging Protocol),是 WebSocket 通信标准。在通常的发布-订阅语义之上,它通过 begin/publish/commit 序列以及 acknowledgement 机制来提供消息可靠投递。

特点:协议简单且易于实现,几乎所有的编程语言都有 STOMP 的客户端实现。但是在消息大小和处理速度方面并无优势。由于在许多发布-订阅式的架构中,信息交换是基于文本的,所以许多协议选择简单地将整个信息转化为文本,从而降低复杂性并提高了可读性,当然带来的代价就是需要再消息接受后执行额外的计算任务。

应用场景:信息交换基于文本,要求简单的场景。

典型实现:ActiveMQ以及它的下一代实现Apache Apollo。

AMQP

AMQP(Advanced Message Queuing Protocol ,高级消息队列协议)是比较全面和复杂的一个协议,包括协议本身以及模型(broker、exchange、routing key等概念)。

特点:AMQP 十分可靠且功能强大。当然它及它的实现并不是足够轻量级。

应用场景:当简单的发布-订阅模型不能满足使用要求。

典型实现:RabbitMQ是AMQP消息队列最有名的开源实现。RabbitMQ同时还可以通过插件支持STOMP、MQTT等协议接入。

OpenWire

OpenWire协议在网上没有找到太多的介绍,似乎是activeMQ自己定义的一种协议,官方网站对其的介绍地址为http://activemq.apache.org/openwire.html

消息队列

消息队列中间件(Message Queue Middleware ,简称为MQ) 是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。

消息队列中间件,也可以称为消息队列或者消息中间件。它一般有两种传递模式:点对点(P2P, Point-to-Point) 模式和发布/订阅(Pub/Sub) 模式。点对点模式是基于队列的,消息生产者发送消息到队列,消息消费者从队列中接收消息,队列的存在使得消息的异步传输成为可能。发布订阅模式定义了如何向一个内容节点发布和订阅消息,这个内容节点称为主题(topic) ,主题可以认为是消息传递的中介,消息发布者将消息发布到某个主题,而消息订阅者则从主题中订阅消息。主题使得消息的订阅者与消息的发布者互相保持独立,不需要进行接触即可保证消息的传递,发布/订阅模式在消息的一对多广播时采用。

面向消息的中间件(简称为MOM , Message Oriented Middleware) 提供了以松散藕合的灵活方式集成应用程序的一种机制。它们提供了基于存储和转发的应用程序之间的异步数据发送,即应用程序彼此不直接通信,而是与作为中介的消息中间件通信。消息中间件提供了有保证的消息发送,应用程序开发人员无须了解远程过程调用( RPC) 和网络通信协议的细节。

JMS

提到MQ不得不提JMS,Java消息服务(Java Message Service,JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API(注意:JMS并不是消息队列,它只是定义了一套接口规范),绝大多数MOM提供商都对JMS提供支持。 JMS中的P2P和Pub/Sub消息模式:点对点(point to point, queue)与发布订阅(publish/subscribe,topic)最初是由JMS定义的。这两种模式主要区别或解决的问题就是发送到队列的消息能否重复消费(多订阅)。

JMS是一种与厂商无关的 API,用来访问收发系统消息,它类似于JDBC(Java Database Connectivity)。这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商都支持 JMS,包括 Apache的ActiveMQ、 IBM 的 MQSeries、BEA的 Weblogic JMS service和 Progress 的 SonicMQ等。 JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JMS客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数据组成。消息主体则携带着应用程序的数据或有效负载。根据有效负载的类型来划分,可以将消息分为几种类型,它们分别携带:简单文本(TextMessage)、可序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。

上面是从网上找的一张JMS的对象模型图,关于JMS更细的内容这里不做过多讨论。

为什么要使用消息队列

上面介绍一堆关于MQ的概念,那么问题来了,好端端的我为什么要使用MQ呢?使用MQ有什么好处呢?MQ在不同的应用场景下可以展现不同的作用。总的来说,消息中间件的作用可以概括如下三点:解耦、异步、削峰。下面对这三点分别做下介绍:

1、解耦:比如A系统产生的数据,B、C、D系统都需要A系统的数据,如果用传统的方式,只能A分别给BCD三个系统发送数据,如果新增加一个E系统就要修改A系统,或者如果B系统不要数据了也要修改A系统,这样系统间耦合很严重,A系统的开发维护者要崩溃了啊。

我们可以将A系统的数据写入消息队列,需要A系统数据的下游系统只要订阅消息就行了,如果某个系统不想接受了直接取消订阅就可以了,这样A系统都不用做任何修改。

 2、异步:有些业务操作其实不用立即处理完成,后续慢慢完成就行,这时候可以用到消息队列的异步处理机制。比如电商网站用户注册操作:要写入用户数据,调用短信服务给用户发送短信,调用营销系统给用户发送优惠券。。。。。。假如写入用户DB需要100ms,发送短信需要200ms,发优惠券需要300ms。。。。。。这样要做的操作越多,响应就会越慢,用户体验也会越差。

 其实用户注册操作并不需要立即就发送短信及优惠券等,我们可以将用户数据写入DB之后,发送消息到消息队列,然后就可以返回给前台用户了,这样响应很快,用户体验比较好,后续的任务只要订阅消息然后处理就行了。

3、削峰:在电商系统中,进行商品秒杀时用户请求量会瞬时暴增,这时如果接收请求后直接操作数据库,最终会压垮数据库,最终导致整个系统崩溃掉。

我们可以使用如下方式进行优化,当然了真正的秒杀系统不可能直接把所有的用户请求都写入队列的,会先用redis之类的缓存过滤掉大量的用户请求,只有通过redis预处理成功的用户请求才会写入到消息队列,然后我们的下游系统慢慢拉取队列中的消息进行处理,这种短暂的高峰期的积压是可以接受的。

消息队列常见的使用场景

上面介绍了使用消息队列的好处之后,其实消息队列的使用场景就比较容易理解了。结合使用消息队列的优点,介绍几个常见的使用场景:

  1. 进行系统解耦:在电商系统中的下单扣减库存时,如果按照传统的方式,订单系统将订单数据持久化到数据库之后,一般会通过RPC接口进行远程调用库存系统,这时候如果库存系统挂掉了,将导致下单失败,从而导致订单系统不可用,系统耦合比较严重。我们可以在订单系统中将订单数据持久化到DB之后,发送一条消息到MQ,然后库存系统去拉取消息扣减库存,即使库存系统暂时宕机了,我们的订单系统还是可以正常下单的。
  2. 异步操作:在我们的业务处理过程中,有些操作并不需要立即处理,可以异步进行处理,比如注册之后,给用户发短信等操作,完全可以直接返回给用户,然后异步发送短信,这样给用户的体验也比较好。其实异步操作也可以通过多线程的方式进行处理,但是过多的开启线程会消耗很多的资源,而且线程不好管理,所以我们可以发消息到MQ然后消费消息进行异步处理。
  3. 削峰:应对瞬时大流量请求,比如秒杀,通过消息队列进行缓冲,防止系统被压垮。
  4. 日志处理:通常是用Kafka接收日志,然后结合ELK(Elasticsearch,Logstash,Kibana)进行日志分析处理。
  5. 其他:利用延迟队列的特性,实现订单达到例如24小时未支付自动关闭的功能。

使用消息队列的坏处

问题来了,前面说了一大堆的使用消息队列的好处,那么是不是意味着使用MQ只有好处没有坏处呢?当然不是的,使用消息队列后主要有如下两个缺点:系统复杂性增加、系统可用性降低。

系统复杂性增加:在我们引入消息队列后,我们要考虑很多的问题:怎么保证消息一定发到了队列、怎么保证发过去的消息一定被消费了、怎么知道消息被消费了、怎么让消息不会重复消费、数据一致性问题等等,本来用的好好的,加了消息队列之后会复杂很多。

系统可用性降低:在我们引入消息队列之前,直接通过接口调用就可以完成业务操作,引入了消息队列之后,如果消息队列挂掉了你的系统还能否使用呢?系统可用性自然会降低。

虽然也有坏处,但是大并发量的很多业务场景还是离不开消息队列的,好处是远远大于坏处的,只要我们掌握的足够多,这些坏处都是可以解决的,哈哈!

常用的消息队列对比及技术选型

下面这张图比较了常用的四种消息队列:ActiveMQ,RabbitMQ,RocketMQ,Kafka

关于技术选型,其实没有最好的,只有最合适的,要看消息中间件的功能、性能、可靠性、可用性、运维管理和社区活跃度等方面,具体的还要根据公司的业务需要、系统并发量、开发人员掌握上手难度等进行考虑,下面做下简单的总结:

  1. ActiveMQ:比较老牌的消息中间件,支持的协议较多,功能完善,遵循JMS规范,对队列数较多的情况支持不好。当前更新不太活跃,据说精力都投向了下一代产品apollo,不过还没有新的进展,之前的很多老系统用的都是ActiveMQ。
  2. RabbitMQ:采用erlang语言开发,支持的吞吐量比ActiveMQ高,版本迭代十分活跃,目前互联网公司业务系统中应用较多,如果您所在的公司并发量不是特别高的话推荐使用。
  3. RocketMQ:由阿里开源出来并捐献给Apache,目前已经成为Apache的顶级项目,版本迭代较慢,官网文档也不多,如果您所在公司并发量特别高并且技术人员功力深厚的话,推荐使用。
  4. Kafka:在日志领域应用十分广泛,还有就是一些用于实时计算的数据流转,业务系统一般都不会使用Kafka。

关于消息队列的概要介绍就先到这里,下一节将会介绍一个目前比较流行的消息中间件RabbitMQ。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值