MQ的那些事儿——第一季

Java基础

浏览数:73

2020-5-30


ActiveMQ的破壳日

时间回到2003年,一群开源开发者集合在一起形成了Apache Geronimo。之后,他们发现当前没有好用的使用BSD-style许可协议的消息代理器。Geronimo是由于java EE兼容性需要一个JMS实现。所以一些开发者开始讨论其可能性。拥有丰富MOMs经验甚至自己创建过一些MOMs的这些开发者开始创建下一个伟大的开源消息代理。ActiveMQ这么快开始是因为当时市场上大多数的MOMs是商业,闭源而且购买和支持昂贵。市场上的MOMs已经广泛地被使用,但是一些商业行为是买不起如此昂贵的软件。这使得创建一个开源MOMs的需求更加大。很明显,有一个市场急需一个开源的使用Apache License的MOM。最终就导致了Apache ActiveMQ的诞生。

松耦合的MQ

ActiveMQ提供松耦合的应用架构。松耦合一般是为了减轻经典RPC(Remote Procedure Calls)调用的紧耦合架构而被引入的。该松耦合以异步形式存在,任何一个应用对ActiveMQ的调用不依赖于任何其它应用,没有任何依赖或者时序要求。应用依赖于ActiveMQ的能力保证消息传递。因此,我们把应用发送消息的形式称之为触发和忘记(fire-and-forget)–应用发送消息到ActiveMQ之后并不关心消息如何或者什么时候被传递。同样的消息的接收者也不关心消息从哪里或者如何到来。在不同的环境中这样做的好处是允许客户端使用不同的语言编写甚至使用不同的线路协议。ActiveMQ作为中间人存在,允许不同环境的集成和异步交互。

经典RPC部署

      当我们考虑分布式应用设计时,耦合是很重要的。耦合是指两个或多个应用间的相互依赖。考虑耦合的一个简单办法是思考其中某个应用改变所产生的影响,即其它应用所需要作出的改变。是否一个应用的变化会强制其它应用跟着改变?如果答案是肯定的,则这些应用是紧耦合的。如果一个应用的变化无需强制其它应用跟着改变,则这些应用是松耦合的。这说明了紧耦合系统比松耦合系统更难维护。也就是说,松耦合系统更能适应未知的变化。

      使用RPC,当一个应用调用另一个应用,调用者将被阻塞直到被调用者返回结果。上图描述了这个过程。

      但是对于这样一个紧耦合系统确实有很多缺点:最显著的缺点是,即使很小的一个改变都要较高的维护代价;正确的时机也很重要,当请求从应用1发到应用2时,两个系统都必须正常工作,同样的,响应从应用2发送到应用1时,两个系统也必须正常工作。这样的时序要求有点麻烦,使得系统稳定性降低。

经典MQ部署

      现在我们把这个紧耦合系统和MOM系统进行比较。

      应用1发送消息到MOM只是一个单方行为。可能一段时间后,应用2从MOM接收消息,这也是一个单方行为。任何一方都不需要知道另一方的存在,它们之间也没有任何时序要求。所以在分布式系统设计时,松耦合系统比紧耦合系统有巨大的优势。如图所示,这就是ActiveMQ存在的地方。

      考虑现在其中的一个应用必须搬到一个新的地方。这可能在新硬件引入或应用需要移动时发生。如果是一个紧耦合系统,这样的迁移会很困难,因为系统的其它部分都必须停止工作等待迁移完成。如果是松耦合系统,系统的各个部分能够自由迁移而不影响其它部分。考虑这样一个场景,应用A和B各有很多个实例,其中各个实例分布在不同的机器上。ActiveMQ安装在另外的机器上。在这种情况下,任何一个应用实例都可以自由移动而不影响其它应用。事实上,多个ActiveMQ实例也可以通过network of brokers配置联合使用。这就允许ActiveMQ实例自由迁移而不影响应用A或应用B。采用这种价构,系统的任何一部分在任何时间都可以停机进行维护而不影响整个系统。

When ActiveMQ

  • 不同语言应用集成
  • RPC的替代者
  • 应用间解耦
  • 作为事件驱动架构的骨架
  • 提高系统扩展性

ActiveMQ features

  • JMS compliance
  • Connectivity
  • Pluggable persistence and security
  • Building messing applications with JAVA
  • Integration with application servers
  • Client APIs
  • Broker clustering
  • Many advanced broker features and client options
  • Dramatically simplified administration

一条消息的生命周期

图片中简单的描述了一条消息的生命周期,一条消息从producer端发出之后,一旦被broker正确保存,那么它将会被consumer消费,然后ACK,broker端才会删除;不过当消息过期或者存储设备溢出时,也会终结它。

消息传送机制

消息消费的两种方式

queue主要用于多个客户端形成一个消费者组去订阅一个类型的消息,生产者生产的消息最后会被组内的一个客户端消费;topic主要用于不同的系统(订阅者)同时对一个(一组)消息感兴趣,因此每个订阅者都会拿到一个消息的拷贝进行处理。

存在的问题

怎么解决系统之间关心同样的消息,同时系统内部又想达到负载和故障转移的目的?

解决方案

分布式锁

优点:1. 简单易开发。

缺点:1. 依赖第三方服务。2. 需要业务上支持重复消息的检测过滤。

复合目的地

优点:1. 可以同时发布消息到topic和queue。

缺点:2. 发布者需要关心订阅者的位置。2. 需要修改mq配置。3. 每次新加一个主题或queue就要改mq配置。

虚拟主题

优点:1. 虚拟主题定义方式灵活,可以使用VirtualTopic前缀(缺点是发布者/订阅者都要修改,优点是不需要修改mq配置);也可以在修改mq配置(优点是发布者和部分订阅者不需要修改,缺点是修改mq配置)。2. 不关心或者不想用队列的订阅者不用做任何改动。3. 可以通过通配符来修改某些符合命名规则的主题为虚拟主题。

缺点:1. 需要修改mq配置。但是通过配置文件不需要发布者做任何改动。(发布者改动可能影响所有订阅者,因此只修改订阅者成本小。)

如果想了解更多,请看:https://my.oschina.net/noryar/blog/1575431

作者:noryar