原 RabbitMq基础教程之基本概念

RabbitMq基础教程之基本概念

RabbitMQ是一个消息队列,和Kafka以及阿里的ActiveMQ从属性来讲,干的都是一回事。消息队列的主要目的实现消息的生产者和消费者之间的解耦,支持多应用之间的异步协调工作

由于工作原因,接触和使用rabbitmq作为生产环境下的消息队列,因此准备写一些博文,记录下这个过程中的收货;而开篇除了环境搭建之外,就是对于其内部的基本概念进行熟悉和了解了。

基础环境搭建可以参考: 《RabbitMq基础教程之安装与测试》

本文则主要集中在以下几点:

  • 几个基本概念(Message, Publisher, Exchange, Binding, Queue, Channel, Consuer, Virtual host)
  • 消息分发的几种策略
  • ACK是什么鬼

<!-- more -->

I. 基本概念

1. 消息队列

首先来一张消息队列的经典图,可以划分为三个角色: Producer, Queue, Consumer

  • Queue:为承载消息的容器,为什么是队列而不是栈呢?主要是因为绝大部分的场景,我们都是希望消息是先进先出,有顺序的
  • Producer:生产者,就是产生消息,并不断往队列塞的角色
  • Consumer:消费者,也就是不断从队列中获取消息的角色

看到这个模型,如果对JDK的容器有一定的了解,很容易可以想到借助 ArrayBlockingQueue 或者 ListBlockingQueue 就可以实现简易的消息队列(也就是我们常说的生产者-消费者模型)

2. 实例理解消息队列

其实在生活中,这种模型用得非常多,就比如我们都会接触的网购快递,可以说是一个典型的消息队列的case了:

商家不断的把商品扔给快递公司(注意不是直接将商品给买家),而快递公司则将商品根据地质分发对应的买家

对上面这个过程进行拆解,可以映射扮演的角色

  • 商品:Message,传递的消息,由商家投递给快递公司时,需要进行打包(一般Producer生产消息也会将实体数据进行封装)
  • 商家:Produer 生产者
  • 快递公司: Queue,消息的载体
  • 买家:Consumer 消费者

那么快递公司时怎么知道要把商品给对应的买家呢?根据包裹上的地址+电话

  • 同样消息队列也需要一个映射规则,实现Message和Consumer之间的路由

3. RabbitMQ基本概念

通过上面的实例对比,发现基本的消息队列定义的元素太少,这里则正好可以看一下RabbitMQ是怎么具体来实现消息队列的

  • Message:消息,包含消息头(即附属的配置信息)和消息体(即消息的实体内容)
  • Publisher:生产者,向交换机发布消息的主体
  • Exchange:交换机,用来接收生产者发送的消息并将这些消息路由给服务器中的队列
  • Binding:绑定,用于给Exchange和Queue建立关系,就是我们熟知的配对的红娘
  • Queue:消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。
  • Connection:连接
  • Channel:通道,MQ与外部打交道都是通过Channel来的,发布消息、订阅队列还是接收消息,这些动作都是通过Channel完成;简单来说就是消息通过Channel塞进队列或者流出队列
  • Consumer:消费者,从消息队列中获取消息的主体
  • Virtual Host: 虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 /
  • Broker:消息队列服务器实体

上面是一些专业的概念,那么可以怎么映射到前面的快递上呢?

II. Exchange类型

生产者,将消息投递给Exchange,然后由Exchange将消息路由到对应的Queue上,供消费者消费,那么这个路由有哪些方式呢?

1. Direct策略

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中

简单来讲,就是路由键与队列名完全匹配

  • 如果一个队列绑定到交换机要求路由键为“dog”
  • 只转发 routing key 标记为“dog”的消息,
  • 不会转发“dog.puppy”,也不会转发“dog.guard”等等
  • 它是完全匹配、单播的模式

举例说明

Exchange和两个队列绑定在一起:

  • Q1的bindingkey是orange
  • Q2的binding key是black和green.
  • 当Producer publish key是orange时, exchange会把它放到Q1上, 如果是black或green就会到Q2上, 其余的Message被丢弃

2. Fanout策略

从上图也可以看出,这种策略,将忽略所谓的routing key,将消息分发到所有绑定的Queue上,更加类似我们理解的广播模式

3. Topic策略

topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上

可以理解为直接策略的进阶版,直接策略是完全精确匹配,而topic则支持正则匹配,满足某类指定规则的(如以xxx开头的路由键),可以键消息分发过去

  • # 匹配0个或多个单词
  • * 匹配不多不少一个单词

一个更直观的实例如下

