C#队列学习笔记:RabbitMQ基础知识

Stella981
• 阅读 706

    一、引言

    RabbitMQ是Rabbit Message Queue的简写,但不能仅仅理解其为消息队列,消息代理更合适。RabbitMQ是一个由 Erlang 语言开发的AMQP(高级消息队列协议)的开源实现,其内部结构如下:

C#队列学习笔记:RabbitMQ基础知识

    RabbitMQ作为一个消息代理,主要和消息打交道,负责接收并转发消息。RabbitMQ提供了可靠的消息机制、跟踪机制和灵活的消息路由,支持消息集群和分布式部署。适用于排队算法、秒杀活动、消息分发、异步处理、数据同步、处理耗时任务、CQRS等应用场景。

    二、基础概念

     讲解基础概念之前,先来构造一个整体结构图,以方便我们更好地去理解RabbitMQ的基本原理。

C#队列学习笔记:RabbitMQ基础知识

    通过上面这张结构图,能够清晰地了解到Send Message到Receive Message的一个大致流程。

2.1、Queue

    Queue(队列)在RabbitMQ中的作用是存储消息,队列的特性是先进先出。上图可以清晰地看到Client A和Client B是生产者,生产者生产消息最终被送到RabbitMQ的内部对象Queue中去,而消费者则是从Queue中取出数据,可以简化表示为:

C#队列学习笔记:RabbitMQ基础知识

    生产者Send Message,“A”被传送到Queue中,消费者发现消息队列Queue中有订阅的消息,就会将这条消息A读取出来进行一系列的业务操作。这里是一个消费者对应一个队列Queue,也可以多个消费者订阅同一个队列Queue,此时就会将Queue里面的消息平分给其他的消费者,但是会存在一个问题就是如果每个消息的处理时间不同,就会导致某些消费者一直在忙碌中,而有的消费者处理完消息后一直处于空闲状态。这时我们可以使用prefetchCount来限制每次发送给消费者消息的个数,详情见下图所示:

C#队列学习笔记:RabbitMQ基础知识

    这里的prefetchCount=1是指每次从Queue中发送一条消息,等消费者处理完这条消息后,Queue会再发送一条消息给消费者。

2.2、Exchange

    在本节开头的结构图中我们留下了一个坑:消费者Client A和消费者Client B,是如何知道要发送的消息是给Queue1还是给Queue2的呢?下面让我们来解开这个面纱。首先要明确的一点是:生产者生产的消息并不是直接发送给消息队列Queue的,而是要经过Exchange(交换器)将消息路由到一个或多个Queue,当然这里还会对不符合路由规则的消息进行丢弃,这个涉及到后面要讲的Exchange Type。那么Exchange是怎样将消息准确地推送到对应的Queue的呢?功劳最大的当属Binding。RabbitMQ通过Binding将Exchange和Queue链接在一起,这样Exchange就知道如何将消息准确地推送到Queue中去了,简单示意图如下所示:

C#队列学习笔记:RabbitMQ基础知识

    生产者将消息发送给Exchange的时候,一般会产生一个Routing Key,而通过Binding链接Exchange和Queue的时候,一般会指定一个Binding Key。当Routing Key与Binding Key对应得上的时候,消息就会发送到对应的Queue中去。

2.3、Exchange Type

    Exchange Type有4种,不同的类型有着不同的策略,也就意味着类型的不同将决定着绑定的Queue的不同。换言之,生产者发送了一个消息,Routing Key的规则是A,那么生产者会将Routing Key=A的消息推送到Exchange中,这时候Exchange根据自己的规则去筛选生产者发来的消息。

  • fanout

    fanout类型的Exchange,路由规则非常简单:它会把所有发送到该Exchange的消息,路由到所有与它绑定的Queue中。

C#队列学习笔记:RabbitMQ基础知识

    上图所示,生产者(P)将消息1推送到Exchange,由于Exchange Type=fanout,这时候会遵循fanout的规则将消息推送到所有与它绑定的Queue中(上图的两个Queue),最后给两个消费者消费。

  • direct

    direct类型的Exchange,路由规则也很简单:它会把消息路由到那些Routing Key与Binding Key完全匹配的Queue中。

C#队列学习笔记:RabbitMQ基础知识

    当生产者(P)发送消息时Rotuing key=booking,Exchange获取到生产者发送过来的消息后,会根据自身的规则进行匹配相应的Queue,这时发现Queue1和Queue2都符合,就会将消息传送给这两个队列。如果我们以Rotuing key=create和Rotuing key=confirm发送消息时,这时消息只会被推送到Queue2队列中,其它Routing Key的消息将会被丢弃。

  • topic

    如果说前面的direct规则是严格意义上的匹配(即Routing Key必须与Binding Key相匹配的时候才将消息传送给Queue),那么topic这个规则就是模糊匹配,可以通过通配符满足一部分规则就可以传送,它的约定是:

    1)Routing Key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”。

    2)Binding Key与Routing Key一样也是句点号“. ”分隔的字符串。

    3)Binding Key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)。

C#队列学习笔记:RabbitMQ基础知识

    当生产者发送消息Routing Key=F.C.E的时候,这时候只满足Queue1,所以会被路由到Queue1中;如果Routing Key=A.C.E这时候会被同时路由到Queue1和Queue2中;如果Routing Key=A.F.B时,这时只会路由到Queue2中。

  • headers

    headers类型的Exchange,不依赖于Routing Key与Binding Key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。

    在绑定Exchange与Queue时指定一组键值对,当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),并对比其中的键值对是否完全匹配Exchange与Queue绑定时指定的键值对,如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。该类型的Exchange没有用到过(不过也应该很有用武之地),所以不作介绍。

    下面对4种Exchange类型进行简要的表格整理:

Exchange规则

类型名称

类型描述

fanout

把所有发送到该Exchange的消息路由到所有与它绑定的Queue中

direct

Routing Key==Binding Key

topic

简称模糊匹配

headers

Exchange不依赖于Routing Key与Binding Key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。

2.4、补充说明

ConnectionFactory、Connection、Channel:都是RabbitMQ对外API中最基本的对象。

    ConnectionFactory:Connection的制造工厂。

    Connection:RabbitMQ的socket链接,它封装了socket协议相关的逻辑。Connection建立一个TCP连接,生产者和消费者通过TCP连接到RabbitMQ Server。

    Channel:

    1)Channel是与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作都是通过Channel这个接口来完成的,包括定义Exchange与Queue、绑定Exchange与Queue、发布消息等。

    2)Channel虚拟连接,是建立在上面TCP连接的基础上。数据流动都是通过Channel来进行的,为什么不是直接在TCP连接上进行数据流动呢?是因为建立和关闭TCP连接是有代价的。频繁地建立与关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,这也限制了系统处理高并发的能力,而在TCP连接中建立Channel是没有上述代价的。

    参考自:

    https://www.cnblogs.com/dwlsxj/p/RabbitMQ.html

    https://www.cnblogs.com/sheng-jie/p/7192690.html

    https://www.cnblogs.com/davenkin/p/rabbitmq-best-practices.html

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
RabbitMQ学习总结(7)——Spring整合RabbitMQ实例
1.RabbitMQ简介RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是AMQP(高级消息队列协议)的标准实现。 官网:http://www.rabbitmq.com/(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.rabbi
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这