RabbitMQ新手教程

RabbitMQ 新手指南

@author shangwei

  1. 安装RabbitMQ
  2. 安装Erlang
  3. RabbitMQ是什么鬼
  4. 写个Hello World 测试一下
  5. RabbitMQ中插件管理

安装RabbitMQ

由于我现在的电脑是windows系统,所以我们选择windows版本的RabbitMQ(此处吐槽一下,windows的编程环境不是很好,MacOS 无敌)
点击此处进入下载页面,然后我们就进入了下载的页面
在这里插入图片描述

现在我们选择图片里面标红的进行下载就可以了
在这里插入图片描述

RabbitMQ不是很大,应该一会儿就下载好了。下载完毕以后我们就点击安装进行安装了。但是这个时候会出现新的问题,发现安装不了,这时候就进入了第二步了

安装Erlang

安装Erlang也比较简单,傻瓜式操作,一直next就可以啦,点击此处进入下载页面,进入下载页面以后,我们点击图中标红的地方就可以进行下载了
在这里插入图片描述

下载完成以后,我们就开始一直next了,之前弄过Java的人应该都知道Java有个环境变量,这里Erlang也有个环境变量,所以接下来就是设置环境变量了(RabbitMQ不用设置环境变量也可以运行,所以不想设置环境变量的话这一步可以跳过去)

1) 添加系统环境变量ERLANG_HOME,值为安装目录. 
2) 修改系统环境变量Path,在PATH变量中添加“%ERLANG_HOME%\bin” 
3) 重启电脑后,在控制台输入 erl,如果出现类似“Eshell V6.1 (abort with ^G)”字样,说明安装成功。

安装完Erlang以后,之前RabbitMQ也就可以继续安装了。一直next就行了,RabbitMQ也不是很大就丢在C盘。

RabbitMQ 是个什么鬼

我想安装到了这一步还是没有明白,RabbitMQ是个什么东西,这里如果想直接看官方文档的话,也可以。官方文档有多种语言的用法,这里我只介绍一下Java的用法。
接下来从4个方面来介绍一下RabbitMQ

  1. 历史
  2. 应用场景
  3. 系统架构
  4. 进一步的细节阐明
1.历史

RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现。AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消息通讯的世界里有很多公开标准(如 COBAR的 IIOP ,或者是 SOAP 等),但是在异步消息处理中却不是这样,只有大企业有一些商业实现(如微软的 MSMQ ,IBM 的 Websphere MQ 等),因此,在 2006 年的 6 月,Cisco 、Redhat、iMatix 等联合制定了 AMQP 的公开标准。

RabbitMQ是由RabbitMQ Technologies Ltd开发并且提供商业支持的。该公司在2010年4月被SpringSource(VMWare的一个部门)收购。在2013年5月被并入Pivotal。其实VMWare,Pivotal和EMC本质上是一家的。不同的是VMWare是独立上市子公司,而Pivotal是整合了EMC的某些资源,现在并没有上市。

RabbitMQ的官网是http://www.rabbitmq.com
2.应用场景

言归正传。RabbitMQ,或者说AMQP解决了什么问题,或者说它的应用场景是什么?

对于一个大型的软件系统来说,它会有很多的组件或者说模块或者说子系统或者(subsystem or Component or submodule)。那么这些模块的如何通信?这和传统的IPC有很大的区别。传统的IPC很多都是在单一系统上的,模块耦合性很大,不适合扩展(Scalability);如果使用socket那么不同的模块的确可以部署到不同的机器上,但是还是有很多问题需要解决。比如:

1)信息的发送者和接收者如何维持这个连接,如果一方的连接中断,这期间的数据如何方式丢失?

2)如何降低发送者和接收者的耦合度?

3)如何让Priority高的接收者先接到数据?

4)如何做到load balance?有效均衡接收者的负载?

5)如何有效的将数据发送到相关的接收者?也就是说将接收者subscribe 不同的数据,如何做有效的filter。

6)如何做到可扩展,甚至将这个通信模块发到cluster上?

7)如何保证接收者接收到了完整,正确的数据?

AMQP协议解决了以上的问题,而RabbitMQ实现了AMQP。

