深入了解RabbitMQ工作原理及简单使用

深入了解RabbitMQ工作原理及简单使用

RabbitMQ系列文章

  1. RabbitMQ在Ubuntu上的环境搭建
  2. 深入了解RabbitMQ工作原理及简单使用
  3. RabbitMQ交换器Exchange介绍与实践
  4. RabbitMQ事务和Confirm发送方消息确认——深入解读
  5. 使用Docker部署RabbitMQ集群
  6. 你不知道的RabbitMQ集群架构全解

RabbitMQ简介

在介绍RabbitMQ之前实现要介绍一下MQ,MQ是什么?

MQ全称是Message Queue,可以理解为消息队列的意思,简单来说就是消息以管道的方式进行传递。

RabbitMQ是一个实现了AMQP(Advanced Message Queuing Protocol)高级消息队列协议的消息队列服务,用Erlang语言的。

使用场景

在我们秒杀抢购商品的时候,系统会提醒我们稍等排队中,而不是像几年前一样页面卡死或报错给用户。

像这种排队结算就用到了消息队列机制,放入通道里面一个一个结算处理,而不是某个时间断突然涌入大批量的查询新增把数据库给搞宕机,所以RabbitMQ本质上起到的作用就是削峰填谷,为业务保驾护航。

为什么选择RabbitMQ

现在的市面上有很多MQ可以选择,比如ActiveMQ、ZeroMQ、Appche Qpid,那问题来了为什么要选择RabbitMQ?

  1. 除了Qpid,RabbitMQ是唯一一个实现了AMQP标准的消息服务器;
  2. 可靠性,RabbitMQ的持久化支持,保证了消息的稳定性;
  3. 高并发,RabbitMQ使用了Erlang开发语言,Erlang是为电话交换机开发的语言,天生自带高并发光环,和高可用特性;
  4. 集群部署简单,正是应为Erlang使得RabbitMQ集群部署变的超级简单;
  5. 社区活跃度高,根据网上资料来看,RabbitMQ也是首选;

工作机制

生产者、消费者和代理

在了解消息通讯之前首先要了解3个概念:生产者、消费者和代理。

生产者:消息的创建者,负责创建和推送数据到消息服务器;

消费者:消息的接收方,用于处理数据和确认消息;

代理:就是RabbitMQ本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

消息发送原理

首先你必须连接到Rabbit才能发布和消费消息,那怎么连接和发送消息的呢?

你的应用程序和Rabbit Server之间会创建一个TCP连接,一旦TCP打开,并通过了认证,认证就是你试图连接Rabbit之前发送的Rabbit服务器连接信息和用户名和密码,有点像程序连接数据库,使用Java有两种连接认证的方式,后面代码会详细介绍,一旦认证通过你的应用程序和Rabbit就创建了一条AMQP信道(Channel)。

信道是创建在“真实”TCP上的虚拟连接,AMQP命令都是通过信道发送出去的,每个信道都会有一个唯一的ID,不论是发布消息,订阅队列或者介绍消息都是通过信道完成的。

为什么不通过TCP直接发送命令?

对于操作系统来说创建和销毁TCP会话是非常昂贵的开销,假设高峰期每秒有成千上万条连接,每个连接都要创建一条TCP会话,这就造成了TCP连接的巨大浪费,而且操作系统每秒能创建的TCP也是有限的,因此很快就会遇到系统瓶颈。

如果我们每个请求都使用一条TCP连接,既满足了性能的需要,又能确保每个连接的私密性,这就是引入信道概念的原因。

你必须知道的Rabbit

想要真正的了解Rabbit有些名词是你必须知道的。

包括:ConnectionFactory(连接管理器)、Channel(信道)、Exchange(交换器)、Queue(队列)、RoutingKey(路由键)、BindingKey(绑定键)。

ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用;

Channel(信道):消息推送使用的通道;

Exchange(交换器):用于接受、分配消息;

Queue(队列):用于存储生产者的消息;

RoutingKey(路由键):用于把生成者的数据分配到交换器上;

BindingKey(绑定键):用于把交换器的消息绑定到队列上;

看到上面的解释,最难理解的路由键和绑定键了,那么他们具体怎么发挥作用的,请看下图:

关于更多交换器的信息,我们在后面再讲。

消息持久化

Rabbit队列和交换器有一个不可告人的秘密,就是默认情况下重启服务器会导致消息丢失,那么怎么保证Rabbit在重启的时候不丢失呢?答案就是消息持久化。

