总结消息队列RabbitMQ的基本用法
一、RabbitMQ是什么?
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。
AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
二、消息队列的特性
解耦:消息的生产者与消费者均基于AMQP协议(相同的接口与规范)进行发送与接收消息,互相不存依赖;
冗余:消息只有处理了才会被删除,除非明确允许多个消费者可以收到同一消息的多个副本,否则每个消息只会被单个消费者接收并处理;
扩展性:可增加或减少多个消息的生产者与消费者,两者的改动均不会影响到双方;
灵活性 & 峰值处理能力:因为有良好的扩展性,所以可视服务器的处理情况【可称为:消费者】(比如:高并发负载过大)动态的增减服务器,以提提高处理能力(可称为:负载均衡);
可恢复性:消息的生产者与消费者不论哪一方出现问题,均不会影响消息的正常发出与接收(当然单一的生产者与消费者除外,如果是这样也就没有必要使用分布式消息队列);
送达保证:只有消息被确认成功处理后才会被删除,否则会重新分发给其它的消费者进行处理,直到确认处理成功为止;
排序保证:先进先出是队列的基本特性;
缓冲:同一时间有多个消息进入消息队列,但是同一时间可以指定一个多个消息被消息者接收并处理,其余的消息处理等待状态,这样可以降低服务器的压力,起到缓冲的作用;
理解数据流:传递的消息内容以字节数组为主,但可以将对象序列化后成字节数组,然后在消费者接收到消息后,可反序列化成对象并进行相关的处理,应用场景:CQRS;
异步通信:允许将一个或多个消息放入消息队列,但并不立即处理它,而是在恰当的时候再去由一个或多个消费者分别接收并处理它们;
以上是我的个人理解,也可参看《使用消息队列的 10 个理由》
应用场景:针对高并发且无需立即返回处理结果的时候,可以考虑使用消息队列,如果处理需要立即返回结果则不适合;
三、RabbitMQ环境的安装
1.服务器端:
A.需要先安装Erlang环境,下载地址:http://www.erlang.org/download.html,可能有时无法正常访问,可以通过VPN代理来访问该网站或在其它网站上下载(比如:CSDN)
B.安装RabbitMQ Server(有针对多个操作系统的下载,我这边以WINDOWS平台为主),下载地址:http://www.rabbitmq.com/download.html,
说明:最新版的Erlang及abbitMQ Server安装后,一般WINDOWS环境变量及服务均都已正常安装与并正常启动,可不是最新版或没有安装好,则可执行以下命令:
Setx ERLANG_HOME “C:\Program Files\erl7.1″ -Erlang的-安装目录,也可通过系统属性-->高级-->环境变量来手动设置;
cd C:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.5.6\sbin --切换到RabbitMQ Server的sbin目录下,然后执行如下命令:
rabbitmq-service install
rabbitmq-service enable
rabbitmq-service start
安装并设置OK后,可以通过:rabbitmqctl status查看运行情况、rabbitmqctl list_users查看当前用户、以下命令增加一个新用户:
rabbitmqctl add_user username password
rabbitmqctl set_permissions username ".*" ".*" ".*"
rabbitmqctl set_user_tags username administrator
修改密码:rabbitmqctl change_password username newpassowrd
删除指定的用户:rabbitmqctl delete_user username
列出所有queue:rabbitmqctl list_queues
列出指定queue的信息:rabbitmqctl list_queues [the queue name] messages_ready messages_unacknowledged
列出所有exchange:rabbitmqctl list_exchanges
列出所有binding:rabbitmqctl list_bindings
安装基于web的管理插件:rabbitmq-plugins.bat enable rabbitmq_management
当然还有其它的命令,大家可以去查看官网及其它资料,但我认为知道以上的命令足够用了
四、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的基本用法的更多相关文章
- openstack (共享服务) 消息队列rabbitmq服务
云计算openstack共享组件——消息队列rabbitmq(3) 一.MQ 全称为 Message Queue, 消息队列( MQ ) 是一种应用程序对应用程序的通信方法.应用程序通过读写出入队 ...
- C#中使用消息队列RabbitMQ
在C#中使用消息队列RabbitMQ 2014-10-27 14:41 by qy1141, 745 阅读, 2 评论, 收藏, 编辑 1.什么是RabbitMQ.详见 http://www.rabb ...
- node使用消息队列RabbitMQ一
基础发布和订阅 消息队列RabbitMQ使用 1 安装RabbitMQ服务器 安装erlang服务 下载地址 http://www.erlang.org/downloads 安装RabbitMQ 下载 ...
- 消息队列--RabbitMQ(一)
1.消息队列概述 可以理解为保存消息的一个媒介/或者是个容器,与之相关有两个概念(即生产者(Publish)与消费者(Consumer)).所谓生产者,就是生产创造消息的一方,那么,消费者便是从队列中 ...
- (二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念
原文:(二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念 没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. Rabbit ...
- (一)RabbitMQ消息队列-RabbitMQ的优劣势及产生背景
原文:(一)RabbitMQ消息队列-RabbitMQ的优劣势及产生背景 本篇并没有直接讲到技术,例如没有先写个Helloword.我想在选择了解或者学习一门技术之前先要明白为什么要现在这个技术而不是 ...
- ASP.NET Core消息队列RabbitMQ基础入门实战演练
一.课程介绍 人生苦短,我用.NET Core!消息队列RabbitMQ大家相比都不陌生,本次分享课程阿笨将给大家分享一下在一般项目中99%都会用到的消息队列MQ的一个实战业务运用场景.本次分享课程不 ...
- 消息队列rabbitmq/kafka
12.1 rabbitMQ 1. 你了解的消息队列 rabbitmq是一个消息代理,它接收和转发消息,可以理解为是生活的邮局.你可以将邮件放在邮箱里,你可以确定有邮递员会发送邮件给收件人.概括:rab ...
- nodejs操作消息队列RabbitMQ
一. 什么是消息队列 消息队列(Message Queue,简称MQ),从字面意思上看,本质是个队列,FIFO先入先出,只不过队列中存放的内容是message而已.其主要用途:不同进程Process/ ...
随机推荐
- .NET Core下使用gRpc公开服务(SSL/TLS)
一.前言 前一阵子关于.NET的各大公众号都发表了关于gRpc的消息,而随之而来的就是一波关于.NET Core下如何使用的教程,但是在这众多的教程中基本都是泛泛而谈,难以实际在实际环境中使用,而该篇 ...
- UML-用例图
用例图是指由参与者.用例以及它们之间的关系构成的用于描述系统功能的视图.用例图是被称为参与者的外部用户所能观察到的系统功能的模型图,呈现了一些参与者和一些用例,以及它们之间的关系,主要用于对系统.子系 ...
- 图解集合2:LinkedList
初识LinkedList 上一篇中讲解了ArrayList,本篇文章讲解一下LinkedList的实现. LinkedList是基于链表实现的,所以先讲解一下什么是链表.链表原先是C/C++的概念,是 ...
- Powershell--批量拆分SQL语句为事务并批处理
作为DBA,时不时会遇到将数据导入到数据库的情况,假设业务或研发提供一个包含上百万行INSERT语句的脚本文件,而且这些INSERT 语句没有使用GO来进行批处理拆分,那么直接使用SQLCMD来执行会 ...
- 【译】用jQuery 处理XML-- jQuery与XML
用jQuery 处理XML--写在前面的话 用jQuery 处理XML-- DOM(文本对象模型)简介 用jQuery 处理XML--浏览器中的XML与JavaScript 用jQuery 处理XML ...
- 据说每个大牛、小牛都应该有自己的库——Ajax
蹉跎到今天终于要写Ajax部分了,平时工作中除了选择器我用jQuery的最多的就是ajax,所以这部分在自己的框架中必不可少. XMLHttpRequest 我以为对每个使用过Ajax的人来说XMLH ...
- 爱上MVC3~在控制器或Action上动态设定模板页(Layout)
回到目录 很多境况下,我们需要设置自己模块的layout,即它的布局页面,在MVC2中叫它模板页面,你可以在return view方法时设置它,当然,这不是一种好方法,因为我不想每个action都去设 ...
- Atitit sql执行计划
Atitit sql执行计划 1.1. 首先要搞明白什么叫执行计划? 执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生的 Oracle中的执行计划 ...
- Atitit 循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate).
Atitit 循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate). 1.1. 循环算是最基础的概念, 凡是重复执行一段代码, 都可以称之为循环. ...
- 搭建LNAMP环境(五)- PHP7源码安装Redis和Redis拓展
上一篇:搭建LNAMP环境(四)- 源码安装PHP7 一.安装Redis 1.创建redis用户组和用户 groupadd redis useradd -r -g redis -s /sbin/nol ...