【分布式系统】4.分布式系统之消息队列

1.消息队列

       在分布式系统中,消息系统的应用十分广泛,消息可以作为应用间通信的一种方式,消息被保存在队列中,直到被接收者取出,由于消息发送者不需要同步等待消息接收者的响应,消息的异步接收降低了系统集成的耦合度,提升了分布式系统协作的效率,使得系统能够更快的响应用户,提供更高的吞吐,当系统处于峰值压力时,分布式消息队列还能够作为缓冲,削峰填谷,缓解集群的压力,避免整个系统被压垮
       开源的消息系统有很多,包括apache的ActiveMQ,apache的Kafka,RabbitMQ,memcacheQ等等。。。

2.消息队列-JMS

       JMS(Java Message Service,即Java消息服务)是J2EE提出消息服务规范,它是一组java应用程序接囗,它提供消息的创建、消息的发送、消息接收、消息读取等等一系列服务。JMS定义了一组公共应用程序接口和相应的语法,类似于java数据库的统一访问接囗JDBC,它是一种与厂商无关的API,使得java程序能够很好的与不同厂商的消息组件进行通信。
       JMS支持的消息类型包括:简单文本(TextMessage)、可序列化的对象(ObjectMessage)、键值对(MapMessage)、字节流(BytesMessage)、流(StreamlMessage),以及无有效负载的消息(Message)等等。消息的发送是异步的,因此,消息的发布者发送完消息之后,不需要等待消息接收者立即响应,这样便提高了分布式系统协作的效率。

2.1 JMS消息模型

       JMS支持两种消息发送和接收模型,一种称为Point-to-Point(P2P)模型,即采用点对点的方式发送消息,P2P模型是基于queue(队列)的,消息生产者发送消息到队列,消息消费者从队列中接收消息,队列的存在,使得消息的异步传输称为可能,P2P模型在点对点的情况下进行消息传递时采用。另一种为pub/sub(Publish/Subscribe,即发布/订阅)模型,发布/订阅模型定义了如何向一个内容节点发布和订阅消息,这个内容节点称为topic(主题),主题可以认为是消息传递的中介,消息发布者将消息发布到某个主题,而消息订阅者则从主题订阅消息,主题使得消息的订阅者与消息的发布者互相保持独立,不需要进行接触即可保证消息的传递,发布/订阅模型在消息的一对多广播时采用。

2.2  点对点模型

       多个消息的生产者和消息的消费者都可以注册到同一个消息队列,当消息的生产者发送一条消息之后,只有其中一个消息消费者会接收到消息生产者所发送的消息,而不是所有的消息消费者都会收到该消息。

2.3 发布/订阅模型

        对于发布/订阅的消息传输模型来说,消息的发布者需将消息投递给topic,而消息的订阅者则需要在相应的topic进行注册,以便接收相应topic的消息,与点对点消息传输模型不同的是,消息发布者的消息将被自动发送给所有订阅了该topic的消息订阅者。当消息订阅者某段时间由于某种原因断开了与消息发布者的连接时,这个时间段内的消息将会丢失,除非将消息的订阅模式设置为持久订阅(durable subscription),这时,消息的发布者将会为消息的订阅者保留这部分时间所产生的消息,当消息的订阅者重新连接消息发布者时,消息订阅者仍然可以获得这部分消息,而不至于这部分消息丢失。

2.4 JMS的模型的限制

2.5 实际应用消息队列

   大型分布式系统对于消息系统的需求:
      1.消息发送和消息接收都是集群
      2.同一个消息的接收方可能有多台机器甚至是多个集群
   来进行消息的处理
      3.不同集群对于同一条消息的处理都不能相互干扰

        具体来说,我们可以把集群和集群之间对消息的消费当做topic模型来处理,而集群内部的各个具体应用实例对消息的消费当做queue模型来处理,我们可以引入groupid,用这个id来标识不同的集群,而集群内的各个应用实例的连接使用同样的groupid,当服务器进行调度时,根据groupid进行连接分组,在不同的groupid之间保障消息的独立投送,而拥有同样groupid的连接则共同消费这些信息。
        这个策略分两级来进行处理,把topic模型和queue模型的特点结合起来使用,从而达到多个不同的集群进行消息订阅的目的。当然,抛弃JMS意味着我们可能需要自己实现连接的管理、消息创建、消息发送、消息接收、消息读取等一系列接囗。

2.6 持久订阅和非持久订阅

2.7 如何保证消息的一致性

第一种方式

业务处理代码:
  function){
      //务操作
      //调用服务,将数据写入数据库
      //发送消息

}

1.业务操作在前,发送消息在后,如果业务失败还行,如果业务成功,此时系统宕机,消息则发送失败
2.如果业务成功,应用也正常,此时消息系统宕机,消息没收到,也会导致消息收不到

第二种方式

另外一种业务代码的写法:
function){
/∥发送消息
∥业务操作
/调用服务或者写数据库
这种方式更不靠谱,业务如果失败,消息却已经发出。
真正的生产环境,第一种做法丢失消息的比例相对来说是很低的,但是,对于必须保证一致性的场景下,比如跟交易相关的业务操作,这两种方案都不能接受。

发布了264 篇原创文章 · 获赞 347 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/jia970426/article/details/105007342