AMQP ,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。

AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

安装

Rabbit MQ 是建立在强大的Erlang OTP平台上,因此安装RabbitMQ之前要先安装Erlang。

erlang:http://www.erlang.org/download.html

rabbitmq:http://www.rabbitmq.com/download.html

注意:

1.现在先别装最新的 3.6.3 ,本人在安装完最新的版本,queue 队列有问题,降到了 3.6.2 就解决了。

2.默认安装的Rabbit MQ 监听端口是:5672

Listening ports

Protocol

Bound to

Port

amqp

0.0.0.0

5672

amqp

::

5672

clustering

::

25672

Web contexts

Context

Bound to

Port

SSL

Path

RabbitMQ Management

0.0.0.0

15672

/

安装完成后,在RabbitMQ的安装目录的sbin会有:rabbitmq-server.bat

在cmd下(以管理员方式运行):进入sbin目录,运行rabbitmq-server start

监控配置

在cmd下(以管理员方式运行):进入sbin目录,运行rabbitmq-plugins.bat enable rabbitmq_management

安装完成之后以管理员身份启动

  1. rabbitmq-service.bat stop
  2. rabbitmq-service.bat install
  3. rabbitmq-service.bat start

浏览器访问http://localhost:15672  默认账号:guest  密码:guest

消息队列的特性

解耦:消息的生产者与消费者均基于AMQP协议(相同的接口与规范)进行发送与接收消息,互相不存依赖;

冗余:消息只有处理了才会被删除,除非明确允许多个消费者可以收到同一消息的多个副本,否则每个消息只会被单个消费者接收并处理;

扩展性:可增加或减少多个消息的生产者与消费者,两者的改动均不会影响到双方;

灵活性 & 峰值处理能力:因为有良好的扩展性,所以可视服务器的处理情况【可称为:消费者】(比如:高并发负载过大)动态的增减服务器,以提提高处理能力(可称为:负载均衡);

可恢复性:消息的生产者与消费者不论哪一方出现问题,均不会影响消息的正常发出与接收(当然单一的生产者与消费者除外,如果是这样也就没有必要使用分布式消息队列);

送达保证:只有消息被确认成功处理后才会被删除,否则会重新分发给其它的消费者进行处理,直到确认处理成功为止;

排序保证:先进先出是队列的基本特性;

缓冲:同一时间有多个消息进入消息队列,但是同一时间可以指定一个多个消息被消息者接收并处理,其余的消息处理等待状态,这样可以降低服务器的压力,起到缓冲的作用;

理解数据流:传递的消息内容以字节数组为主,但可以将对象序列化后成字节数组,然后在消费者接收到消息后,可反序列化成对象并进行相关的处理,应用场景:CQRS;

异步通信:允许将一个或多个消息放入消息队列,但并不立即处理它,而是在恰当的时候再去由一个或多个消费者分别接收并处理它们;

应用场景:针对高并发且无需立即返回处理结果的时候,可以考虑使用消息队列,如果处理需要立即返回结果则不适合;

 

RabbitMQ的基本用法

使用RabbitMQ客户端就必需在项目中引用其相关的组件,这里可以通过NuGet安装或从官网下载再引用均可,方法很简单,不再重述;

1.普通用法:采用默认的exchange(交换机,或称路由器)+默认的exchange类型:direct+noAck(自动应答,接收就应答)

/// <summary>

/// 消息发送者,一般用在客户端

/// </summary>

class RabbitMQPublish

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel()) //创建一个通道

{

channel.QueueDeclare("hello", false, false, false, null);//创建一个队列

string message = "";

while (message!="exit")

{

Console.Write("Please enter the message to be sent:");

message = Console.ReadLine();

var body = Encoding.UTF8.GetBytes(message);

channel.BasicPublish("", "hello", null, body); //发送消息

Console.WriteLine("set message: {0}", message);

}

}

}

}

}

/// <summary>

/// 消费者,一般用在服务端

/// </summary>

class RabbitMQConsume

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel())//创建一个通道

{

channel.QueueDeclare("hello", false, false, false, null);//创建一个队列

var consumer = new QueueingBasicConsumer(channel);//创建一个消费者

channel.BasicConsume("hello", true, consumer);//开启消息者与通道、队列关联

Console.WriteLine(" waiting for message.");

while (true)

{

var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();//接收消息并出列

var body = ea.Body;//消息主体

var message = Encoding.UTF8.GetString(body);

Console.WriteLine("Received {0}", message);

if (message == "exit")

{

Console.WriteLine("exit!");

break;

}

}

}

}

}

}

2.负载均衡处理模式:采用默认的exchange(交换机)+智能分发+默认的exchange类型:direct+手动应答

消息生产者/发布者代码与上面相同;