当你把消息发送到Rabbit服务器的时候,你需要选择你是否要进行持久化,但这并不能保证Rabbit能从崩溃中恢复,想要Rabbit消息能恢复必须满足3个条件:

  1. 投递消息的时候durable设置为true,消息持久化,代码:channel.queueDeclare(x, true, false, false, null),参数2设置为true持久化;
  2. 设置投递模式deliveryMode设置为2(持久),代码:channel.basicPublish(x, x, MessageProperties.PERSISTENT_TEXT_PLAIN,x),参数3设置为存储纯文本到磁盘;
  3. 消息已经到达持久化交换器上;
  4. 消息已经到达持久化的队列;

持久化工作原理

Rabbit会将你的持久化消息写入磁盘上的持久化日志文件,等消息被消费之后,Rabbit会把这条消息标识为等待垃圾回收。

持久化的缺点

消息持久化的优点显而易见,但缺点也很明显,那就是性能,因为要写入硬盘要比写入内存性能较低很多,从而降低了服务器的吞吐量,尽管使用SSD硬盘可以使事情得到缓解,但他仍然吸干了Rabbit的性能,当消息成千上万条要写入磁盘的时候,性能是很低的。

所以使用者要根据自己的情况,选择适合自己的方式。

虚拟主机

每个Rabbit都能创建很多vhost,我们称之为虚拟主机,每个虚拟主机其实都是mini版的RabbitMQ,拥有自己的队列,交换器和绑定,拥有自己的权限机制。

vhost特性

  1. RabbitMQ默认的vhost是“/”开箱即用;

  2. 多个vhost是隔离的,多个vhost无法通讯,并且不用担心命名冲突(队列和交换器和绑定),实现了多层分离;

  3. 创建用户的时候必须指定vhost;

vhost操作

可以通过rabbitmqctl工具命令创建:

rabbitmqctl add_vhost[vhost_name]

删除vhost:

rabbitmqctl delete_vhost[vhost_name]

查看所有的vhost:

rabbitmqctl list_vhosts

环境搭建

前文我们已经介绍了Ubuntu搭建RabbitMQ的步骤:RabbitMQ在Ubuntu上的环境搭建

如果你是在Windows10上去安装那就更简单了,先放下载地址:

Erlang/Rabbit Server百度网盘链接:https://pan.baidu.com/s/1TnKDV-ZuXLiIgyK8c8f9dg 密码:wct9

当然也可去Erlang和Rabbit官网去下,就是速度比较慢。我的百度云Rabbit最新版本:3.7.6,Erlang版本:20.2,注意:不要下载最新的Erlang,在Windows10上打开扩展插件有问题,打不开。

  1. 安装Erlang;

  2. 安装Rabbit Server;

  3. 进入安装目录\sbin下,使用命令“rabbitmq-plugins enable rabbitmq_management”启动网页管理插件;

  4. 重启Rabbit服务;

使用:http://localhost:15672进行测试,默认的登陆账号为:guest,密码为:guest

重复安装Rabbit Server的坑

如果不是第一次在Windows上安装Rabbit Server一定要把Rabbit和Erlang卸载干净之后,找到注册表:HKEY_LOCAL_MACHINE\SOFTWARE\Ericsson\Erlang\ErlSrv 删除其下的所有项。

不然会出现Rabbit安装之后启动不了的情况,理论上卸载的顺序也是先Rabbit在Erlang。

代码实现

java版实现,使用maven项目,创建可以查看:MyEclipse2017破解设置与maven项目搭建

项目创建成功之后,添加Rabbit Client jar包,只需要在pom.xml里面配置,如下信息:

 <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.2.0</version>
</dependency>

java实现代码分为两个类,第一个是创建Rabbit连接,第二是应用类使用最简单的方式发布和消费消息。

Rabbit的连接,两种方式:

方式一:

public static Connection GetRabbitConnection() {ConnectionFactory factory = new ConnectionFactory();factory.setUsername(Config.UserName);factory.setPassword(Config.Password);factory.setVirtualHost(Config.VHost);factory.setHost(Config.Host);factory.setPort(Config.Port);Connection conn = null;try {conn = factory.newConnection();} catch (Exception e) {e.printStackTrace();}return conn;
}

方式二:

public static Connection GetRabbitConnection2() {ConnectionFactory factory = new ConnectionFactory();// 连接格式:amqp://userName:password@hostName:portNumber/virtualHostString uri = String.format("amqp://%s:%s@%s:%d%s", Config.UserName, Config.Password, Config.Host, Config.Port,Config.VHost);Connection conn = null;try {factory.setUri(uri);factory.setVirtualHost(Config.VHost);conn = factory.newConnection();} catch (Exception e) {e.printStackTrace();}return conn;
}

第二部分:应用类,使用最简单的方式发布和消费消息

