消息队列探险-1、AMQP与JMS

1 篇文章 0 订阅

一、AMQP:

  ①AMQP概览

    AMQP(Advanced Message Queue Protocol),中文名称为高级消息队列协议,是一个异步消息传递所使用的应用层协议规范。作为线路层协议,而不是API(例如JMS),AMQP客户端能够无视消息的来源任意发送和接受信息。同时,AMQP也不受客户端/中间件的不同产品、不同开发语言等条件的限制。

    AMQP协议是一种二进制协议,提供客户端应用与消息中间件之间异步、安全、高效地交互。从整体来看,AMQP协议可划分为三层:
AMQP分层
    这种分层架构类似于OSI网络协议,可替换各层实现而不影响与其它层的交互。

    AMQP定义了合适的服务器端域模型,用于规范服务器的行为(AMQP服务器端可称为broker)。在这里Model层决定这些基本域模型所产生的行为,这种行为在AMQP中用”command”表示。Session层定义客户端与broker之间的通信(通信双方都是一个peer,可互称做partner),为command的可靠传输提供保障。Transport层专注于数据传送,并与Session保持交互,接受上层的数据,组装成二进制流,传送到receiver后再解析数据,交付给Session层。Session层需要Transport层完成网络异常情况的汇报,顺序传送command等工作。

    消息中间件的主要功能是消息的路由(Routing)和缓存(Buffering)。在AMQP中,提供类似功能的两种域模型:Exchange 和 Message queue。
AMQP与消息中间件
    Exchange接收消息生产者(Message Producer)发送的消息根据不同的路由算法将消息发送往Message queue。Message queue会在消息不能被正常消费时缓存这些消息,具体的缓存策略由实现者决定,当Message queue与消息消费者(Message consumer)之间的连接通畅时,Message queue有将消息转发到consumer的责任。

  ②AMQP模型

    AMQP模型直接影响着所有遵守AMQP的各种实现,在后续各种实现分别的讨论中可以看到其身影。
AMQP模型
    AMQP模型中有几个重要的概念:
      ●Publisher:消息发送者。将消息发送到Exchange并指明Routing Key,以便Message Queue可以正确的收到消息。
      ●Consumer:消息接受者。从Message Queue获取消息,一个Consumer可以订阅多个Queue,来接受Queue中的消息。
      ●Server:一个具体的MQ服务实例。
      ●Virtual host:虚拟主机。一个server下面可以有多个虚拟主机,通常用于隔离不同的项目,一个Virtual host下面通常会有多个Exchange、Message Queue。
      ●Exchange:交换器。从Producer接受消息,根据Bindings中配置的Routing key,把消息分派到对应的Message Queue中。
      ●Routing key:路由键。用于Exchange判断哪些消息需要发送对应的Message Queue。
      ●Bindings:描述了Exchange和Queue之间的关系。Exchange 根据路由键(Routing key)和Binding配置来决定把消息分派到哪个Queue中。
      ●Message Queue:消息队列。存储消息,并把消息传递给最终的 Consumer。

    Message 是当前模型中所操纵的基本单位,它由Producer产生,经过Broker被Consumer所消费。它的基本结构有两部分:Header和Body。Header 是由Producer添加上的各种属性的集合,这些属性由控制Message是否可被缓存、接收的queue是哪个、优先级是多少等信息组成。Body 是真正需要传送的数据,它是对Broker不可见的二进制数据流,在传输过程中不应该受到影响。
    一个Broker中会存在多个Message queue,Exchange怎样知道它要把消息发送到哪个Message queue中去呢? 这就是Binding的作用了。Message queue的创建是由Client application控制的,在创建Message queue后需要确定它来接收并保存哪个Exchange路由的结果。Binding 是用来关联Exchange与Message queue的域模型。Client application控制Exchange与某个特定Message queue关联,并将这个queue接受哪种消息的条件绑定到Exchange,这个条件也叫Binding key或是 Criteria。
    在与多个Message queue关联后,Exchange中就会存在一个路由表,这个表中存储着每个Message queue所需要消息的限制条件。Exchange就会检查它接受到的每个Message的Header及Body信息,来决定将Message路由到哪个queue中去。Message的 Header 中有个属性叫 Routing Key,它是由Message发送者产生,提供给Exchange路由这条Message的标准。Exchange根据不同路由算法有不同有Exchange Type。比如Direct等,需要Binding key等于Routing key;也有Binding key与Routing key符合一个模式关系;也有根据Message包含的某些属性来判断。一些基础的路由算法由AMQP所提供,Client application也允许自定义各种自己的扩展路由算法。
    一个 Virtual Host 可持有一些 Exchange 和 Message queue。它是一个虚拟概念,一个 Virtual Host 可以是一台服务器,也可以是由多台服务器组成的集群。同步扩展下,Exchange 与 Message queue 的部署也可以是一台或是多台服务器上。

    Message 的产生者和消费者可能是不同的应用,也可以是同一个应用。整个 AMQP 定义的就是 Client application 与 Broker 之间的交互。
     在 AMQP 中,Client application 想要与 Broker 沟通,就需要建立起与 Broker 的 connection,这种 connection 其实是与 Virtual Host 相关联的,也就是说,connection 是建立在 client 与 Virtual Host 之间。可以在一个 connection 上并发运行多个 channel,每个 channel 执行与 Broker 的通信,前面提供的 session 就是依附于 channel 上的。
    这里的 Session 可以有多种定义,既可以表示 AMQP 内部提供的 command 分发机制,也可以说是在宏观上区别与域模型的接口。正常理解就是我们平时所说的交互 context,主要作用就是在网络上可靠地传递每一个 command。在 AMQP 的设计中,应当是借鉴了 TCP 的各种设计,用于保证这种可靠性。
    在 Session 层,为上层所需要交互的每个command分配一个唯一标识符(可以是一个UUID),是为了在传输过程中可以对command做校验和重传。Command发送端也需要记录每个发送出去的command到Replay Buffer,以期得到接收方的回馈,保证这个command被接收方明确地接收或是已执行这个command。对于超时没有收到反馈的command,发送方再次重传。如果接收方已明确地回馈信息想要告知command发送方但这条信息在中途丢失或是其它问题发送方没有收到,那么发送方不断重传会对接收方产生影响,为了降低这种影响,command接收方设置一个过滤器Idempotency Barrier,来拦截那些已接收过的command。 关于这种重传及确认机制,可以参考下TCP的相关设计。