以下是消费者代码:

/// <summary>

/// 消费者,一般用在服务端

/// </summary>

class RabbitMQConsume

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel())//创建一个通道

{

channel.QueueDeclare("hello", false, false, false, null);//创建一个队列

channel.BasicQos(0, 1, false);//在一个工作者还在处理消息,并且没有响应消息之前,不要给他分发新的消息。相反,将这条新的消息发送给下一个不那么忙碌的工作者。

var consumer = new QueueingBasicConsumer(channel);//创建一个消费者

channel.BasicConsume("hello", false, consumer);//开启消息者与通道、队列关联

Console.WriteLine(" waiting for message.");

while (true)

{

var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();//接收消息并出列

var body = ea.Body;//消息主体

var message = Encoding.UTF8.GetString(body);

Console.WriteLine("Received {0}", message);

channel.BasicAck(ea.DeliveryTag, false);

if (message == "exit")

{

Console.WriteLine("exit!");

break;

}

Thread.Sleep(1000);

}

}

}

}

}

3.消息持久化模式:在2的基础上加上持久化,这样即使生产者或消费者或服务端断开,消息均不会丢失

/// <summary>

/// 消息发送者,一般用在客户端

/// </summary>

class RabbitMQPublish

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel()) //创建一个通道

{

channel.QueueDeclare("hello", true, false, false, null);//创建一个队列,第2个参数为true表示为持久队列

var properties = channel.CreateBasicProperties();

//properties.SetPersistent(true);这个方法提示过时,不建议使用

properties.DeliveryMode = 2;//1表示不持久,2.表示持久化

string message = "";

while (message!="exit")

{

Console.Write("Please enter the message to be sent:");

message = Console.ReadLine();

var body = Encoding.UTF8.GetBytes(message);

channel.BasicPublish("", "hello", properties, body); //发送消息

Console.WriteLine("set message: {0}", message);

}

}

}

}

}

/// <summary>

/// 消费者,一般用在服务端

/// </summary>

class RabbitMQConsume

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel())//创建一个通道

{

channel.QueueDeclare("hello", true, false, false, null);//创建一个队列,第2个参数为true表示为持久队列

channel.BasicQos(0, 1, false);//在一个工作者还在处理消息,并且没有响应消息之前,不要给他分发新的消息。相反,将这条新的消息发送给下一个不那么忙碌的工作者。

var consumer = new QueueingBasicConsumer(channel);//创建一个消费者

channel.BasicConsume("hello", false, consumer);//开启消息者与通道、队列关联

Console.WriteLine(" waiting for message.");

while (true)

{

var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();//接收消息并出列

var body = ea.Body;//消息主体

var message = Encoding.UTF8.GetString(body);

Console.WriteLine("Received {0}", message);

channel.BasicAck(ea.DeliveryTag, false);

if (message == "exit")

{

Console.WriteLine("exit!");

break;

}

Thread.Sleep(1000);

}

}

}

}

}

4.广播订阅模式:定义一个交换机,其类型设为广播类型,发送消息时指定这个交换机,消费者的消息队列绑定到该交换机实现消息的订阅,订阅后则可接收消息,未订阅则无法收到消息

/// <summary>

/// 消息发送者/生产者,一般用在客户端

/// </summary>

class RabbitMQPublish

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel()) //创建一个通道

{

channel.ExchangeDeclare("publish", "fanout",true);//定义一个交换机,且采用广播类型,并设为持久化

string queueName = channel.QueueDeclare("hello", true, false, false, null);//创建一个队列,第2个参数为true表示为持久队列,这里将结果隐式转换成string

var properties = channel.CreateBasicProperties();

//properties.SetPersistent(true);这个方法提示过时,不建议使用

properties.DeliveryMode = 2;//1表示不持久,2.表示持久化

string message = "";

while (message!="exit")

{

Console.Write("Please enter the message to be sent:");

message = Console.ReadLine();

var body = Encoding.UTF8.GetBytes(message);

channel.BasicPublish("publish", "hello", properties, body); //发送消息,这里指定了交换机名称,且routeKey会被忽略

Console.WriteLine("set message: {0}", message);

}

}

}

}

}

/// <summary>

/// 消费者,一般用在服务端

/// </summary>

class RabbitMQConsume

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel())//创建一个通道

