RabbitMQ入门与使用篇(转)

介绍

RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的开源实现。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面都非常的优秀。是当前最主流的消息中间件之一。

RabbitMQ的官方

概念:

Brocker:消息队列服务器实体。

Exchange:消息交换机,指定消息按什么规则,路由到哪个队列。

Queue:消息队列,每个消息都会被投入到一个或者多个队列里。

Binding:绑定,它的作用是把exchange和queue按照路由规则binding起来。

Routing Key:路由关键字,exchange根据这个关键字进行消息投递。

Vhost:虚拟主机,一个broker里可以开设多个vhost,用作不用用户的权限分离。

Producer:消息生产者,就是投递消息的程序。

Consumer:消息消费者,就是接受消息的程序。

Channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

消息队列的使用过程大概如下:

消息接收

客户端连接到消息队列服务器,打开一个channel。

客户端声明一个exchange,并设置相关属性。

客户端声明一个queue,并设置相关属性。

客户端使用routing key,在exchange和queue之间建立好绑定关系。

消息发布

客户端投递消息到exchange。

exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

AMQP 里主要要说两个组件:

Exchange 和 Queue

绿色的 X 就是 Exchange ,红色的是 Queue ,这两者都在 Server 端,又称作 Broker

这部分是 RabbitMQ 实现的,而蓝色的则是客户端,通常有 Producer 和 Consumer 两种类型。

Exchange通常分为四种:

fanout:该类型路由规则非常简单,会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中,相当于广播功能

direct:该类型路由规则会将消息路由到binding key与routing key完全匹配的Queue中

topic:与direct类型相似,只是规则没有那么严格,可以模糊匹配和多条件匹配

headers:该类型不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配

使用场景

官方介绍

下载与安装

下载

rabbitmq

erlang

安装

先安装erlang

然后再安装rabbitmq

管理工具

参考官方文档

操作起来很简单,只需要在DOS下面,进入安装目录(安装路径\RabbitMQ Server\rabbitmq_server-3.2.2\sbin)执行如下命令就可以成功安装。

rabbitmq-pluginsenable rabbitmq_management   

可以通过访问:http://localhost:15672进行测试,默认的登陆账号为:guest,密码为:guest。

其他配置

1. 安装完以后erlang需要手动设置ERLANG_HOME 的系统变量。

setERLANG_HOME=F:\Program Files\erl9.0#环境变量`path`里加入:%ERLANG_HOME%\bin#环境变量`path`里加入: 安装路径\RabbitMQ Server\rabbitmq_server-3.6.10\sbin

2.激活Rabbit MQ’s Management Plugin

使用Rabbit MQ 管理插件,可以更好的可视化方式查看Rabbit MQ 服务器实例的状态,你可以在命令行中使用下面的命令激活。

rabbitmq-plugins.batenable  rabbitmq_management

3.创建管理用户

rabbitmqctl.bat add_user sa 123456

4. 设置管理员

rabbitmqctl.bat set_user_tags sa administrator

5.设置权限

rabbitmqctl.bat set_permissions -p / sa".*"".*"".*"

6. 其他命令

#查询用户:    rabbitmqctl.bat list_users#查询vhosts:    rabbitmqctl.bat list_vhosts#启动RabbitMQ服务:    net stop RabbitMQ&& net start RabbitMQ   

以上这些,账号、vhost、权限、作用域等基本就设置完了。

基于.net使用

RabbitMQ.Client是RabbiMQ 官方提供的的客户端

EasyNetQ是基于RabbitMQ.Client 基础上封装的开源客户端,使用非常方便

以下操作RabbitMQ的代码例子,都是基于EasyNetQ的使用和再封装,在文章底部有demo例子的源码下载地址

创建 IBus

/// /// 消息服务器连接器/// publicclassBusBuilder{publicstaticIBusCreateMessageBus(){// 消息服务器连接字符串// var connectionString = ConfigurationManager.ConnectionStrings["RabbitMQ"];stringconnString="host=127.0.0.1:5672;virtualHost=TestQueue;username=sa;password=123456";if(connString==null||connString==string.Empty)thrownewException("messageserver connection string is missing or empty");returnRabbitHutch.CreateBus(connString);}}

Fanout Exchange

所有发送到Fanout Exchange的消息都会被转发到与该Exchange 绑定(Binding)的所有Queue上。

Fanout Exchange 不需要处理RouteKey 。只需要简单的将队列绑定到exchange 上。这样发送到exchange的消息都会被转发到与该交换机绑定的所有队列上。类似子网广播,每台子网内的主机都获得了一份复制的消息。 所以,Fanout Exchange 转发消息是最快的。

