RabbitMQ知识整合及探究

RabbitMQ知识整合及探究

1、总体介绍

1.1 RabbitMQ是一个由Erlang语言编写的AMQP协议的开源实现.

1.2 RabbitMQ是信息传输的中间者.本质上,他从生产者(producers)接收消息,转发这些消息给消费者(consumers).换句话说,他能够按根据你指定的规则进行消息转发、缓冲、和持久化,解耦了生产者和消费者。

1.3 有着分布式,高可用,持久化,可靠,安全的特点

1.4 RabbitMQ是支持多种客户端的开发。

2、开发环境及配置

    2.1下载安装Erlang

    因为RabbitMQ是建立在Erlang OTP平台上的,因此安装RabbitMQ之前需要安装Erlang.配置环境变量”ERLANG_HOME”指向安装Erlang的目录,并把”%ERLANG_HOME%\bin”加到系统环境变量Path中.

    2.2RabbitMQ

    安装RabbitMQ Server成功,同样需要配置环境变量”RABBITMQ_BASE”指向安装目录,配置”%RABBITMQ_BASE%\sbin”到Path中。如果安装成功后双击【rabbitmq-server.bat】启动不了,提示【node with name rabbit already running on ***】的错误,就试着删除【C:\Users\Administrator\AppData\Roaming\rabbitmq】这个目录,如果还是没有效果,就点击开始菜单,在所有程序》RabbitMQ Service 》RabbitMQ Service stop,先关闭已经启动的RabbitMQ,然后再启动。安装错误

    2.3rabbit-client.jar包

    因为我们针对的是Android应用,所以我们需要下载一个RabbitMQ针对java语言的jar包,导入到项目中。

3、处理流程及实例

    3.1RabbitMQ中基本概念理解

Rabbit基本概念图

    1)RabbitMQ Server

    也叫broker server,是一种传输服务,维护一条从Producer到Consumer的路线

    2)Producer

    即上图中的ClientA&ClientB,是数据的发送方.作用是创造消息和发送消息到broker server.传输的Message分为两个部分payload和label。payload就是传输的数据,而label就是exchange的名字或者说是一个tag。RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer

    3)Consumer

    即是上图中的Client1,2,3,表示数据的接收方。Consumer依附于一个broker server 并且订阅一个queue。Consumer可以从queue中获取Message,并且做出相应的处理

    4)Queues

    队列,是消息的终点,可以理解成分装消息的容器。消息一直就在里面,直到有Consumer连接到这个队列并将消息取走(不过也可以设置成一旦消息进入这个队列,次消息就被删除)

    5)Exchanges

    交换机,可以理解成有路由表的路由程序。每一个消息都有一个routingKey的属性(就是一个简单的字符串),当中有系列的binding机制即路由规则。

    6)Bindings

    Binding即是一种路由规则,一个绑定就是一个基于RoutingKey将Exchange和Queue链接起来的路由规则。

    7)Connection

    就是一个TCP的连接。Producer和Consumer都是通过TCP连接到RabbitMQ Server的。以后我们可以看到,程序的起始处就是建立这个TCP连接。

    API: 

1
new ConnectionFactory();    //Connection工厂类的无参构造

    得到ConnectionFactory实例之后,其也有许多的set方法,比如设置主机地址和端口号,设置用户名和密码,设置虚拟地址,设置连接超时等等,不在做一一阐述。最后通过下列方法

1
factory.newConnection();

  得到Connection对象的实例。

  newConnection还有其他的重载方法,一下是参数较多的一个方法。

1
newConnection( ExecutorService executor,Address[] addrs,String clientProvidedName);

    //executor:为消费者连接的线程池

    //addrs:一个已知的代理地址列表,如果自动回复连接启用,遇到重连的情况会在addrs的地址列表中随机选取一个

    //clientProvidedName:特定应用程序的连接名称,RabbitMQ如果支持它,其将会在UI管理中显示出来。这个值不一定是唯一的,所以不能使用作为一个连接标识符如HTTP API请求。

    8)Channel

    虚拟连接。它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。官方推荐是如果是多线程并发执行任务的时候,在一个Connection对象上创建多个Channel,如果需要公用一个Channel,至少要保证共用Channel的线程发送消息必须是串行的。

1
connetion.creatChannel() //创建Channel实例
    9)Virtual Host

    虚拟的地址,其实是一个虚拟概念,类似于权限控制组,一个Virtual Host里面可以有若干个Exchange和Queue,但是权限控制的最小粒度是Virtual Host。

    3.2消息的发布和接收

    前文我们已经简单的介绍了Exchange,现在我们来深入了解一下。

    RabbitMQ消息模型的核心理念是生产者永远不会直接发送任何消息给队列,一般的情况生产者甚至不知道消息应该发送到哪些队列。

    相反的,生产者只能发送消息给转发器(Exchange)。转发器是非常简单的,一边接收从生产者发来的消息,另一边把消息推送到队列中。转发器必须清楚的知道消息如何处理它收到的每一条消息。是否应该追加到一个指定的队列?是否应该追加到多个队列?或者是否应该丢弃?这些规则通过转发器的类型进行定义,以下是声明转发器的方法和发送消息的方法。

1
channel.exchangeDeclare(newExchangeName, "direct" );

    //声明Exchange参数一:转发器名称;参数二:转发器路由类型

   //该方法还有一些重载,可以设置是否为持久的Exchange,是否可以自动删除等

