大家好,我是民工哥!
在这之前,我们相继卷完了:关系型数据库 MySQL 、 NoSQL 数据库 Redis 、 MongoDB 、搜索引擎 ElasticSearch 、大数据 Hadoop框架、PostgreSQL 数据库、消息中间件 Kafka、分布式协调中间件 Zookeeper 这些系列的知识体系。今天开始,我们将踏上另一个中间件学习之路:RabbitMQ!
MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是 message 而已,还是一种跨进程的通信机制,用于上下游传递消息。在互联网架构中,MQ 是一种非常常见的上下游 “逻辑解耦+物理解耦” 的消息通信服务。使用了 MQ 之后,消息发送上游只需要依赖 MQ,不用依赖其他服务。
以12306为例,假设平时可能买票的人不多,所以订单系统的QPS( 每秒查询率 )也不是很高,每秒也就处理1000个请求,但是一到节假日、春运期间可能抢票的人就非常多,并发量远远大于平时,这个时候,订单系统明显扛不住了。怎么办呢,当然我们可以设计弹性伸缩的集群,进行机器扩容,保证高可用。但是我们依然可以采用MQ来解决这个问题。
所以我们可以设计高可用的MQ,让所有的请求都到MQ,缓存起来。这样一来高峰期的流量和数据都将积压在MQ中,流量高峰就被削弱了(削峰),然后我们的订单系统就避免了高并发的请求,它可以慢慢的从MQ中拉取自己能力范围内的消息就行处理。这样一来,高峰期积压的消息也终将被消费完,可以叫做填谷。
我购买车票成功后,会收到信息提醒,但是如果短信系统故障了,客户就有可能收到不短信了,这就是各个系统之间的耦合太高了,我们应该解耦。
我们在订单系统产生数据后,将订单这条数据发送给MQ,就返回成功,然后让短信、邮件等系统都订阅MQ,一旦发现MQ有消息,他们主动拉取消息,然后解析,进行业务处理。这样一来,就算你短信系统挂了,丝毫不会影响其他系统,而且如果后来想加一个新的系统,你也不用改订单系统的代码了,你只要订阅我们的MQ提供的消息就行了。
不用MQ,那么我们的代码必然耦合在一起,下单成功后,依次要通过RPC远程调用这几个系统,然后同步等到他们的响应才能返回给用户是否成功的结果。假设每个系统耗时200ms,那么就得花费600ms。
所以这个逻辑我们可以设计成异步的。我们可以当下单成功后,只需要将订单消息发给MQ,然后立即将结果返回通知客户。这才是正确的打开姿势。这样一来,我订单系统只需要告诉你MQ,我下单成功了,其他模块收到消息后,该发短信的发短信,发邮件的发邮件。因为本来MQ的性能就很好,所以这个效率一下就提升了。
更多关于消息中间件 RabbitMQ 系列的学习文章,请参阅:消息中间件 RabbitMQ ,本系列持续更新中。
前面已经详细介绍过了有关Kafka技术的知识体系,从今天开始学习有关RabbitMQ的知识体系。
RabbitMQ是由erlang语言开发,基于AMQP协议实现的消息队列,它是一种应用程序之间的通信方法,消息队列在分布式系统开发中应用非常广泛。
RabbitMQ 是一个消息中间件:它接受并转发消息。
你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放到快递站,快递员最终会把你的快递送到收件人那里,按照这种逻辑 RabbitMQ 是 一个快递站,一个快递员帮你传递快件。
RabbitMQ 与快递站的主要区别在于,它不处理快件而是接收, 存储和转发消息数据。
生产者:产生数据发送消息的程序是生产者
交换机:交换机是 RabbitMQ 非常重要的一个部件,一方面它接收来自生产者的消息,另一方面它将消息 推送到队列中。交换机必须确切知道如何处理它接收到的消息,是将这些消息推送到特定队列还是推 送到多个队列,亦或者是把消息丢弃,这个得有交换机类型决定
队列:队列是 RabbitMQ 内部使用的一种数据结构,尽管消息流经 RabbitMQ 和应用程序,但它们只能存 储在队列中。队列仅受主机的内存和磁盘限制的约束,本质上是一个大的消息缓冲区。许多生产者可 以将消息发送到一个队列,许多消费者可以尝试从一个队列接收数据。这就是我们使用队列的方式
消费者:消费与接收具有相似的含义。消费者大多时候是一个等待接收消息的程序。请注意生产者,消费 者和消息中间件很多时候并不在同一机器上。同一个应用程序既可以是生产者又是可以是消费者。
Broker:接收和分发消息的应用,RabbitMQ Server 就是 Message Broker。
Virtual host:出于多租户和安全因素设计的,把 AMQP 的基本组件划分到一个虚拟的分组中,类似 于网络中的 namespace 概念。当多个不同的用户使用同一个 RabbitMQ server 提供的服务时,可以划分出 多个 vhost,每个用户在自己的 vhost 创建 exchange/queue 等。
Connection:publisher/consumer 和 broker 之间的 TCP 连接。
Channel:如果每一次访问 RabbitMQ 都建立一个 Connection,在消息量大的时候建立 TCP Connection 的开销将是巨大的,效率也较低。Channel 是在 connection 内部建立的逻辑连接,如果应用程 序支持多线程,通常每个 thread 创建单独的 channel 进行通讯,AMQP method 包含了 channel id 帮助客 户端和 message broker 识别 channel,所以 channel 之间是完全隔离的。Channel 作为轻量级的 Connection 极大减少了操作系统建立 TCP connection 的开销。
Exchange:message 到达 broker 的第一站,根据分发规则,匹配查询表中的 routing key,分发 消息到 queue 中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。
Queue:消息最终被送到这里等待 consumer 取走。
Binding:exchange 和 queue 之间的虚拟连接,binding 中可以包含 routing key,Binding 信息被保 存到 exchange 中的查询表中,用于 message 的分发依据。
AMQP(高级消息队列协议)是一个网络协议。它支持符合要求的客户端应用(application)和消息中间件代理(messaging middleware broker)之间进行通信。主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP是协议,类比HTTP。
JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的 API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。JSM是API接口规范,类比JDBC。更多关于消息中间件 RabbitMQ 系列的学习文章,请参阅:消息中间件 RabbitMQ ,本系列持续更新中。
RabbitMQ提供了7种模式:
AMQP模型中,消息在producer中产生,发送到MQ的exchange上,exchange根据配置的路由方式投递到相应的Queue上,Queue又将消息发送给已经在此Queue上注册的consumer,消息从queue到consumer有push和pull两种方式。
消息队列的使用过程大概如下:
exchange接收到消息后,根据消息的key和以及设置的binding,进行消息路由,将消息投递到一个或多个消息队列中。
RabbitMQ支持数据持久化,也就是把数据写在磁盘上,可以增加数据的安全性。消息队列持久化包括三个部分:
如果消息交换机(exchange)和消息队列(queue)都是持久化的话,那么他们之间的绑定(Binding)也是持久化的。如果消息交换机和消息队列之间一个持久化、一个非持久化,那么就不允许绑定。
比较适合异步传输,这里解释一下什么是异步和同步。
下边以Http中的同步和异步为例:
如:普通的B/S架构客户端和服务器端之间的通信就是同步的,即提交请求 ---> 等待服务器处理完毕返回消息 ---> 拿到服务器返回的消息,处理完毕。
如:Ajax技术就是异步的,请求通过事件触发 ---> 服务器处理(浏览器不用等待,仍可以做其他的事情) ---> 处理完毕。
有人可能会好奇说应用场景怎么说到了同步和异步,那说明你还不是很理解技术和应用场景之间的紧密联系。
因此当需要一个稳定的、高可靠性的、功能强大且易于管理的消息队列可以选择RabbitMQ。如果对消息吞吐量需求较大,且不在乎消息偶尔丢失的情况可以使用Kafka。更多关于消息中间件 RabbitMQ 系列的学习文章,请参阅:消息中间件 RabbitMQ ,本系列持续更新中。
参考文章:https://blog.csdn.net/qq_58035032/article/ details/131198036 https://blog.csdn.net/select_myname/ article/details/128122436
推荐阅读 点击标题可跳转