RabbitMQ的消息模型

1.消息队列(MQ,Message Queue)

消息队列里可以存放大量消息,这些消息由生产者生成放到队列里,等待消费者获取并处理。使用消息队列可以提升系统的性能,降低系统耦合性。

比如说,一个发短信的系统。如果不用消息队列,每发送一条短信都要经过-----  需求产生、发送短信。两个步骤。而发送短信这个步骤相对很慢。这样系统性能就会被拖慢。如果把这两个步骤分开,就会极大地提高性能。而消息队列就是这两个步骤的桥梁。让生产者把大量消息存放到消息队列里,然后就可以腾出双手去处理别的事了。消费者就慢慢的去获取消息,处理消息。

把这两个步骤分开,也可以有效降低系统耦合性。因为,就算生产者或消费者崩溃了,也不影响消费者或生产者。

1.1实现MQ的方式

MQ是消息通信的模型,并不是具体实现。现在实现MQ的有两种主流方式:AMQP、JMS。

两者间的区别和联系:

  • JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式

  • JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。

  • JMS规定了两种消息模型;而AMQP的消息模型更加丰富

1.2常见的MQ产品

  • ActiveMQ:基于JMS

  • RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好

  • RocketMQ:基于JMS,阿里巴巴产品,目前交由Apache基金会

  • Kafka:分布式消息系统,高吞吐量

1.3RabbitMQ

rabbitmq是基于amqp协议的。用erlang语言编写。所以安装它时需要erlang环境。

2.RabbitMQ的六种消息模型

2.1基本消息模型

RabbitMQ是一个消息代理:它接受和转发消息。 你可以把它想象成一个邮局:当你把邮件放在邮箱里时,你可以确定邮差先生最终会把邮件发送给你的收件人。 在这个比喻中,RabbitMQ是邮政信箱,邮局和邮递员。

RabbitMQ与邮局的主要区别是它不处理纸张,而是接受,存储和转发数据消息的二进制数据块。

P(producer/ publisher):生产者,一个发送消息的用户应用程序。

C(consumer):消费者,消费和接收有类似的意思,消费者是一个主要用来等待接收消息的用户应用程序

队列(红色区域):rabbitmq内部类似于邮箱的一个概念。虽然消息流经rabbitmq和你的应用程序,但是它们只能存储在队列中。队列只受主机的内存和磁盘限制,实质上是一个大的消息缓冲区。许多生产者可以发送消息到一个队列,许多消费者可以尝试从一个队列接收数据。

我们将用Java编写两个程序;发送单个消息的生产者,以及接收消息并将其打印出来的消费者。我们将详细介绍Java API中的一些细节,这是一个消息传递的“Hello World”。

我们将调用我们的消息发布者(发送者)Send和我们的消息消费者(接收者)Recv。发布者将连接到RabbitMQ,发送一条消息,然后退出。

2.1.1消息确认机制ack

消息一旦被消费者接收,rabbitmq队列就回把消息从队列中删除掉。那么rabbitmq队列怎么知道消息被接收了呢?如果消费者获取一条消息处理时挂掉了呢?消费失败,怎么办呢?

因此要用到ack机制。当消费者获取消息后,会向rabbitmq发送ack确认,告知消息已经被接收。然后rabbitmq就可以吧消息删除掉了。

消费者发送ack有两种方式:

1.自动ack:消息一旦被接收,消费者自动发ack。(默认就是自动ack)

          如果消息不太重要,丢失也没有影响,那么自动ACK会比较方便。

2.手动ack:消息被接收后,用代码手动发送ack。

          如果消息非常重要,不容丢失。那么最好在消费完成后手动ACK,否则接收消息后就自动ACK,RabbitMQ就会把消            息从队列中删除。如果此时消费者宕机,那么消息就丢失了。

2.2work消息模型

工作队列或者竞争消费者模式

一个消息队列,有多个消费者共同消费。又称任务队列。主要思想就是避免执行资源密集型任务时,必须等待它执行完成。相反我们稍后完成任务,我们将任务封装为消息并将其发送到队列。 在后台运行的工作进程将获取任务并最终执行作业。当你运行许多消费者时,任务将在他们之间共享,但是一个消息只能被一个消费者获取

这个概念在Web应用程序中特别有用,因为在短的HTTP请求窗口中无法处理复杂的任务。 请求通过nginx或网关分发tomcat服务器。

问题1:消息堆积

如果生产者产生消息特别快,消费者不能及时消费完,就可能会产生消息堆积,使rabbitmq消息队列内存溢出。如何避免?

1.采用work模型,多个消费者共同监听同一个队列。

2.消费者收到消息后,通过线程池,多线程异步消费消息。

问题2:能者多劳

在work模型中,一个队列可能有多个消费者,假设有两个,其中一个性能很好,处理速度远远高于另一个。如果采用默认配置,消息队列会把队列中所有消息平均分给这两个消费者,这样会使,性能好的长时间处于空闲状态。这样是不行的。应该采用能者多劳的模式。

我们可以使用basicQos方法和prefetchCount = 1设置。 这告诉RabbitMQ一次不要向工作人员发送多于一条消息。 或者换句话说,不要向工作人员发送新消息,直到它处理并确认了前一个消息。 相反,它会将其分派给不是仍然忙碌的下一个工作人员。

2.3订阅模型-Fanout

订阅模型

在之前的模式中,我们创建了一个工作队列。 工作队列背后的假设是:每个任务只被传递给一个工作人员。 在这一部分,我们将做一些完全不同的事情 - 我们将会传递一个信息给多个消费者。 这种模式被称为“发布/订阅”。

一个生产者,生产消息发给交换机(X),交换机再根据条件分发给各个队列,消费者只能消费自己的队列。

Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失

 

订阅模型-Fanout模式,就是最简单的广播模式。

2.4订阅模型-Direct

有选择性的接收。

引入RoutingKey的概念。图中的error、info、warning就是RoutingKey。

每个队列可以绑定多个的RoutingKey。消息绑定一个RoutingKey。

这样消息会被交换机发到RoutingKey匹配的队列中,然后再被消费者消费。

2.5订阅模型-Topic

和direct类似,只不过在RoutingKey中加入了通配符的概念。

有两种通配符,*和#。

`#`:匹配一个或多个词
`*`:匹配不多不少恰好1个词

2.6rpc模型

rpc是指远程调用。客户端发一个请求给远程服务端,让它去执行,然后服务端端再把执行的结果再返回给客户端。rabbitmq通过rpc模型提供一种远程调用的方式。比上面的模型更复杂一些。上面的模型消费者没有返回值。rpc模型里,Server会把返回值放到另一个队列里,等待Client消费。所以C和S既是生产者也是消费者。

3.持久化

消息队列里的消息都是放在内存里的。如果服务器挂掉。队列里的消息会全部丢失。如果消息不容丢失,我们需要持久化它们。

我们必须要将队列、Exchange都持久化。

声明交换机和队列时durable参数置为true。

发送消息时,配置一下消息类型,为持久化的类型。

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值