二、JMS:

  ①JMS概览

    JMS即Java消息服务(Java Message Service)应用程序接口,是一个 Java 平台中关于面向消息中间件(MOM)的API,用于在两个应用程序间或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。简单的理解:两个应用程序之间需要进行通信,使用一个JMS服务,进行中间的转发,通过JMS 的使用,可以解除两个程序之间的耦合。

    JMS有两大优势:
      ●Asynchronous(异步):JMS is asynchronous by default. So to receive a message, the client is not required to send the request. The message will arrive automatically to the client as they become available.(JMS 默认就是一个异步的消息服务,客户端获取消息的时候,不需要主动发送请求,消息会自动发送给可用的客户端)
      ●Reliable(可靠):JMS provides the facility of assurance that the message will delivered once and only once. You know that duplicate messages create problems. JMS helps you avoiding such problems.(JMS保证消息只会递送一次。大家都遇到过重复创建消息问题,而JMS能帮你避免该问题)

    在JMS中,消息的产生和消费是异步的。JMS的消息者可以通过两种方式来消费消息:
      ●同步(Synchronous):在同步消费信息模式模式中,订阅者/接收方通过调用 receive()方法来接收消息。在receive()方法中,线程会阻塞直到消息到达或者到指定时间后消息仍未到达。
      ●异步(Asynchronous):使用异步方式接收消息的话,消息订阅者需注册一个消息监听者,类似于事件监听器,只要消息到达,JMS服务提供者会通过调用监听器的onMessage()递送消息。

  ②JMS消息模型

    JMS具有两种通信模式:
      ●Point-to-Point Messaging Domain(点对点)
      ●Publish/Subscribe Messaging Domain(发布/订阅模式)
    在JMS API出现之前,大部分产品使用“点对点”和“发布/订阅”中的任一方式来进行消息通讯。JMS定义了这两种消息发送模型的规范,它们相互独立。任何JMS的提供者可以实现其中的一种或两种模型,这是它们自己的选择。JMS规范提供了通用接口保证我们基于JMS API编写的程序适用于任何一种模型。

    1、Point-to-Point Messaging Domain(点对点)