{

channel.ExchangeDeclare("publish", "fanout", true);//定义一个交换机,且采用广播类型,并持久化该交换机,并设为持久化

string queueName = channel.QueueDeclare("hello", true, false, false, null);//创建一个队列,第2个参数为true表示为持久队列

channel.QueueBind(queueName, "publish", "");//将队列绑定到名publish的交换机上,实现消息订阅

channel.BasicQos(0, 1, false);//在一个工作者还在处理消息,并且没有响应消息之前,不要给他分发新的消息。相反,将这条新的消息发送给下一个不那么忙碌的工作者。

var consumer = new QueueingBasicConsumer(channel);//创建一个消费者

channel.BasicConsume(queueName, false, consumer);//开启消息者与通道、队列关联

Console.WriteLine(" waiting for message.");

while (true)

{

var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();//接收消息并出列

var body = ea.Body;//消息主体

var message = Encoding.UTF8.GetString(body);

Console.WriteLine("Received {0}", message);

channel.BasicAck(ea.DeliveryTag, false);//应答

if (message == "exit")

{

Console.WriteLine("exit!");

break;

}

Thread.Sleep(1000);

}

}

}

}

}

5.主题订阅模式:定义一个交换机,其类型设为主题订阅类型,发送消息时指定这个交换机及RoutingKey,消费者的消息队列绑定到该交换机并匹配到RoutingKey实现消息的订阅,订阅后则可接收消息,未订阅则无法收到消息

/// <summary>

/// 消息发送者/生产者,一般用在客户端

/// </summary>

class RabbitMQPublish

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel()) //创建一个通道

{

channel.ExchangeDeclare("publish-topic", "topic", true);//定义一个交换机,且采用广播类型,并持久化该交换机

channel.QueueDeclare("hello-mq", true, false, false, null);//创建一个队列,第2个参数为true表示为持久队列

var properties = channel.CreateBasicProperties();

//properties.SetPersistent(true);这个方法提示过时,不建议使用

properties.DeliveryMode = 2;//1表示不持久,2.表示持久化

string message = "";

while (message!="exit")

{

Console.Write("Please enter the message to be sent:");

message = Console.ReadLine();

var body = Encoding.UTF8.GetBytes(message);

channel.BasicPublish("publish-topic", "hello.test", properties, body); //发送消息,这里指定了交换机名称,且routeKey会被忽略

Console.WriteLine("set message: {0}", message);

}

}

}

}

}

/// <summary>

/// 消费者,一般用在服务端

/// </summary>

class RabbitMQConsume

{

static void Main(string[] args)

{

var factory = new ConnectionFactory();//创建连接工厂并初始连接

factory.HostName = "localhost";

factory.UserName = "zwj";

factory.Password = "www.zuowenjun.cn";

using (var connection = factory.CreateConnection())//创建一个连接

{

using (var channel = connection.CreateModel())//创建一个通道

{

channel.ExchangeDeclare("publish-topic", "topic",true);//定义一个交换机,且采用广播类型,并持久化该交换机

string queueName = channel.QueueDeclare("hello-mq", true, false, false, null);//创建一个队列,第2个参数为true表示为持久队列

channel.QueueBind(queueName, "publish-topic", "*.test");//将队列绑定到路由上,实现消息订阅

channel.BasicQos(0, 1, false);//在一个工作者还在处理消息,并且没有响应消息之前,不要给他分发新的消息。相反,将这条新的消息发送给下一个不那么忙碌的工作者。

var consumer = new QueueingBasicConsumer(channel);//创建一个消费者

channel.BasicConsume(queueName, false, consumer);//开启消息者与通道、队列关联

Console.WriteLine(" waiting for message.");

while (true)

{

var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();//接收消息并出列

var body = ea.Body;//消息主体

var message = Encoding.UTF8.GetString(body);

Console.WriteLine("Received {0}", message);

channel.BasicAck(ea.DeliveryTag, false);//应答

if (message == "exit")

{

Console.WriteLine("exit!");

break;

}

Thread.Sleep(1000);

}

}

}

}

}

交换机路由类型如下:

Direct Exchange:直接匹配,通过Exchange名称+RoutingKey来发送与接收消息;

Fanout Exchange:广播订阅,向所有消费者发布消息,但只有消费者将队列绑定到该路由才能收到消息,忽略RoutingKey;

Topic Exchange:主题匹配订阅,这里的主题指的是RoutingKey,RoutingKey可以采用通配符,如:*或#,RoutingKey命名采用.来分隔多个词,只有消费者将队列绑定到该路由且指定的RoutingKey符合匹配规则时才能收到消息;

Headers Exchange:消息头订阅,消息发布前,为消息定义一个或多个键值对的消息头,然后消费者接收消息时同样需要定义类似的键值对请求头,里面需要多包含一个匹配模式(有:x-mactch=all,或者x-mactch=any),只有请求头与消息头相匹配,才能接收到消息,忽略RoutingKey;