3.系统架构

成为系统架构可能不太合适,可能叫应用场景的系统架构更合适。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFPNfIP1-1570436527393)(evernotecid://35A29B35-92A2-4099-AB5B-F33662D07A67/appyinxiangcom/20351905/ENResource/p1600)]

RabbitMQ Server: 也叫broker server,它不是运送食物的卡车,而是一种传输服务。原话是RabbitMQisn’t a food truck, it’s a delivery service. 他的角色就是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输。但是这个保证也不是100%的保证,但是对于普通的应用来说这已经足够了。当然对于商业系统来说,可以再做一层数据一致性的guard,就可以彻底保证系统的一致性了。

Client A & B: 也叫Producer,数据的发送方。createmessages and publish (send) them to a broker server (RabbitMQ).一个Message有两个部分:payload(有效载荷)和label(标签)。payload顾名思义就是传输的数据。label是exchange的名字或者说是一个tag,它描述了payload,而且RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer。AMQP仅仅描述了label,而RabbitMQ决定了如何使用这个label的规则。

Client 1,2,3: 也叫Consumer,数据的接收方。Consumersattach to a broker server (RabbitMQ) and subscribe to a queue。把queue比作是一个有名字的邮箱。当有Message到达某个邮箱后,RabbitMQ把它发送给它的某个订阅者即Consumer。当然可能会把同一个Message发送给很多的Consumer。在这个Message中,只有payload,label已经被删掉了。对于Consumer来说,它是不知道谁发送的这个信息的。就是协议本身不支持。但是当然了如果Producer发送的payload包含了Producer的信息就另当别论了。

 对于一个数据从Producer到Consumer的正确传递,还有三个概念需要明确:exchanges, queues and bindings。

    *Exchanges are where producers publish their messages.*

    *Queuesare where the messages end up and are received by consumers*

    *Bindings are how the messages get routed from the exchange to particular queues.*

还有几个概念是上述图中没有标明的,那就是Connection(连接),Channel(通道,频道)。
Connection: 就是一个TCP的连接。Producer和Consumer都是通过TCP连接到RabbitMQ Server的。以后我们可以看到,程序的起始处就是建立这个TCP连接。

Channels: 虚拟连接。它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。

那么,为什么使用Channel,而不是直接使用TCP连接?

对于OS来说,建立和关闭TCP连接是有代价的,频繁的建立关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,这也限制了系统处理高并发的能力。但是,在TCP连接中建立Channel是没有上述代价的。对于Producer或者Consumer来说,可以并发的使用多个Channel进行Publish或者Receive。有实验表明,1s的数据可以Publish10K的数据包。当然对于不同的硬件环境,不同的数据包大小这个数据肯定不一样,但是我只想说明,对于普通的Consumer或者Producer来说,这已经足够了。如果不够用,你考虑的应该是如何细化split你的设计。
4.进一步的细节阐明
4.1 使用ack确认Message的正确传递

默认情况下,如果Message 已经被某个Consumer正确的接收到了,那么该Message就会被从queue中移除。当然也可以让同一个Message发送到很多的Consumer。

如果一个queue没被任何的Consumer Subscribe(订阅),那么,如果这个queue有数据到达,那么这个数据会被cache,不会被丢弃。当有Consumer时,这个数据会被立即发送到这个Consumer,这个数据被Consumer正确收到时,这个数据就被从queue中删除。

那么什么是正确收到呢?通过ack。每个Message都要被acknowledged(确认,ack)。我们可以显示的在程序中去ack,也可以自动的ack。如果有数据没有被ack,那么:

RabbitMQ Server会把这个信息发送到下一个Consumer。

如果这个app有bug,忘记了ack,那么RabbitMQ Server不会再发送数据给它,因为Server认为这个Consumer处理能力有限。

而且ack的机制可以起到限流的作用(Benefitto throttling):在Consumer处理完成数据后发送ack,甚至在额外的延时后发送ack,将有效的balance Consumer的load。

当然对于实际的例子,比如我们可能会对某些数据进行merge,比如merge 4s内的数据,然后sleep 4s后再获取数据。特别是在监听系统的state,我们不希望所有的state实时的传递上去,而是希望有一定的延时。这样可以减少某些IO,而且终端用户也不会感觉到。

4.2 Reject a message

有两种方式,第一种的Reject可以让RabbitMQ Server将该Message 发送到下一个Consumer。第二种是从queue中立即删除该Message。

4.3 Creating a queue

Consumer和Procuder都可以通过 queue.declare 创建queue。对于某个Channel来说,Consumer不能declare一个queue,却订阅其他的queue。当然也可以创建私有的queue。这样只有app本身才可以使用这个queue。queue也可以自动删除,被标为auto-delete的queue在最后一个Consumer unsubscribe后就会被自动删除。那么如果是创建一个已经存在的queue呢?那么不会有任何的影响。需要注意的是没有任何的影响,也就是说第二次创建如果参数和第一次不一样,那么该操作虽然成功,但是queue的属性并不会被修改。

那么谁应该负责创建这个queue呢?是Consumer,还是Producer?

如果queue不存在,当然Consumer不会得到任何的Message。但是如果queue不存在,那么Producer Publish的Message会被丢弃。所以,还是为了数据不丢失,Consumer和Producer都try to create the queue!反正不管怎么样,这个接口都不会出问题。

queue对load balance的处理是完美的。对于多个Consumer来说,RabbitMQ 使用循环的方式(round-robin)的方式均衡的发送给不同的Consumer。

4.4 Exchanges

从架构图可以看出,Procuder Publish的Message进入了Exchange。接着通过“routing keys”, RabbitMQ会找到应该把这个Message放到哪个queue里。queue也是通过这个routing keys来做的绑定。

 有三种类型的Exchanges:direct, fanout,topic。 每个实现了不同的路由算法(routing algorithm)。

· Direct exchange: 如果 routing key 匹配, 那么Message就会被传递到相应的queue中。其实在queue创建时,它会自动的以queue的名字作为routing key来绑定那个exchange。

· Fanout exchange: 会向响应的queue广播。

· Topic exchange: 对key进行模式匹配,比如ab可以传递到所有ab的queue。

4.5 Virtual hosts

每个virtual host本质上都是一个RabbitMQ Server,拥有它自己的queue,exchagne,和bings rule等等。这保证了你可以在多个不同的application中使用RabbitMQ。

写个Hello World测试一下

说了这么久理论(全是复制粘贴),现在来动手写写代码来体验一下吧。(就是这个项目里面的rabbit)
首先我们用idea创建一个Maven项目,然后引入依赖

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

然后我们再创建一个Producer类,也就是生产者,代码如下:

package com.shang;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 /**
  * @author shangwei
  */
public class Producer {

	 public static void main(String[] args) throws IOException, TimeoutException {
		//创建连接工厂
		ConnectionFactory factory = new ConnectionFactory();
		factory.setUsername("guest");
		factory.setPassword("guest");
		//设置 RabbitMQ 地址
		factory.setHost("localhost");
		//建立到代理服务器到连接
		Connection conn = factory.newConnection();
		//获得信道
		Channel channel = conn.createChannel();
		//声明交换器
		String exchangeName = "hello-exchange";
		channel.exchangeDeclare(exchangeName, "direct", true);

		String routingKey = "HHHHH";
		//发布消息
		byte[] messageBodyBytes = "shangwei".getBytes();
		channel.basicPublish(exchangeName, routingKey, null, messageBodyBytes);

		channel.close();
		conn.close();
    	}
}

然后我们再创建消费者Consumer类

package com.shang;

import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
 * @author shangwei
 */
public class Consumer {

	public static void main(String[] args) throws IOException, TimeoutException {
		ConnectionFactory factory = new ConnectionFactory();
		factory.setUsername("guest");
		factory.setPassword("guest");
		factory.setHost("localhost");
		//建立到代理服务器到连接
		Connection conn = factory.newConnection();
		//获得信道
		final Channel channel = conn.createChannel();
		//声明交换器
		String exchangeName = "hello-exchange";
		channel.exchangeDeclare(exchangeName, "direct", true);
		//声明队列
		String queueName = channel.queueDeclare().getQueue();
		String routingKey = "HHHHH";
		//绑定队列,通过键 hola 将队列和交换器绑定起来
		channel.queueBind(queueName, exchangeName, routingKey);

		while(true) {
			//消费消息
			boolean autoAck = false;
			String consumerTag = "";
			channel.basicConsume(queueName, autoAck, consumerTag, new DefaultConsumer(channel) {
				@Override
				public void handleDelivery(String consumerTag,
				                           Envelope envelope,
				                           AMQP.BasicProperties properties,
				                           byte[] body) throws IOException {
					String routingKey = envelope.getRoutingKey();
					String contentType = properties.getContentType();
					System.out.println("消费的路由键:" + routingKey);
					System.out.println("消费的内容类型:" + contentType);
					long deliveryTag = envelope.getDeliveryTag();
					//确认消息
					channel.basicAck(deliveryTag, false);
					System.out.print("消费的消息体内容:");
					String bodyStr = new String(body, "UTF-8");
					System.out.println(bodyStr);

				}
			});
		}
	}
}

写完了这两个类以后我们再开启之前的RabbitMQ,我们可以直接点击windows的左下角菜单栏,然后我们找到RabbitMQ,如下图所示
在这里插入图片描述

这里面主要有三个重要的,一个是start,一个是stop,还有一个就是命令行。我们先将RabbitMQ 启动。然后我们就将上面之前写的Consumer类开启,然后再打开Producer类. 至于为什么先开启Consumer,那就自己慢慢去思考一下。注意一定要打开RabbitMQ,然后就可以在idea上面看到如下所示的运行结果
在这里插入图片描述

可以一直执行生产者,这样在消费者这边类里就可以看到下面一直在重复出现。

RabbitMQ中插件管理

注意上面说了一下RabbitMQ的命令行,我们可以在这个命令行里输入命令执行相应的操作。

比如:rabbitmq-plugins <command> [<command options>]
Commands:
	list [-v] [-m] [-E] [-e] [<pattern>]  显示所有的的插件。-v 显示版本 -m 显示名称 -E 显示明确已经开启的 -e显示明确的和暗中开启的
	enable <plugin> ...   开启一个插件
	disable <plugin> ...  关闭一个插件

如下所示

在这里插入图片描述

然后我们再重启一下RabbitMQ,如下图所示:
在这里插入图片描述

现在我们在浏览器输入 localhost:15672 账号和密码都是guest。现在我们就可以在界面下仔细看下RabbitMQ了
在这里插入图片描述

在这里可以看Exchange和Queue的详细信息,还有刚刚发送的消息。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RabbitMQ 是一个开源的消息队列系统,它可以用于在应用程序之间传递消息。下面是一个简单的 RabbitMQ 中文教程: 1. 安装 RabbitMQ:你可以从 RabbitMQ 的官方网站下载适合你操作系统的安装包,并按照官方文档的说明进行安装。 2. 启动 RabbitMQ 服务器:安装完成后,你可以启动 RabbitMQ 服务器。在大多数情况下,它会自动启动并运行在默认端口上(5672)。 3. 创建连接:使用你的编程语言(如 Python、Java、JavaScript等)连接到 RabbitMQ 服务器。你需要提供服务器的地址、端口、用户名和密码等信息来建立连接。 4. 创建队列:使用 RabbitMQ 的管理界面或编程语言的客户端库来创建一个队列。队列用于存储消息,应用程序可以通过队列收发消息。 5. 发布消息:使用编程语言的客户端库将消息发布到队列中。你可以指定消息的内容和其他属性。 6. 消费消息:使用编程语言的客户端库从队列中消费消息。你可以注册一个消费者来处理从队列中获取到的消息。 7. 确认消息:在消费消息后,你可以发送确认给 RabbitMQ,表示消息已被处理。RabbitMQ 将从队列中删除已确认的消息。 8. 关闭连接:当你完成所有操作后,记得关闭与 RabbitMQ 的连接。 这只是一个简单的 RabbitMQ 中文教程,你可以根据需要深入学习 RabbitMQ 的更多特性和用法。文档和官方网站上有更详细的教程和示例代码可供参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值