Point to point JMS Messaging
      在点对点通信模式中,应用程序由消息队列,发送方,接收方组成。每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。

      特点:
        ●每个消息只有一个消费者。
        ●发送者和接收者在时间上没有时间的约束,也就是说发送者在发送完消息之后,不管接收者有没有接受消息,都不会影响发送方发送消息到消息队列中。
        ●发送方不管是否在发送消息,接收方都可以从消息队列中取到消息(The receiver can fetch message whether it is running or not when the sender sends the message)。
        ●接收方在接收完消息之后,需要向消息队列应答成功。

    2、Publish/Subscribe Messaging Domain(发布/订阅模式)

Publish Subscribe JMS Messaging
      在发布/订阅消息模型中,发布者发布一个消息,该消息通过topic传递给所有的客户端。该模式下,发布者与订阅者都是匿名的,即发布者与订阅者都不知道对方是谁。并且可以动态的发布与订阅Topic。Topic主要用于保存和传递消息,且会一直保存消息直到消息被传递给客户端。

      特点:
        ●一个消息可以传递给多个订阅者(即:一个消息可以有多个接受方)。
        ●发布者与订阅者具有时间约束,针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。
        ●为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。

  ③JMS模型

JMS模型
    与AMQP类似,JMS模型中也有几个重要的概念:
      ●Connection Factories:创建Connection对象的工厂。针对两种不同的JMS消息模型,分别有QueueConnectionFactory和TopicConnectionFactory两种。可以通过JNDI来查找ConnectionFactory对象。客户端使用一个连接工厂对象连接到JMS服务提供者,它创建了JMS服务提供者和客户端之间的连接。JMS客户端(如发送者或接受者)会在JNDI名字空间中搜索并获取该连接。使用该连接,客户端能够与目的地通讯,往队列或话题发送/接收消息。
      ●Destination:目的地。指明消息被发送的目的地以及客户端接收消息的来源。JMS使用两种目的地:队列和话题。
      ●Connection:Connection表示在客户端和JMS系统之间建立的链接(对TCP/IP socket的包装)。Connection可以产生一个或多个Session。跟ConnectionFactory一样,Connection也有两种类型:QueueConnection和TopicConnection。连接对象封装了与JMS提供者之间的虚拟连接,如果我们有一个ConnectionFactory对象,可以使用它来创建一个连接。
      ●Session:Session 是我们对消息进行操作的接口,可以通过session创建生产者、消费者、消息等。Session 提供了事务的功能,如果需要使用session发送/接收多个消息时,可以将这些发送/接收动作放到一个事务中。
      ●Producter:消息生产者。由Session创建,用于往目的地发送消息。生产者实现MessageProducer接口,我们可以为目的地、队列或话题创建生产者。
      ●Consumer:消息消费者。由Session创建,用于接收被发送到Destination的消息。
      ●Message Listener:消息监听器。如果注册了消息监听器,一旦消息到达,将自动调用监听器的onMessage()。EJB中的MDB(Message-Driven Bean)就是一种Message Listener。


三、AMQP与JMS:

  ①起源:

    ●AMQP 主要是由金融领域的软件专家们贡献的创意,而联合了通讯和软件方面的力量,一起打造出来的规范。(Contributors: JPMorgan Chase Bank & Co., Cisco Systems, Inc., Credit Suisse, Envoy Technologies Inc.,iMatix Corporation,
IONA Technologies, Rabbit Technologies Ltd., Red Hat, Inc., TWIST Process Innovations Ltd, and 29West, Inc.)其诞生的目的是满足金融系统的消息通讯业务需求。
    ●JMS是由Sun公司早期提出的消息标准,旨在为Java应用提供统一的消息操作,包括create、send、receive等。JMS已经成为Java Enterprise Edition的一部分。从使用角度看,JMS和JDBC担任差不多的角色,用户都是根据相应的接口可以和实现了JMS的服务进行通信,进行相关的操作。

  ②定义:

    ●AMQP 同时定义了消息中间件的语意层面和协议层面,并且是语言中立的。允许多种消息协议、多种语言进行通信。
    ●JMS 只允许基于Java实现的消息平台的之间进行通信。

  ③消息模型:

    ●AMQP 提供了五种消息模型:1、direct exchange,2、fanout exchange,3、topic change,4、headers exchange,5、system exchange。本质来讲,后四种和JMS的Pub/Sub模型没有太大差别,仅在路由机制上做了更详细的划分。
    ●JMS 提供了两种消息模型:1、PTP(Point to Point),2、Publish/Subscribe(Pub/Sub)。

  ④支持消息类型:

    ●AMQP 支持byte[],当实际应用时,有复杂的消息,可以将消息序列化后发送。
    ●JMS 支持多种消息类型:TextMessage、MapMessage、BytesMessage、StreamMessage、ObjectMessage、Message(只有消息头和属性)。

  ⑤综合评比:

    ●AMQP 定义了wire-level层的协议标准,天然具有跨平台、跨语言特性。
    ●JMS 定义了Java API层面的标准。在Java体系中,多个client均可以通过JMS进行交互,不需要应用修改代码,但是其对跨平台的支持较差。


