业务背景

leyou的商品详情和搜索服务开发完成之后,发现存在下面的问题:

  • 商品的原始数据保存在数据库中,增删改查都在数据库中完成。
  • 搜索服务数据来源是索引库,如果数据库商品发生变化,索引库不能及时更新
  • 商品详情做了页面静态化,静态页面数据也不会随着数据库商品发生变化

如果在后台修改了商品的价格,搜索页面和商品详情页面显示的依然是旧的价格,显然不对,该如何解决?

解决方案:

  • 商品服务对商品增删改以后,无需去操作索引库或静态页面,只是发送一条消息,也不关心消息被谁接收。
  • 搜索服务和静态页面服务接收消息,分别去处理索引库和静态页面

消息队列,即MQ,MessageQueue

MQ全称为Message Queue,消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接他们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如 远程过程调用 的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。
其中较为成熟的MQ产品有  IBM WEBSPHERE MQ等。

消息队列是典型的:生产者,消费者模型。
生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦。

AMQP和JMS
MQ是消息通信的模型,并不是具体实现,java中实现 MQ的有两种流行方式:AMQP,JMS。

AMQP:(Advanced Message Queuing  Protocol)一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
Erlang 中的实现有RabbitMQ等。

JMS:(Java MessageService)实际上是指JMS API。JMS是由Sun公司早期提供的消息标准,是为了给Java应用提供统一的消息操作,包括create,send,receive等。
JMS已经成为java Enterprise Edition的一部分,从使用角度看,JMS和JDBC 担任差不多的角色,用户都是根据相应的接口可以和实现了JMS的服务进行通信,进行相关的操作。

常见的MQ产品
    • ActiveMQ:基于JMS
    • RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好
    • RocketMQ:基于JMS,阿里巴巴产品,目前交由Apache基金会
Kafka:分布式消息系统,高吞吐量

RabbitMQ是一个消息代理:它接受和转发消息。可以把它想象成一个邮局:当你把邮件放在邮箱里时,你可以确定邮差先生最终会把邮件发送给你的收件人。RabbitMQ是邮政信箱,邮局和邮递员。
RabbitMQ与邮局的主要区别是它不处理纸张,而是接受,存储和转发数据消息的二进制数据块。

RabbitMQ消息队列

P(producer):生产者,一个发送消息的用户应用程序
C(consumer):消费者,消费和接收有类似的意思,消费者是一个主要用来等待接收消息的用户应用程序。
队列(红色区域):rabbitMQ内部类似于邮箱的一个概念。虽然消息流经rabbitMQ和应用程序,但是他们只能存储在队列中。队列只受主机的内存和磁盘限制,实质上是一个大的消息缓冲区。
许多生产者可以发送消息到一个队列,许多消费者可以尝试从一个队列中接收消息。

总之:生产者将消息发送到队列,消费者从队列中获取消息,队列是存储消息的缓冲区。

1、发布订阅fanout

工作队列背后的假设是:每个任务只被传递给一个工作人员。
发布/订阅:传递一个信息给多个消费者。
订阅模型示意图:

RabbitMQ消息队列

    1. 一个生产者,多个消费者
    2. 每一个消费者都有自己的一个队列
    3. 生产者没有将消息直接发送到队列,而是发送到了交换机
    4. 每个队列都要绑定到交换机
    5. 生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者获取的目的。
    
X(Exchanges):交换机一方面:接收生产者发送的消息。另一方面:知道如何处理消息,例如递交给某个特别的队列,递交给所有队列,或是将消息丢弃。具体如何操作,取决于Exchange的类型。
Fanout:即广播模式
Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失。

2、订阅模型-Direct

有选择性的接收消息
在订阅模式中,生产者发布消息,所有消费者都可以获取所有消息。
在路由模式中,只能订阅一部分消息。
例如:我们只能将重要的错误消息引导到日志文件(以节省磁盘空间),同时仍然能在控制台上打印所有的日志消息。

在某些场景下,我们希望不同的消息被不同的队列消费。这时要用到Direct类型的Exchange。
在Direct模型下,队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)
消息的发送方在向Exchange发送消息时,也必须指定消息的routing key

RabbitMQ消息队列

P :生产者,向Exchange发送消息,发送消息时,会指定一个routing key
X :Exchange(交换机),接收生产者的消息,然后把消息递交给routing key完全匹配的队列
C1:消费者,其所在队列指定了需要routing key 为error的消息
C2:消费者,其所在队列指定了需要routing key 为info error warning的消息

3、订阅模型-Topic

Topic类型的Exchange与Direct相比,都是可以根据routingkey 把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key的时候使用通配符。
Routingkey 一般都是有一个或多个单词组成,多个单词之间以 “.”分割。
例如:item.insert

RabbitMQ消息队列

如何避免消息丢失?——持久化

消费者的ACK确认机制,可以防止消费者丢失信息。但是如果在消费者消费之前,MQ就宕机了,消息就没了。要将消息持久化,前提是:队列,Exchange都持久化。

几种模型的整理

RabbitMQ消息队列

 

相关文章:

  • 2021-03-31
  • 2021-12-02
  • 2022-01-02
  • 2018-11-14
猜你喜欢
  • 2022-12-23
  • 2021-12-02
  • 2021-12-23
  • 2021-08-03
  • 2021-09-23
相关资源
相似解决方案