1
channel.basicPublish( "logs" , "" , null , message.getBytes());

    第一个参数为转发器的名称,第二个参数是routingKey,第三个参数是MessageProperties,第四个参数就是传递的消息。Exchange会判断routingKey再决定把消息发送到哪个队列。

    3.2.1临时队列

    如果想要实现这么一个需求:我们想要接收到所有的消息,而且我们也只对当前正在传递的数据的感兴趣。这个时候RabbitMQ为我们提供了一个临时队列。

    第一, 无论什么时间连接到Rabbit我们都需要一个新的空的队列。为了实现,我们可以使用随机数创建队列,或者更好的,让服务器给我们提供一个随机的名称。
    第二, 一旦消费者与Rabbit断开,消费者所接收的那个队列应该被自动删除。

    在java的RabbitMQ中我们可以使用queueDeclare()方法,不传递任何参数,来创建一个非持久的、唯一的、自动删除的队列且队列名称由服务器随机产生,方法如下:

1
channel.queueDeclare();
    3.2.2绑定

    我们已经创建了一个转发器和队列,我们现在需要通过binding告诉转发器把消息发送给我们的队列。

1
channel.queueBind(queueName,“logs”, routingKey);

    参数1:队列名称 ;参数2:转发器名称;参数3:绑定键名称。

    这个方法还有一个四参的重载,第四个参数是一个Map集合用于其他的绑定参数的设置。

四种转发器类型:

    1)Fanout

    相当于广播,无论绑定键的名称是什么,消息都会被发送到于该Exchange绑定的Queue中。

    2)Direct

    消息会被推送至绑定键(binding key)和消息发布附带的选择键(routing key)完全匹配的队列。

direct1

    当然是用一个绑定键也可以与多个Queue相绑定:

多重绑定

    3)Topic

    发往主题类型的转发器的消息不能随意的设置选择键(routing_key),必须是由点隔开的一系列的标识符组成。

    绑定键和选择键的形式一样。主题类型的转发器背后的逻辑和直接类型的转发器很类似:一个附带特殊的选择键将会被转发到绑定键与之匹配的队列中。需要注意的是:关于绑定键有两种特殊的情况。
    *可以匹配一个标识符。
    #可以匹配0个或多个标识符。

topic

    比如说我们的绑定逻辑是这么写的:

1
channel.queueBind(queueName, EXCHANGE_NAME, "*.orange.*" );

    我们的绑定键是"*.orange.*"

    然后从服务端发来的Message中RoutingKey中含有"*.orange.*"特征的话,该Message就会被发往相应的队列。

    3.3RabbitMQ的工作队列

    3.3.1消息应答机制

    如果执行一个任务需要几秒钟,可能一个Consumer在执行任务时发生中断。而RabbitMQ默认的会将一个一个的发送消息给下一个Consumer,而不考虑每个任务的时长,且是一次性分配的,并非一个一个分配的。而且RabbitMQ一旦交付了一个信息给消费者,会马上从内存中移除这个信息。这种情况下,我们会丢失已经转发给这个工作者且他还未执行的消息。(这种情况只会发生在一条Queue中有多个Consumer的情形)

    而消息的应答机制是,在未关闭消息的ACK机制的情况下, 当消息从队列中提取后, 在未明确获取确认信息之前, 队列中的消息是不会被删除的. 这样, 流程上就变成, 当消息被提取之后, 队列中的这条消息处于"等待确认"的状态. 如果反馈"成功"给队列, 则消息可以安全地被删除了。如果反馈"拒绝"给队列, 则消息可能还需要再次被其它 Consumer提取。

    我们可以通过消息的应答机制,来确保当Consumer被杀死的时候,RabbitMQ会把还未处理完的信息重新转发给别的消费者。

    具体代码如下:

    1)打开消息的应答机制

打开消息应答机制

   2)手动发送应答

手动发送应答

   以上就是最为基本的应答机制使用的是basicAck方法,除了这个方法外还有两个发送应答的方法,分别是basicNack和basicReject。

    其区别为前者是积极的确认,即获取消息后成功的处理消息,后两者为消极的确认,为消息并不会处理。

    而两个消极的响应唯一的区别就是basicReject方法只能处理一条消息,而basicNack方法可以处理多条消息。

API:

1
mChannel. basicAck( long deliveryTag, boolean multiple);

//deliveryTag:在AMQP.Basic.GetOk 或 AMQP.Basic.Deliver中获取的一个tag

//multiple:如果是true,表示确认所有的消息,直到提供的tag值,如果是false,表示仅仅确认tag值所为提供的消息

1
mChannel. basicNack( long deliveryTag, boolean multiple, boolean requeue);

//deliveryTag:在AMQP.Basic.GetOk 或 AMQP.Basic.Deliver中获取的一个tag

//multiple:如果是true,表示拒绝所有的消息,直到提供的tag值,如果是false,表示仅仅拒绝tag值所为提供的消息

//requeue:如果是true,表示所拒绝的消息会重新再queue中排队,如果是false,表示该消息会被丢弃

1
mChannel. basicReject( long deliveryTag, boolean requeue);

//deliveryTag:在AMQP.Basic.GetOk 或 AMQP.Basic.Deliver中获取的一个tag

//requeue:如果是true,表示所拒绝的消息会重新再queue中排队,如果是false,表示该消息会被丢弃

    3.3.2消息持久化

    通过消息的应答机制,我们可以做到即使Consumer即使被杀死了,消息也不会丢失,但是如果RabbitMQ服务器停止了消息依然会丢失,我们可以通过消息的持久化设置确保消息不会丢失:

    1)交换机持久化

1
mChannel.exchangeDeclare(newExchangeName, "direct"
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值