RabbitMQ是如何运转的?
前言
rabbitmq是消息队列中间件(message queue middleware)中一种,工作虽然有用到,但是却没有形成很好的整体包括,主要是一些基础概念的认识,这里通过阅读《rabbitmq实战指南》整理笔记并进行代码实践,更好地理解rabbitmq!
本文只通过讲解rabbitmq的一些基础概念,主要是rabbitmq的“生产者-消费者”模型涉及到的交换器、路由键、绑定键、消息路由规则等,下一篇rabbitmq是如何运转的?会有简单介绍rabbitmq的运转、rabbitmq部署,java代码实践。
需要电子书pdf版《rabbitmq实战指南》(高清带标签)可以评论或者联系我
一、mq的作用
讲解rabbitmq之前先认识下mq作为消息中间件的作用(优点),使用的时候如果不去思考为什么用mq,怎样更好地才能达到它的作用的话,那都是毫无意义的使用!
1、解耦:可以很好地屏蔽应用程序及平台之间的特性,充当中间者,松散耦合应用程序及平台,它们彼此不需要了解远程过程调用rpc与网络协议的细节;
2、异步通信:能提供c/s之间同步与异步连接,在任何时刻都可以将消息进行传送或者存储转发;
3、可恢复性:当消息接收方宕机或网络不通的情况下,消息转储于mq中,直到网络恢复或接收方恢复再进行转发;
4、扩展性:提高消息入队列和处理效率是容易的,只需要另外增加处理过程即可,不需要改变代码,也不需要调节参数。
5、顺序性:由于大部分mq支持队列模式,自然也就能保证一定的数据处理顺序;
6、缓冲:mq通过一个缓冲层来帮助任务最高效率执行,写入mq的处理会尽可能快速。
二、rabbitmq的“交换机”模型
rabbitmq整体的模型其实是一种“生产者-消费者”模型,发送消息的一方称之为生产者,接收消息一方称之为消费者。中间会有交换器、队列、broker等概念。下图是简单的rabbitmq的模型图(截图来自于《rabbitmq实战指南》,以下截图同)
1、生产者-消费者与rabbitmq broker
(1)producer:
投递消息的一方,创建了消息之后发布到rabbitmq中,消息主要包括消息体(payload)与label标签,消息体可以通常是业务数据,比如json等,label则用来表述这条消息,比如一个交换机名称和一个路由键。
生产者把消息交由rabbitmq,之后会根据标签把消息发送给感兴趣的消费者。
(2 consumer:
消费者,接收消息的一方,连接到rabbitmq服务器,并订阅到队列上,当消费者消费一条消息时只是消费了消息体payload,在消息路由过程中,消息的标签会丢失,存入队列中只有消息体。消费者不需要知道生产者是谁。
(3)broker:
消息中间件的服务节点,一个rabbitmq broker可以简单地看做一个rabbitmq服务节或者rabbitmq服务实例(大多数情况下可以看做是一台rabbitmq的服务器)
由上图可知,消息队列运转过程是这样的:
封装好的消息发送(amqp命令为basic.publish)到broker中,消费者订阅并接收(basic.get/basic.consume)消息,之后再进行业务逻辑处理(可以再开另外的进程,不需要与接收消息同一个进程)
2、队列
rabbitmq中消息都只能存储在队列中,当多个消费者订阅一个队列时,队列中的消息会被平均分摊(round-robin),也就是并不是每个消费者都能收到所有的消息并处理。
注意以下几点:
1)对于生产者生产的消息到队列中,并不是平均分摊。而是通过路由键、绑定键、交换器类型三个决定消息最终被哪个消费者消费,之后会介绍!
2)生产者与消费者之间的连接,并不只是通过队列那么简单连接,而是外加通过tcp连接与信道channel,之后也会介绍
3、交换器、路由键、绑定
(1) 交换器(exchange, x):由上图交换机模型图中看不到交换器这个东西,但实际上是存在的,生产者将消息投递到队列,然而真实情况是:生产者将消息发送到exchange,由exchange再路由到一个或多个队列中;
交换器的类型有fanout、direct、topic、headers这四种类型,不同的类型的交换器有其独特的匹配规则,这里的匹配规则其实就是决定消息最终路由到哪的队列的关键,具体请往下看
(2) 路由键(routingkey):生产者将消息发送给交换器的时候,会指定routingkey指定路由规则,实际情况是需要将routingkey、交换器类型、绑定键联合使用才能最终生效。当交换器类型与bindingkey固定情况下,通过执行routingkey来决定消息流向哪里。
(3)绑定(bindingkey):通过绑定键将交换器与队列关联起来,这样rabbitmq就知道如何正确地将消息路由到队列,其实绑定键也是一种路由键的一种,不过是用在绑定交换器与队列的时候。
总结有以下三点:
(1) 生产者将消息发送给哪个exchange是需要由routingkey决定的,生产者需要将exchange与哪个队列绑定时需要由bindingkey决定的(当然还要看交换器类型,bindingkey不一定会生效,如fanout类型交换器);
(2) 生产者将消息发送给交换器时,需要一个routingkey,当bindingkey和routingkey相匹配时,消息会被路由到对象的队列中(当然也要看交换器类型)。
(3) bindingkey其实也属于路由键的一种,在使用邦定的时候,需要的路由键是bingdingkey,在发送消息的时,需要的路由键是routingkey
4、交换器类型
为什么非要介绍交换器类型呢?上文中也提到过交换器类型关系到具体的消息路由途径,处路由键、绑定键之外的还需要关注交换器的类型。不同的交换器会有不同的匹配规则。
rabbitmq常用的交换器类型有fanout、direct、topic、headers这四种类型
(1)fanout:它会把所有的交换器上的消息路由到所有与该交换器邦定的队列中,不需要bindingkey生效
(2)direct:它会把消息路由到bindingkey与routingkey完全匹配的队列中。比如在发送消息的时候,设置label中routingkey为warning,则消息会路由到queue1与queue2上(请看下图)。
(3)topic:是direct上的扩展,同样是利用routingkey与bindingkey相匹配,但是匹配规则不一样,支持模糊匹配。有如下的规则
-
-
-
-
- routingkey为一个点号“.”分隔的字符串,每个被隔开的独立字符串即为一个单词,是匹配的单位;
- bindingkey和routingkey一样,也是"."分割的字符串;
- 但不同的是bindingkey,可以用“#”,“*”进行类似于占位符的模糊匹配,“#”表示一个单词,"*"表示多个单词(也可以是零个)
-
-
-
比如:
routingkey为com.hidden.client的消息只会到队列queue2中:因为只有queue2的bindingkey=*.*.client匹配com.hidden.client
routingkey为com.rabbitmq.client的消息会到队列queue1-2中: 因为queue1的bindingkey=*.rabbitmq.*.匹配com.rabbitmq.client,queue2的bindingkey=*.*.client匹配com.rabbitmq.client
routingkey为java.rabbitmq.demo的消息只会到队列queue1中:因为只有queue1的bindingkey=*.rabbitmq.*.匹配java.rabbitmq.demo
routingkey为java.util.concurrent的消息会被丢弃或者返回给生产者(需要设置)
(4)headers:依赖发送消息内容中的hearders属性进行匹配,在绑定队列和交换器时指定一组键值对,这里的也就是headers,当发送消息到交换器时,rabbitmq会获取到该消息的headers,通过比较会路由到相关队列中,这种交换器性能会很差,一般不会使用。
以上内容总结起来只是介绍了rabbitmq的从生产者产生消息到消费者消费消息过程中涉及到的概念。还未介绍具体的rabbitmq是如何运转的,比如生产者是怎样建立连接生成消息的,消费者又是怎样读取消息的,这将是下一篇rabbitmq是如何运转的?主要介绍的。
上一篇: 超市管理系统