RabbitMQ原理与相关操作(一)
小编是菜鸟一枚,最近想试试MQ相关的技术,所以自己看了下RabbitMQ官网,试着写下自己的理解与操作的过程。
刚开始的第一篇,原理只介绍 生产者、消费者、队列,至于其他的内容,会在后续中陆续补齐。
引入MQ话题
什么时候会用到MQ
可能很多人有疑惑:MQ到底是什么?哪些场景下要使用MQ?
前段时间安装了RabbitMQ,现在就记录下自己的学习心得吧。
首先看段程序:
class Program
{
static void Main(string[] args)
{
new Thread(Write).Start();
new Thread(Write).Start();
new Thread(Write).Start();
new Thread(Write).Start();
} public static void WriteLog(int i)
{
using (FileStream f = new FileStream(@"d:\\test.txt", FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(f, Encoding.Default))
{
sw.Write(i);
}
}
} public static void Write()
{
for (int i = ; i < ; i++)
{
WriteLog(i);
}
}
}
仅仅从代码上看,没有觉得任何问题对吧?编译也是通过的,但是执行时,出现一个问题:

当然,这仅仅是一个小的案例,类似这种多线程写文件造成的问题, 就应该使用MQ了。
MQ的使用场景大概包括解耦,提高峰值处理能力,送达和排序保证,缓冲等。
MQ概述
消息队列技术是分布式应用间交换信息的一种技术。
消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读走。
通过消息队列,应用程序可独立地执行--它们不需要知道彼此的位置、或在继续执行前不需要等待接收程序接收此消息。
MQ主要作用是接受和转发消息。你可以想想在生活中的一种场景:当你把信件的投进邮筒,邮递员肯定最终会将信件送给收件人。我们可以把MQ比作 邮局和邮递员。
MQ和邮局的主要区别是,它不处理消息,但是,它会接受数据、存储消息数据、转发消息。
RabbitMQ术语
生产者:
消息发送者,在MQ中被称为生产者(producer),一个发送消息的应用也被叫做生产者,用P表示

消费者:
生产者“生产”出消息后,最终由谁消费呢?等待接受消息的应用程序,我们称之为消费者(Consuming ),用C表示

队列:
消息只能存储在队列(queue )中。尽管消息在rabbitMQ和应用程序间流通,但是队列却是存在于RabbitMQ内部。
一个队列不受任何限制,它可以存储你想要存储的消息量,它本质上是一个无限的缓冲区。
多个生产者可以向同一个队列发送消息,多个消费者可以尝试从同一个消息队列中接收数据。
一个队列像下面这样(上面是它的队列名称)

注意:
生产者、消费者、中间件不必在一台机器上,实际应用中也是绝大多数不在一起的。我们可以用一张图表示RabbitMQ的构造:

注:此图片摘自于百度百科RabbitMQ。
使用RabbitMQ解决多线程写入文件问题
分析
多线程写入,产生消息的也就是一个程序(一个生产者P),消费消息的也是一个消息,它的模型应该是:

编写代码
引入RabbitMQ client DLL
程序包管理控制台命令:
PM> Install-Package RabbitMQ.Client


生产者
首先,创建一个 connection 通过socket连接 去和服务器连接起来(需要传目的服务器的IP、用户名、密码等)。
接着 创建一个 channel ,这是大部分的要做的事情所在。
要发送消息,我们必须声明一个队列,,然后我们可以向队列发布消息。
执行一次BasicPublish方法,推送一个消息。
class Program
{
static void Main(string[] args)
{
new Thread(Write).Start();
new Thread(Write).Start();
new Thread(Write).Start();
} public static void Write()
{
var factory = new ConnectionFactory() { HostName = "localhost", UserName = "eric", Password = "", };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "writeLog", durable: false, exclusive: false, autoDelete: false, arguments: null);
for (int i = ; i < ; i++)
{
string message = i.ToString();
var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "", routingKey: "writeLog", basicProperties: null, body: body);
Console.WriteLine("Program Sent {0}", message);
}
}
}
}
声明的队列,在服务器中如果不存在了,会自动创建。而消息的内容是字节数组,在使用时,注意编码问题。
消费者
当队列里有消息时,消费者要随时能够从队列里获取消息,所以我需要一直运行它,让它监听消息。
就像我们打篮球进行传球,需要事先确认要传给的那个队友位置一样,生产者要发送消息,一定要事先知道消费消息的程序的对列是哪个。所以,在运行生产者程序前,需要先启动消费者程序。
由此,声明对列,就应该在消费者程序中完成。
class Program
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost", UserName = "eric", Password = "", VirtualHost ="/"};
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "writeLog",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null); var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
ExcuateWriteFile(message);
Console.WriteLine(" Receiver Received {0}", message);
};
channel.BasicConsume(queue: "writeLog",
noAck: true,
consumer: consumer); Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
public static void ExcuateWriteFile(string i)
{
using (FileStream fs = new FileStream(@"d:\\test.txt", FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(fs, Encoding.Unicode))
{
sw.Write(i);
}
}
}
}
执行程序
先执行 消费者程序,让它一直保持监听。
错误解决
执行时VS报错:
“RabbitMQ.Client.Exceptions.BrokerUnreachableException”类型的未经处理的异常在 RabbitMQ.Client.dll 中发生 其他信息: None of the specified endpoints were reachable。
进入查看详细的内部异常:
innerEception:{"The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=530, text=\"NOT_ALLOWED - access to vhost '/' refused for user 'eric'\", classId=10, methodId=40, cause="}
此时,我们打开在http://localhost:15672/#/users 可以看到eric 下 的Can access virtual hosts 为 NoAccess