public static void main(String[] args) {Publisher(); // 推送消息Consumer(); // 消费消息
}/*** 推送消息*/
public static void Publisher() {// 创建一个连接Connection conn = ConnectionFactoryUtil.GetRabbitConnection();if (conn != null) {try {// 创建通道Channel channel = conn.createChannel();// 声明队列【参数说明:参数一:队列名称,参数二:是否持久化;参数三:是否独占模式;参数四:消费者断开连接时是否删除队列;参数五:消息其他参数】channel.queueDeclare(Config.QueueName, false, false, false, null);String content = String.format("当前时间:%s", new Date().getTime());// 发送内容【参数说明:参数一:交换机名称;参数二:队列名称,参数三:消息的其他属性-routing headers,此属性为MessageProperties.PERSISTENT_TEXT_PLAIN用于设置纯文本消息存储到硬盘;参数四:消息主体】channel.basicPublish("", Config.QueueName, null, content.getBytes("UTF-8"));System.out.println("已发送消息:" + content);// 关闭连接channel.close();conn.close();} catch (Exception e) {e.printStackTrace();}}
}/*** 消费消息*/
public static void Consumer() {// 创建一个连接Connection conn = ConnectionFactoryUtil.GetRabbitConnection();if (conn != null) {try {// 创建通道Channel channel = conn.createChannel();// 声明队列【参数说明:参数一:队列名称,参数二:是否持久化;参数三:是否独占模式;参数四:消费者断开连接时是否删除队列;参数五:消息其他参数】channel.queueDeclare(Config.QueueName, false, false, false, null);// 创建订阅器,并接受消息channel.basicConsume(Config.QueueName, false, "", new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,byte[] body) throws IOException {String routingKey = envelope.getRoutingKey(); // 队列名称String contentType = properties.getContentType(); // 内容类型String content = new String(body, "utf-8"); // 消息正文System.out.println("消息正文:" + content);channel.basicAck(envelope.getDeliveryTag(), false); // 手动确认消息【参数说明:参数一:该消息的index;参数二:是否批量应答,true批量确认小于index的消息】}});} catch (Exception e) {e.printStackTrace();}}
}

代码里面已经写了很详细的注释,在这里也不过多的介绍了。

执行效果,如图:

转载于:https://www.cnblogs.com/javaGoGo/p/10111513.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450395.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring3.2新注解@ControllerAdvice

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 ControllerAdvice&#xff0c;是spring3.2提供的新注解&#xff0c;从名字上可以看出大体意思是控制器增强。让我们先看看ControllerAdv…

C语言关键字

C语言do、while、for关键字—循环 C 语言中循环语句有三种&#xff1a;while 循环、do-while 循环、for 循环。while 循环&#xff1a;先判断while 后面括号里的值&#xff0c;如果为真则执行其后面的代码&#xff1b;否则不执行。while&#xff08;1&#xff09;表示死循环。…

jQuery核心

jQuery(selector) jQuery 的核心功能都是通过这个函数实现的。 jQuery中的一切都基于这个函数&#xff0c;或者说都是在以某种方式使用这个函数。这个函数最基本的用法就是向它传递一个表达式&#xff08;通常由 CSS 选择器组成&#xff09;&#xff0c;然后根据这个表达式来查…

预处理

C语言##预算符 和#运算符一样&#xff0c;##运算符可以用于宏函数的替换部分。这个运算符把两个语言符号组合成单个语言符号。看例子&#xff1a;#define XNAME(n) x ## n如果这样使用宏&#xff1a;XNAME(8)则会被展开成这样&#xff1a;x8看明白了没&#xff1f; ##就是个粘合…

cAdvisor+InfluxDB+Grafana 监控Docker

容器的监控方案其实有很多&#xff0c;有docker自身的docker stats命令、有Scout、有Data Dog等等&#xff0c;本文主要和大家分享一下比较经典的容器开源监控方案组合&#xff1a;cAdvisorInfluxDBGrafan 一、概念 1). InfluxDB是什么nfluxDB是用GO语言编写的一个开源分布式时…

计算机网络知识简单介绍

一、网络基础 1.网络指的是什么&#xff1f; 计算机与计算机之间通过物理链接介质&#xff08;网络设备&#xff09;连接到一起。 计算机与计算机之间基于网络协议通信&#xff08;网络协议就相当于计算机界的英语&#xff09; 2.osi七层协议&#xff1a; 互联网协议按照功能不…

Linux下安装FFmpeg

FFmpeg官网&#xff1a;http://www.ffmpeg.org 官网介绍 FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created. It supports the most obscure…

【Python web 开发】viewset 实现商品详情页的接口

我们如何来完成商品详情页的接口呢&#xff1f; 首先要配置一个商品详情的url 按照我们正常的接口配法 &#xff0c;应该是后面要加一个id 的&#xff0c;为什么这里没有加id 呢? ,应该是rooter register 的作用吧&#xff0c;等我在学习一遍基础再来回答&#xff1f; 那么我…