RabbitMQ队列的更多相关文章

  1. Python开发【十一章】:RabbitMQ队列

    RabbitMQ队列 rabbitMQ是消息队列:想想之前的我们学过队列queue:threading queue(线程queue,多个线程之间进行数据交互).进程queue(父进程与子进程进行交互或 ...

  2. Python自动化 【第十一篇】:Python进阶-RabbitMQ队列/Memcached/Redis

     本节内容: RabbitMQ队列 Memcached Redis 1.  RabbitMQ 安装 http://www.rabbitmq.com/install-standalone-mac.htm ...

  3. python RabbitMQ队列/redis

    RabbitMQ队列 rabbitMQ是消息队列:想想之前的我们学过队列queue:threading queue(线程queue,多个线程之间进行数据交互).进程queue(父进程与子进程进行交互或 ...

  4. rabbitmq队列中消息过期配置

    最近公司某个行情推送的rabbitmq服务器由于客户端异常导致rabbitmq队列中消息快速堆积,还曾导致过内存积压导致rabbitmq客户端被block的情况.考虑到行情信息从业务上来说可以丢失部分 ...

  5. Day10 - Python协程、异步IO、redis缓存、rabbitMQ队列

    Python之路,Day9 - 异步IO\数据库\队列\缓存   本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...

  6. python RabbitMQ队列使用(入门篇)

    ---恢复内容开始--- python RabbitMQ队列使用 关于python的queue介绍 关于python的队列,内置的有两种,一种是线程queue,另一种是进程queue,但是这两种que ...

  7. 【python】-- RabbitMQ 队列消息持久化、消息公平分发

    RabbitMQ 队列消息持久化 假如消息队列test里面还有消息等待消费者(consumers)去接收,但是这个时候服务器端宕机了,这个时候消息是否还在? 1.队列消息非持久化 服务端(produc ...

  8. python RabbitMQ队列使用

    python RabbitMQ队列使用 关于python的queue介绍 关于python的队列,内置的有两种,一种是线程queue,另一种是进程queue,但是这两种queue都是只能在同一个进程下 ...

  9. RabbitMQ队列/Redis缓存

    一.RabbitMQ队列 RabbitMQ安装(Centos7安装):1.安装依赖:yum install socat (不安装会报错)2.下载rpm包:wget http://www.rabbitm ...

  10. 异步IO\数据库\队列\缓存\RabbitMQ队列

    本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...

随机推荐

  1. C# 根据路线点集合动态分段

    /// <summary>         /// 将数据根据起.止点分段,返回结果点集合         /// </summary>         public Obse ...

  2. context.response.end()和return的区别

    最近忽然想起这个问题,上网查了很多,觉得这个网友回答的很给力,从本质上剖析了问题.最后发现这篇文章也是转载自博客园的一位网友.http://www.cnblogs.com/adolphyang/p/4 ...

  3. Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)的解决方法

    在连接数据库时,报这个错误,是/var/lib/mysql/ 目录下没有mysql.sock文件,在服务器搜索myslq.sock文件,我的是在/tmp/mysql.sock 解决方法是加一个软链: ...

  4. Angularjs中的嵌套路由ui-router

    先看看ng-router和ui-router的区别 (1)ng-route的局限性:一个页面无法嵌套多个视图,也就是说一个页面只能有包含一个页面一个控制器的切换.  (2)ui-route的改进:在具 ...

  5. hdu 3842 Machine Works(cdq分治维护凸壳)

    题目链接:hdu 3842 Machine Works 详细题解: HDU 3842 Machine Works cdq分治 斜率优化 细节比较多,好好体会一下. 在维护斜率的时候要考虑x1与x2是否 ...

  6. hdu 5997 rausen loves cakes(线段数合并+启发式修改)

    题目链接:hdu 5997 rausen loves cakes 题意: 给你n个点,每个点有一个颜色,现在有两个操作,第一个操作,将颜色x改为颜色y,第二个操作,询问[x,y]区间有多少颜色段(颜色 ...

  7. 本地win7 把数组写入 txt 文本日志 json_encode转换中文,需要加上JSON_UNESCAPED_UNICODE 不适用unicode --仅仅支持php5.4以后

    json_encode 改进 为 json_encode_ex function json_encode_ex($value){ if (version_compare(PHP_VERSION, '5 ...

  8. 嗯,这个BLOG其实是个更新服务器

    2333 软件:http://dwz.cn/NKSGUI

  9. jQuery DOM 元素方法 - index() 方法

    元素的 index,相对于选择器 获得元素相对于选择器的 index 位置. 该元素可以通过 DOM 元素或 jQuery 选择器来指定. 语法 $(selector).index(element) ...

  10. [其他]Android SDK离线文件路径以及安装更新方法

    一.离线安装Android SDK文件路径 转载自:http://www.oschina.net/code/snippet_1539302_45940 Google TV Addon, Android ...