解决办法:
rabbitmqctl控制台输入
rabbitmqctl set_permissions -p / userName "." "." ".*"


再次执行时,可以看到:

然后运行 生产者程序。
我们先开着 Receive ,当生产者运行时

消费者的自动触发执行 :

直到所有的 指定的 queue 里面的消息完全消费完为止。(此时消费者程序仍然在监听中)
对于需要安装和设置用户的同学,请参考 windows下 安装 rabbitMQ 及操作常用命令
本文参考:
RabbitMQ原理与相关操作(一)的更多相关文章
- RabbitMQ原理与相关操作(二)
接着 上篇随笔 增加几个概念: RabbitMQ是一个在AMQP(高级消息队列协议)标准基础上完整的,可服用的企业消息系统. AMQP模型的功能组件图(上图摘自 Sophia_tj 的 第2章 AMQ ...
- RabbitMQ原理与相关操作(三)消息持久化
现在聊一下RabbitMQ消息持久化: 问题及方案描述 1.当有多个消费者同时收取消息,且每个消费者在接收消息的同时,还要处理其它的事情,且会消耗很长的时间.在此过程中可能会出现一些意外,比如消息接收 ...
- Spring Boot2.X整合消息中间件RabbitMQ原理简浅探析
目录 1.简单概述RabbitMQ重要作用 2.简单概述RabbitMQ重要概念 3.Spring Boot整合RabbitMQ 前言 RabbitMQ是一个消息队列,主要是用来实现应用程序的异步和解 ...
- 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...
- 数据结构Java实现04---树及其相关操作
首先什么是树结构? 树是一种描述非线性层次关系的数据结构,树是n个数据结点的集合,这些集结点包含一个根节点,根节点下有着互相不交叉的子集合,这些子集合便是根节点的子树. 树的特点 在一个树结构中,有且 ...
- 关于C#资源文件的相关操作
关于资源文件的相关操作. //1.比较常见的有获取资源文件对应的文件流,然后转换到相对应的文件 //比较典型的做法是通过代码程序集加载指定资源 //如下通过Assembly的静态方法GetExecut ...
- 转载:【Oracle 集群】RAC知识图文详细教程(三)--RAC工作原理和相关组件
文章导航 集群概念介绍(一) ORACLE集群概念和原理(二) RAC 工作原理和相关组件(三) 缓存融合技术(四) RAC 特殊问题和实战经验(五) ORACLE 11 G版本2 RAC在LINUX ...
- 【Redis】四、Redis设计原理及相关问题
(六)Redis设计原理及相关问题 通过前面关于Redis五种数据类型.相关高级特性以及一些简单示例的使用,对Redis的使用和主要的用途应该有所掌握,但是还有一些原理性的问题我们在本部分做一个探 ...
- 【转】【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
原文地址:http://www.cnblogs.com/baiboy/p/orc3.html 阅读目录 目录 RAC 工作原理和相关组件 ClusterWare 架构 RAC 软件结构 集群注册(OC ...
随机推荐
- SQLServer地址搜索性能优化例子
这是一个很久以前的例子,现在在整理资料时无意发现,就拿出来再改写分享. 1.需求 1.1 基本需求: 根据输入的地址关键字,搜索出完整的地址路径,耗时要控制在几十毫秒内. 1.2 数据库地址表结构和数 ...
- OpenCASCADE AIS Manipulator
OpenCASCADE AIS Manipulator eryar@163.com Abstract. OpenCASCADE7.1.0 introduces new built-in interac ...
- CodeSimth - .Net Framework Data Provider 可能没有安装。解决方法
今天想使用CodeSimth生成一个sqlite数据库的模板.当添加添加数据库的时候发现: .Net Framework Data Provider 可能没有安装. 下面找到官方的文档说明: SQLi ...
- Paypal开发中遇到请求被中止: 未能创建 SSL/TLS 安全通道及解决方案
最近在基于ASP.NET上开发了Paypal支付平台,在ASP.NET开发的过程中没有遇到这个问题,但是引用到MVC开发模式中的时候就出现了"未能创建 SSL/TLS 安全通道及解决方案&q ...
- CRL快速开发框架系列教程十二(MongoDB支持)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- Go web开发初探
2017年的第一篇博客,也是第一次写博客,写的不好,请各位见谅. 本人之前一直学习java.java web,最近开始学习Go语言,所以也想了解一下Go语言中web的开发方式以及运行机制. 在< ...
- php cryptr 加密函数
class CryptHelper { /** * 加密 * @param unknown $password * @param unknown $salt * @return string */ p ...
- BPM协同平台解决方案分享
一.需求分析 企业信息化的过程都是从单纯解决一个业务功能问题,到解决企业内部业务流程问题,再扩展到解决不同业务流程的关联互动问题, 核心是业务的集成和业务的协同,需要有一个统一的业务协同平台. 国内的 ...
- 【SAP业务模式】之ICS(七):IDOC配置
这是ICS业务模式系列的最后一篇了,主要讲解IDOC的配置. 一.指定EDI传输的供应商逻辑地址 事务代码:WEL1 注意:上面逻辑地址是生产公司+内部客户.有以下两种情形: 1.如果内部客户都是纯数 ...
- nginx代理https站点(亲测)
nginx代理https站点(亲测) 首先,我相信大家已经搞定了nginx正常代理http站点的方法,下面重点介绍代理https站点的配置方法,以及注意事项,因为目前大部分站点有转换https的需要所 ...