Ignite中的机器学习介绍

为什么80%的码农都做不了架构师&#xff1f;>>> 本系列共6篇文章&#xff0c;会通过一些代码示例&#xff0c;讲解如何在Ignite中使用机器学习库&#xff0c;本文是本系列的第一篇。 从Ignite的2.4版本开始&#xff0c;机器学习就可以用于生产环境了。在这个版本中…

新架构让数据中心犹如PC

摘要&#xff1a;随着VL2网络拓扑结构带来了对等带宽&#xff0c;大量数据可以存放在远方的数据中心&#xff0c;访问起来却犹如它们就在本地&#xff0c;这将对数据中心的架构产生重大影响。Todd Hoff参加了Hot Interconnects大会&#xff0c;对微软VL2架构做了详细解读。CSDN…

mongodb分片概念和原理-实战分片集群

一、分片分片是一种跨多台机器分发数据的方法。MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署。问题&#xff1a;具有大型数据集或高吞吐量应用程序的数据库系统可能会挑战单个服务器的容量。例如&#xff0c;高查询率会耗尽服务器的CPU容量。工作集大小大于系…

加入初创企业需要想清楚的几个问题

摘要&#xff1a;加入一家初创企业是一段充满冒险的旅程。沿途不会都是美景&#xff0c;更别忘了最初的梦想。 去初创公司面试&#xff0c;你一般会纠结于被问到什么问题。但更重要的是问自己&#xff1a;你下定决心在接下来的5年中“从头再来”吗&#xff1f;你能接受这份薪资…

地图市场三足鼎立:诺基亚官方确认与亚马逊合作

摘要&#xff1a;诺基亚确认为亚马逊新推出的平板提供地图服务&#xff0c;至此地图市场“三家分晋”的格局已趋明朗。 路透社之前曾报道称亚马逊在新版Kindle中将使用诺基亚提供的地图服务。但直到今日&#xff0c;这则消息才得到双方的确认。诺基亚方面确认将为亚马逊提供地图…

关于明晚即将发布的新款 iPad Pro,最大的亮点也许不是 Face ID

北京时间 10 月 30 日晚间 10 点&#xff0c;苹果将会在美国纽约的布鲁克林音乐学院举行新品发布会。考虑到此前苹果已经在 9 月的发布会上宣布了 Apple Watch Series 4 和 iPhone XS/Max、iPhone XR 等新品&#xff0c;因此苹果此次的纽约发布会&#xff0c;大家的目光更多地投…

11. Container With Most Water

题意 给定n个非负整数\(a_1,a_2,...,a_n\),其中每个数表示坐标点\((i,a_i)\),i是数组下标,\(a_i\)是对应高度.寻找两条线,使得两条线构成的长方形面积最大,盛水最多. Example: Input: [1,8,6,2,5,4,8,3,7] Output: 49 解 暴力破解 对每种情况进行循环,计算对应的面积,同时保存最…

先思再行 闭着眼睛编程

摘要&#xff1a;解决问题最重要的习惯不是一直盯着屏幕和编写修改代码&#xff0c;某些时候&#xff0c;阻止你成功的东西恰恰会是过于努力。这时候你需要暂停一下&#xff0c;平缓你的思绪&#xff0c;换一种方法或许能带给你不一样的效果。你会花多少时间思考如何编写代码&a…

javaScript复习

ES6字符串方法&#xff1a; //console.log(String.prototype);var str "abcdefabc";//console.log(str.includes("a"));//结果true//console.log(str.includes("abf"));//结果false//console.log(str.startsWith("d"));//false//cons…

STS的安装教程-鹏鹏

STS全称Spring Tools Suite。 简介&#xff1a;Spring Tools Suite (STS)其实就是一个被包装过的Eclipse&#xff0c;主要用于快速的开发Spring项目&#xff0c;我们不用再去编辑繁琐的xml配置文件&#xff0c;而是由工具自动生成。STS有两种安装方式&#xff0c;一种是直接在E…

linux逻辑卷管理

2019独角兽企业重金招聘Python工程师标准>>> 摘要&#xff1a; Linux用户安装Linux操作系统时遇到的一个最常见的难以决定的问题就是如何正确地给评估各分区大小&#xff0c;以分配合适的硬盘空间。而遇到出现某个分区空间耗尽时&#xff0c;解决的方法通常是使用符…

github 如何设置项目的语言显示

github 会根据一个项目文件最多的那个种类的文件显示为对应的语言项目 如果想让整个项目显示为 HTML 项目, 需要进行以下步骤的设置 1.在根目录下创建一个文件 .gitattributescreate .gitattributes2.在 .gitattributes 内编辑以下内容&#xff1a; *.js linguist-languageHTML…