Producer发送消息时需要设置routing_key,

  • Q1 的binding key 是”.orange.“
  • Q2 是 “..rabbit” 和 “lazy.#”:
  • 产生一个 test.orange.mm 消息,则会路由到Q1;而如果是 test.orange则无法路由到Q1,因为Q1的规则是三个单词,中间一个为orange,不满足这个规则的都无效
  • 产生一个 test.qq.rabbit 或者 lazy.qq 都可以分发到Q2;即路由key为三个单词,最后一个为rabbit或者不限制单词个数,主要第一个是lazy的消息,都可以分发过来
  • 如果产生的是一个 test.orange.rabbit消息,则Q1和Q2都可以满足

4. Headers策略

这个实际上用得不多,它是根据Message的一些头部信息来分发过滤Message,忽略routing key的属性,如果Header信息和message消息的头信息相匹配

5. 小结

主要使用的消息分发策略有三个,直接,路由和扇形,简单的小结下应用场景和区别

a. Direct Exchange

直接完全匹配模式,适用于精准的消息分发

b. Topic Exchange

Routing Key的匹配模式,支持Routing Key的模糊匹配方式,更适用于多类消息的聚合

c. Fanout Exchange

忽略Routing Key, 将消息分配给所有的Queue,广播模式,适用于消息的复用场景

III. ACK

消息队列的一个重要指标,当有消费者获取了消息之后,对这个消息我应该怎么办?是直接删除还是等某个合适的机会再删除?又或者是干脆不删除,就留着了?

在实际的应用场景中,消息正常消费之后,我们希望的是这个消息就不要了,但是消费的过程中如果出现了bug,则希望不要删除消息,等我修复这个bug后,可以把这个消息重新的投递给我

1. ack机制

Consumer接收到了消息之后,必须返回一个ack的标志,表示消息是否成功消费,如果返回true,则表示消费成功了,然后这个消息就会从RabbitMQ的队列中删掉;如果返回false,且设置为重新入队,则这个消息可以被重新投递进来

通常实际编码中,默认是自动ACK的,如果消息的重要性程度较高,我们应该设置为主动ACK,在接收到消息之后,自主的返回对应的ACK信息

这一块更多地内容可以查看实际使用篇

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小白鼠

分布式事务数据库事务CAP定理BASE理论分布式事务案例

断电了,该怎么处理?通过日志的方式!在执行事务的时候数据库首先会记录下这个事务的redo操作日志,然后才开始真正操作数据库,在操作之前首先会把日志文件写入磁盘,...

932
来自专栏Youngxj

安卓四大组件之Broadcast Receiver-广播接收者

1532
来自专栏安全领域

物联网 MQTT 服务质量级别

原文地址:https://dzone.com/articles/internet-things-mqtt-quality

4847
来自专栏Coding01

推荐一个 PHP 网络请求插件 Guzzle

在写后台代码时,避免不了需要与其他第三方接口交互,如向服务号下发模板消息,有时可能需要下发超过 10 万条。这时不得不考虑使用异步和「多线程」的网络请求。

1505
来自专栏Golang语言社区

Go语言异步服务器框架原理和实现

Go语言类库中,有两个官方的服务器框架,一个HTTP,一个是RPC。使用这个两个框架,已经能解决大部分的问题,但是,也有一些需求,这些框架是不够的,这篇文章,我...

3937
来自专栏小白鼠

分布式事务数据库事务CAP定理BASE理论分布式事务案例

断电了,该怎么处理?通过日志的方式!在执行事务的时候数据库首先会记录下这个事务的redo操作日志,然后才开始真正操作数据库,在操作之前首先会把日志文件写入磁盘,...

964
来自专栏Esofar 开发日记

[译]RabbitMQ教程C#版 - 工作队列

在第一篇教程中,我们编写了两个程序,用于从一个指定的队列发送和接收消息。在本文中,我们将创建一个工作队列,用于在多个工作线程间分发耗时的任务。

792
来自专栏用户2442861的专栏

编程思想之多线程与多进程(1)——以操作系统的角度述说线程与进程

什么是线程?线程与进程与有什么关系?这是一个非常抽象的问题,也是一个特别广的话题,涉及到非常多的知识。我不能确保能把它讲的话,也不能确保讲的内容全部都正确。即...

281
来自专栏熊二哥

快速入门系列--WCF--06并发限流、可靠会话和队列服务

这部分将介绍一些相对深入的知识点,包括通过并发限流来保证服务的可用性,通过可靠会话机制保证会话信息的可靠性,通过队列服务来解耦客户端和服务端,提高系统的可服务数...

1787
来自专栏Java成长之路

线程的实现方式

本文主要介绍线程的3种实现方式和java线程的实现方式。线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配 和执行调度分开,各个进程既可以...

925

扫码关注云+社区