RabbitMQ系列(二)深入了解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百度网盘链接:pan.baidu.com/s/1TnKDV-Zu… 密码: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();}}
}
复制代码

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

执行效果,如图:

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

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

相关文章

四叶草社交平台——十天冲刺(10)

姑且就这样了&#xff0c;找了个新模板&#xff0c;这个模板先用来过关吧。转载于:https://www.cnblogs.com/limitCM/p/10925208.html

虚拟机(Visual Machine)的云平台的自动伸缩扩容(auto-scaling)技术

云计算平台中允许客户依据应用的负载进行云计算资源的弹性动态伸缩&#xff08;理想的情况是实现一个用多少付费多少的模型&#xff0c;最大限度地降低用户的运营成本&#xff09; 在进行讨论之前&#xff0c;先对几个名词进行定义 1&#xff09;客户&#xff1a;使用云服务的人…

Unity 3D学习笔记之一 界面介绍

因为学校的课程&#xff0c;本学期对Unity 3D有学习的要求&#xff0c;在博客中记录下自己的Unity学习之路&#xff08;内容摘录自书本和视频&#xff0c;书本为Unity 4.x从入门到精通&#xff09;一、Unity界面介绍首先进入Unity3D&#xff0c;在菜单栏&#xff0c;File中new …

Python 获得程序 exe 的版本号

Python 获得程序 exe 的版本号 python中需要安装 pywin32 包 # based on http://stackoverflow.com/questions/580924/python-windows-file-version-attribute from win32com.client import Dispatchdef get_version_via_com(filename):parser Dispatch("Scripting.FileS…

Coding and Paper Letter(一)

2019独角兽企业重金招聘Python工程师标准>>> 最近发现需要在快速阅读背景下&#xff0c;对快餐式资源做整理与收集。以Coding&#xff08;以Github&#xff09;和Paper&#xff08;自己看到的一些论文&#xff0c;论文一般主要看题目和摘要做些简单小结&#xff09;…

MacBook刷机勘错篇

前一段时间突然发现自己的MacBook已经好久没有刷过系统了&#xff0c;10.9用着还好&#xff0c;但bootcamp装的win8.1越来越卡&#xff0c;越用越慢。想要重做一下双系统&#xff0c;后来就演变成了两个系统一起更新&#xff0c;再后来就演变成了一个惨案。因为自己一直也没有使…

字典、列表、元组

1 字典2 Python内置的字典数据类型&#xff1a;全称dictionary&#xff0c;在其他语言中也称为map&#xff0c;使用键-值&#xff08;key-value&#xff09;存储&#xff0c;具有极快的查找速度3 4 当将key-value放进dict时&#xff0c;dict会根据key算出value要存放地址&#…

Sublime Text怎么快速建立一个html5页面模板

在编辑器中输入一个半角英文的感叹号&#xff08;!&#xff09;,然后按下TAB键

Mac OS X 10.10更新及体验

前一阵子&#xff0c;更新了Mac OS 10.10 Yosemite&#xff0c;总体用起来感觉还是很不错的&#xff0c;是很值得升级&#xff0c;相对于10.9 Mavericks优化了不少东西。我之前写的使用教程有一些也就不适用了&#xff1b;比如更换Dashboard中的背景&#xff0c;10.10中Dashboa…

快速幂学习笔记

啥是快速幂 快速幂&#xff0c;顾名思义&#xff0c;就是快速算某个数的多少次幂。其时间复杂度为 \(O(\log N)\)&#xff0c; 与朴素的\(O(N)\)相比效率有了极大的提高。 原理 来自学长&#xff1a; 我们可以把 \(b\) 分解成二进制数&#xff0c;其中从小到大每一个二进制位 是…

文本处理工具sed

sed&#xff1a;stream Editor流编辑器&#xff0c;默认不编辑原文件&#xff0c;仅对模式空间中的数据做处理&#xff1b;而后&#xff0c;处理结束后&#xff0c;将模式空间打印至屏幕。语法&#xff1a; sed [option] AddressCommand file1 file2... option选项有&#xff1…

Mac OS X必备APP推荐之一

本篇博文要推荐一下装机必备的APP&#xff0c;因为电脑的使用需求因人而异&#xff0c;这里我根据我的见解和长时间的使用经验推荐一些我认为大家基本都用得到的APP&#xff0c;太过专业性质的我就不推荐了&#xff0c;当然我的推荐肯定会有疏漏和偏差的地方&#xff0c;还请熟…

2018-2019-2 20175235 实验四《Android开发基础》实验报告

实验目的 一、Android Studio的安装测试 二、Activity测试 三、UI测试 四、布局测试 五、事件处理测试 一.Android Stuidio的安装测试&#xff1a; 参考《Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)》第二十四章&#xff1a; 参考http://www.cnblogs.com…

Mac OS X必备APP推荐之二

本篇接着上一篇APP推荐的博文&#xff0c;继续为大家推荐Mac下好用的APP。 一、首先推荐一款DaisyDisk&#xff0c;磁盘分析、清理工具。前面第一篇APP推荐中&#xff0c;我们推荐过APP和系统垃圾清理工具——Cleanmymac&#xff0c;这两个APP侧重有所不同。Cleanmymac主要清理…

【编程大系】Java资源汇总

1.学习资料&#xff1a; 1&#xff09;Spring Boot 那些事&#xff1a;https://www.w3cschool.cn/springboot/ 对应的 gitHub代码&#xff1a; https://github.com/JeffLi1993/springboot-learning-example 2&#xff09;Spring Boot基础视频&#xff1a;https://www.w3cschool…

Mac OSX使用VMware Fusion安装windows虚拟机教程

安装虚拟机之前&#xff0c;先要有两步准备工作。第一&#xff0c;安装并激活VMware Fusion&#xff0c;如果大家还没有下载VMware Fusion请参照上一篇博文&#xff0c;APP推荐之二&#xff0c;下载VMware Fusion并激活。第二&#xff0c;下载你想要安装的系统镜像。因为已经装…

利用CAGradientLayer自定义颜色渐变view

说个故事&#xff1a; UI设计对大家说:“我们拒绝炒现饭!"。 然后就加了一波特效。 程序员猝。 #####效果分析&#xff1a; 1.水波动画。 2.背景颜色渐变。 #####实现思路&#xff1a; 1.水波动画&#xff0c;用CGMutablePathRef和三角函数画出波浪线&#xff0c;让后利用…

【笔记】spring定时器时间配置实例

"0/10 * * * * ?" 每10秒触发 "0 0 12 * * ?" 每天中午12点触发 "0 15 10 ? * *" 每天上午10:15触发 "0 15 10 * * ?" 每天上午10:15触发 "0 15 10 * * ? *" 每天上午10:15触发 "0 15 10 * * ? 2005" 2…

java简介和开发环境搭建

因为本人的Java一直以来水平都不怎么样&#xff0c;大一的时候只考了60分。所以在临近毕业的时候&#xff0c;我选择了重修Java&#xff0c;这些天正在慢慢的回顾Java&#xff0c;会到博客里面记录一些Java的知识&#xff0c;不为有多少人来看&#xff0c;只希望自己有所收获。…

第六章 函数和宏定义实验(2)

C程序设计实验报告 实验项目&#xff1a; 1、利用复化梯形公式计算定积分 2、计算Ackerman函数 3、编写计算x的y次幂的递归函数getpower(int x,int y)&#xff0c;并在主程序中实现输入输出 4、编写计算学生年龄的递归函数 5、编写递归函数实现Ackman函数 姓名&#xff1a;王锦…