四、各MQ产品对比简介

  ①ActiveMQ

ActiveMQ
    ActiveMQ 是Apache出品的、最流行的、能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。

    ActiveMQ特性如下:
      ●多种语言和协议编写客户端。比如:语言:Java、C、C++、C#、Ruby、Perl、Python、PHP等。应用协议:OpenWire、Stomp REST、WS Notification、XMPP、AMQP等。
      ●完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)。
      ●对Spring的支持。ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring的特性。
      ●通过了常见J2EE服务器(如 Geronimo、JBoss 4、GlassFish、WebLogic)的测试。其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上。
      ●支持多种传送协议:in-VM、TCP、SSL、NIO、UDP、JGroups、JXTA。
      ●支持通过JDBC和journal提供高速的消息持久化。
      ●从设计上保证了高性能的集群,客户端-服务器,点对点。
      ●支持Ajax。
      ●支持与Axis的整合。
      ●可以很容易得调用内嵌JMS provider,进行测试。

  ②RabbitMQ

RabbitMQ

    RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是AMQP的标准实现。支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX,持久化。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

  ③Kafka

Kafka
    Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群机来提供实时的消费。

    Kafka有如下特性:
      ●通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。(文件追加的方式写入数据,过期的数据定期删除)
      ●高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万的消息。
      ●支持通过Kafka服务器和消费机集群来分区消息。
      ●支持Hadoop并行数据加载。

  ④RocketMQ

RocketMQ
    RocketMQ是阿里开源的消息中间件,纯Java开发,具有高吞吐量、高可用性、适合大规模分布式系统应用的特点。RocketMQ思路起源于Kafka,但并不是简单的复制,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、消息推送、日志流式处理、binglog分发等场景,支撑了阿里多次双十一活动。

    因为是阿里内部从实践到产品的产物,因此里面很多接口、api并不是很普遍适用。可靠性毋庸置疑,而且与Kafka一脉相承(甚至更优),性能强劲,支持海量堆积。

  ⑤如何选择MQ

    一般的业务系统要引入 MQ,最早大家都用 ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以现在不推荐用了。

    后来大家开始用 RabbitMQ,但是确实 erlang 语言阻止了大量的 Java 工程师去深入研究和掌控它,对公司而言,几乎处于不可控的状态,但是确实RabbitMQ是开源的,比较稳定的支持,活跃度也高。

    现在确实越来越多的公司会去用 RocketMQ,确实很不错,毕竟是阿里出品,但社区可能有突然黄掉的风险(目前 RocketMQ 已捐给 Apache,但 GitHub 上的活跃度其实不算高)对自己公司技术实力有绝对自信的,推荐用 RocketMQ,否则回去老老实实用 RabbitMQ 吧,人家有活跃的开源社区,绝对不会黄。

    所以中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。

    如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。

  更多对比可以参考文章:分布式消息队列差异化总结,太全了!


五、消息队列使用总结:

  ●消息队列不是万能的,对于需要强事务保证而且延迟敏感的业务,RPC是优于消息队列的。
  ●对于一些无关痛痒,或者对于别人非常重要但是对于自己不是那么关心的事情,可以利用消息队列去做。
  ●支持最终一致性的消息队列,能够用来处理延迟不那么敏感的“分布式事务”场景,而且相对于笨重的分布式事务,可能是更优的处理方式。
  ●当上下游系统处理能力存在差距的时候,可以利用消息队列做一个通用的“漏斗”,在下游有能力处理的时候,再进行分发。
  ●如果下游有很多系统关心你的系统发出的通知的时候,可以果断地使用消息队列。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值