/// ///  消息消耗(fanout)/// /// 消息类型/// 回调/// 交换器名/// 队列名/// 路由名publicstaticvoidFanoutConsume(Actionhandler,stringexChangeName="fanout_mq",stringqueueName="fanout_queue_default",stringroutingKey="")whereT:class{varbus=BusBuilder.CreateMessageBus();varadbus=bus.Advanced;varexchange=adbus.ExchangeDeclare(exChangeName,ExchangeType.Fanout);varqueue=CreateQueue(adbus,queueName);adbus.Bind(exchange,queue,routingKey);adbus.Consume(queue,registration=>{registration.Add((message,info)=>{handler(message.Body);});});}/// /// 消息上报(fanout)/// /// 消息类型/// 主题名/// 消息命名/// 错误信息/// publicstaticboolFanoutPush(Tt,outstringmsg,stringexChangeName="fanout_mq",stringroutingKey="")whereT:class{msg=string.Empty;try{using(varbus=BusBuilder.CreateMessageBus()){varadbus=bus.Advanced;varexchange=adbus.ExchangeDeclare(exChangeName,ExchangeType.Fanout);adbus.Publish(exchange,routingKey,false,newMessage(t));returntrue;}}catch(Exceptionex){msg=ex.ToString();returnfalse;}}

所有发送到Direct Exchange的消息被转发到RouteKey中指定的Queue。

Direct模式,可以使用RabbitMQ自带的Exchange:default Exchange 。所以不需要将Exchange进行任何绑定(binding)操作 。消息传递时,RouteKey必须完全匹配,才会被队列接收,否则该消息会被抛弃。

/// /// 消息发送(direct)/// /// 消息类型/// 发送到的队列/// 发送内容publicstaticvoidDirectSend(stringqueue,Tmessage)whereT:class{using(varbus=BusBuilder.CreateMessageBus()){bus.Send(queue,message);}}/// /// 消息接收(direct)/// /// 消息类型/// 接收的队列/// 回调操作/// 错误信息/// publicstaticboolDirectReceive(stringqueue,Actioncallback,outstringmsg)whereT:class{msg=string.Empty;try{varbus=BusBuilder.CreateMessageBus();bus.Receive(queue,callback);}catch(Exceptionex){msg=ex.ToString();returnfalse;}returntrue;}/// /// 消息发送/// /// /// /// /// /// /// /// publicstaticboolDirectPush(Tt,outstringmsg,stringexChangeName="direct_mq",stringroutingKey="direct_rout_default")whereT:class{msg=string.Empty;try{using(varbus=BusBuilder.CreateMessageBus()){varadbus=bus.Advanced;varexchange=adbus.ExchangeDeclare(exChangeName,ExchangeType.Direct);adbus.Publish(exchange,routingKey,false,newMessage(t));returntrue;}}catch(Exceptionex){msg=ex.ToString();returnfalse;}}/// /// 消息接收///  /// /// 消息类型/// 回调/// 交换器名/// 队列名/// 路由名publicstaticboolDirectConsume(Actionhandler,outstringmsg,stringexChangeName="direct_mq",stringqueueName="direct_queue_default",stringroutingKey="direct_rout_default")whereT:class{msg=string.Empty;try{varbus=BusBuilder.CreateMessageBus();varadbus=bus.Advanced;varexchange=adbus.ExchangeDeclare(exChangeName,ExchangeType.Direct);varqueue=CreateQueue(adbus,queueName);adbus.Bind(exchange,queue,routingKey);adbus.Consume(queue,registration=>{registration.Add((message,info)=>{handler(message.Body);});});}catch(Exceptionex){msg=ex.ToString();returnfalse;}returntrue;}

Topic Exchange

消息发布(Publish)

要使用主题发布,只需使用带有主题的重载的Publish方法:

varbus=RabbitHutch.CreateBus(...);bus.Publish(message,"X.A");

订阅者可以通过指定要匹配的主题来过滤邮件。

这些可以包括通配符:

*=>匹配一个字。

#=>匹配到零个或多个单词。

所以发布的主题为“X.A.2”的消息将匹配“#”,“X.#”,“* .A.*”,而不是“X.B. *”或“A”。

警告,Publish只顾发送消息到队列,但是不管有没有消费端订阅,所以,发布之后,如果没有消费者,该消息将不会被消费甚至丢失。

消息订阅(Subscribe)

EasyNetQ提供了消息订阅,当调用Subscribe方法时候,EasyNetQ会创建一个用于接收消息的队列,不过与消息发布不同的是,消息订阅增加了一个参数,subscribe_id.代码如下:

bus.Subscribe("my_id",handler,x=>x.WithTopic("X.*"));

警告: 具有相同订阅者但不同主题字符串的两个单独订阅可能不会产生您期望的效果。 subscriberId有效地标识个体AMQP队列。 具有相同subscriptionId的两个订阅者将连接到相同的队列,并且两者都将添加自己的主题绑定。 所以,例如,如果你这样做:

bus.Subscribe("my_id",handlerOfXDotStar,x=>x.WithTopic("X.*"));bus.Subscribe("my_id",handlerOfStarDotB,x=>x.WithTopic("*.B"));

匹配“x.”或“.B”的所有消息将被传递到“XXX_my_id”队列。 然后,RabbitMQ将向两个消费者传递消息,其中handlerOfXDotStar和handlerOfStarDotB轮流获取每条消息。

现在,如果你想要匹配多个主题(“X.”OR“.B”),你可以使用另一个重载的订阅方法,它采用多个主题,如下所示:

bus.Subscribe("my_id",handler,x=>x.WithTopic("X.*").WithTopic("*.B"));

/// /// 获取主题 /// /// 主题内容类型/// 订阅者ID/// 消息接收响应回调///  订阅主题集合publicstaticvoidTopicSubscribe(stringsubscriptionId,Actioncallback,paramsstring[]topics)whereT:class{varbus=BusBuilder.CreateMessageBus();bus.Subscribe(subscriptionId,callback,(config)=>{foreach(varitemintopics)config.WithTopic(item);});}/// /// 发布主题/// /// 主题内容类型/// 主题名称/// 主题内容/// 错误信息/// publicstaticboolTopicPublish(stringtopic,Tmessage,outstringmsg)whereT:class{msg=string.Empty;try{using(varbus=BusBuilder.CreateMessageBus()){bus.Publish(message,topic);returntrue;}}catch(Exceptionex){msg=ex.ToString();returnfalse;}}/// /// 发布主题/// /// /// 消息类型/// 消息内容/// 主题名/// 错误信息/// 交换器名/// publicstaticboolTopicSub(Tt,stringtopic,outstringmsg,stringexChangeName="topic_mq")whereT:class{msg=string.Empty;try{if(string.IsNullOrWhiteSpace(topic))thrownewException("推送主题不能为空");using(varbus=BusBuilder.CreateMessageBus()){varadbus=bus.Advanced;//var queue = adbus.QueueDeclare("user.notice.zhangsan");varexchange=adbus.ExchangeDeclare(exChangeName,ExchangeType.Topic);adbus.Publish(exchange,topic,false,newMessage(t));returntrue;}}catch(Exceptionex){msg=ex.ToString();returnfalse;}}/// /// 获取主题 /// /// /// 消息类型/// 订阅者ID/// 回调/// 交换器名/// 主题名publicstaticvoidTopicConsume(Actioncallback,stringexChangeName="topic_mq",stringsubscriptionId="topic_subid",paramsstring[]topics)whereT:class{varbus=BusBuilder.CreateMessageBus();varadbus=bus.Advanced;varexchange=adbus.ExchangeDeclare(exChangeName,ExchangeType.Topic);varqueue=adbus.QueueDeclare(subscriptionId);foreach(varitemintopics)adbus.Bind(exchange,queue,item);adbus.Consume(queue,registration=>{registration.Add((message,info)=>{callback(message.Body);});});}   

具体发布/订阅消息的Demo和相关测试看源码Demo

注意

当在创建订阅者去消费队列的时候

/// /// 获取主题 /// /// publicstaticvoidGetSub(Ttopic,Actioncallback)whereT:class{using(varbus=BusBuilder.CreateMessageBus()){bus.Subscribe(topic.ToString(),callback,x=>x.WithTopic(topic.ToString()));}}

using里的对象在执行完成后被回收了,导致刚连接上去就又断开了(刚开始写的时候,习惯性加using,排查了好久才发现,欲哭无泪)

源码项目运行前的准备与确认:

到RabbitMQ管理后台添加TestQueueVHost,并且分配用户权限,然后到RabbitMQHelper.BusBuilder类里配置RabbitMQ连接服务的相关信息host=127.0.0.1:5672;virtualHost=TestQueue;username=sa;password=123456,(根据配置的内容和用户修改)

参考资料(鸣谢):

EasyNetQ-基于Topic的路由

.NET操作RabbitMQ组件EasyNetQ使用中文简版文档。

RabbitMQ入门指南

附:Demo源码GitHub地址


欢迎到原文地址关注和交流

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • 介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的...
    SFLYQ阅读 1,111评论 0 9
  • 来源 RabbitMQ是用Erlang实现的一个高并发高可靠AMQP消息队列服务器。支持消息的持久化、事务、拥塞控...
    jiangmo阅读 10,350评论 2 34
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 转载2017年11月01日 09:54:03 2595 RabbitMQ 即一个消息队列,主要是用来实现应用程序的...
    杨传池chris阅读 6,346评论 1 0
  • RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用。 消息...
    彩虹之梦阅读 1,082评论 2 1