rabbitmq用于分布式系统
上文介绍了RabbitMQ在linux下的安装,这里就简单的介绍一下基于RabbitMQ的开发。RabbitMQ已经提供了一大坨材料。
- Java – http://www.RabbitMQ.com/java-client.html
- .NET – http://www.RabbitMQ.com/dotnet.html
- Erlang– http://www.RabbitMQ.com/erlang-client.html
这里使用的RabbitMQ提供的Java的包。
RabbitMQ提供的Java AMQP Client Libaray,最核心的class是ConnectionFactory、Conncetion 和Channel, 分别代表连结工厂、一个连结和一个数据通道。
AMQP支持在一个TCP连接上启用多个MQ通信channel,每个channel都可以被应用作为通信流。每个AMQP程序至少要有一个connection和一个channel。
分布式的消息服务器肯定是要有Producer和Comsumer的。那怎么基于RabbitMQ构建一个Comsumer呢?
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
Connection conn = factory.newConnection();
or
ConnectionFactory factory = new ConnectionFactory();
factory.setUri("amqp://userName:password@hostName:portNumber/virtualHost");
Connection conn = factory.newConnection();
上述的代码,创建了一个connnection,开发者可以在一个connnection创建多个channel。每个channel都被分配了一个整数标识,自动由Connection类的createChannel()方法维护。或者,你可以使用.createChannel(x)来指定channel标识,其中x是你想要使用的channel标识。通常情况下,推荐使用.channel()方法来自动分配channel标识,以便防止冲突。channel用于传递、接收消息。如下代码:
Channel channel = conn.createChannel();
另外,获取connection时候,consumer线程默认自动分配一个 ExceutorService thread pool,如果你需要自己控制线程池的。你可以如下定义:
ExecutorService es = Executors.newFixedThreadPool(20);
Connection conn = factory.newConnection(es);
但是需要注意的是:当connection shutdown的时候,默认分配的ExecutorService会自动shutdown,用户自己定义的不会shutdown,需要手动shutdown。而且,只用在Consumer回调有严重的性能瓶颈的时候才用这种方式,在平常的使用中,默认的分配更加高效。
现在,我们已经有了一个可用的连结和channel,我们来创建一个队列。
//queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,Map<String, Object> arguments) throws IOException;
channel.queueDeclare(”vinoQueue",true,false,false,null);
它创建了一个名叫“vinoQueue”的队列,它是non-durable的(重启之后不会重新建立),并且最后一个消费者断开的时候不会自动删除(autoDelete=False)。在创建durable的队列(或者交换机)的时候,将auto_delete设置成false是很重要的,否则队列将会在最后一个消费者断开的时候消失。另外,还有一个属性是”exclusive“,该属性如果设置成True,只有创建这个队列的消费者程序才允许连接到该队列,这种队列对于这个消费者程序是私有的。
现在队列已经创建成功了,Comsumer有两种方式从队列中取出消息。
一个是调用 channel.basicGet(“vinoQueue”, false)主动从队列中拉出下一个消息。如果队列中无消息,会返回null,代码如下所示:
// GetResponse basicGet(String queue, boolean autoAck) throws IOException; 主动从队列里拉出下一条消息。
channel.basicGet(QUEUE_NAME, false);
另一个是消息队列把消息推给Cumsumer。这种情况你就需要用如下代码。
//消费者用于获取消息信道绑定的消息队列中的信息
QueueingConsumer consumer = new QueueingConsumer(channel);
//注册一个新消息到达的回调,第二个参数表示ack,默认是false.
channel.basicConsume(QUEUE_NAME, true,consumer); while(true){
//循环获取消息队列中的信息,这个函数会等待在队列上,直到下一个消息到达队列。
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println("[x] Received '"+message+"'"); }
/用来注销该回调函数,参数consumer_tag 当中指定的字符串和chan.basicConsume() 注册的一致,这里无用。
//channel.basicCancel(QUEUE_NAME);
这里具体的说一下channel.basicConsume()里的ack参数。当从队列当中取出一个消息的时候,RabbitMQ需要应用显式地回馈说已经获取到了该消息。如果一段时间内不回馈,RabbitMQ会将该消息重新分配给另外一个绑定在该队列上的消费者。另一种情况是消费者断开连接,但是获取到的消息没有回馈,则RabbitMQ同样重新分配。如果将该参数设置为true,则RabbimtMQ会为下一个AMQP请求添加一个ack属性,告诉AMQP服务器需要等待回馈。否者,不要等待回馈。大多数时候,你也许想要自己手工发送回馈,例如,需要在回馈之前将消息存入数据库。回馈通常是通过调用 channel.basicAck(deliveryTag, multiple)方法。
以上就是Comsumer的相关代码。
不过没有人发送消息的话,要消费者何用?所以需要一个Productor。消息投递的大概过程是:
- 客户端连接到消息队列,创建一个channel.
- 声明exchange
- 声明queue
- 绑定exchange和queue
- 投递消息到exchange
下面代码表示如果将一个简单的消息发送到名为“vino”的exchange,并且标记为路由键“hello”
// 创建消息通道
Channel channel = connection.createChannel(); /**
* 声明Exchange
* Exchange.DeclareOk exchangeDeclare(String exchange, String
* type, boolean durable, boolean autoDelete, Map<String, Object>
* argumen s) throws IOException;
*/
channel.exchangeDeclare("vino", "direct", true, false, null);
/**
* Declaring a queue is idempotent - it will only be created if it
* doesn't exist already. The message content is a byte array, so you
* can encode whatever you like there.
*/
channel.queueDeclare("vinoQueue", false, false, false, null);
// 绑定exchange和消息队列 Queue.BindOk queueBind(String queue, String exchange,
// String routingKey) throws IOException;
// 注意绑定支持一个queue绑定多个routingKey,或者一个routingKey绑定到多个queue
queueBind("vinoQueue", "vino", "hello");
// 发布消息
String message = "Hello Wrold " + Math.random();
// 第一个参数是exchange的名称,若用""表示发送到默认的exchange,rabbitmq的默认的exchange的类型是direct。
channel.basicPublish("vino", "hello", null, message.getBytes());
剩下就是最后一件事(生产者和消费者都需要调用的)
channel使用完毕后要关闭
channel.close();
conn.close();
参考:兔子和兔子窝
rabbitmq用于分布式系统的更多相关文章
- RabbitMQ在分布式系统中的应用
怎么保证可靠性的? RabbitMQ提供了几种特性,牺牲了一点性能代价,提供了可靠性的保证. 持久化当RabbitMQ退出时,默认会将消息和队列都清除,所以需要在第一次声明队列和发送消息时指定其持久化 ...
- RabbitMQ.Client API (.NET)中文文档
主要的名称空间,接口和类 核心API中定义接口和类 RabbitMQ.Client 名称空间: 1 using RabbitMQ.Client; 核心API接口和类 IModel :表示一个AMQP ...
- rabbitmq 基本信息
两个或多个系统间需要通过定时任务来同步数据,异构系弘的不同进程间想互调用 通讯的问题,可以用rabbitmq解决.rabbitmq擅长解决多系统 异构系统音的数据交换,也可以用于系统间服务的相互调用R ...
- RabbitMQ基础理解
RabbitMQ基本理解 MQ是消息中间件,常见的有RabbitMQ,Kafka,RocketMQ,activeMQ 等,用于分布式系统中.作用有三点 解耦 异步 削峰 RabbitMQ 整体上是一个 ...
- 消息队列MQ面试专题(rabbitmq)
正文: 1.什么是 rabbitmq 采用 AMQP 高级消息队列协议的一种消息队列技术,最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦 2.为什么要使用 rabbitmq 在分布 ...
- RabbitMQ入门到进阶(Spring整合RabbitMQ&SpringBoot整合RabbitMQ)
1.MQ简介 MQ 全称为 Message Queue,是在消息的传输过程中保存消息的容器.多用于分布式系统 之间进行通信. 2.为什么要用 MQ 1.流量消峰 没使用MQ 使用了MQ 2.应用解耦 ...
- SkyWalking分布式系统应用程序性能监控工具-上
概述 微服务系统监控三要素 现在系统基本都是微服务架构,对于复杂微服务链路调用如下问题如何解决? 一个请求经过了这些服务后其中出现了一个调用失败的问题,如何定位问题发生的地方? 如何计算每个节点访问流 ...
- kafka原理简介并且与RabbitMQ的选择
kafka原理简介并且与RabbitMQ的选择 kafka原理简介,rabbitMQ介绍,大致说一下区别 Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和 ...
- RabbitMQ如何工作和RabbitMQ核心概念
RabbitMQ是一个开源的消息代理软件.它接受来自生产者的消息并将其传递给消费者.它就像一个中间人,可以用来减少Web应用程序服务器的负载和交付时间. RabbitMQ如何工作 让我们简要介绍一下R ...
随机推荐
- eclipse设置java虚拟机内存大小
设置java虚拟机大小可以让eclipse启动运行更快...... 在eclipse中点击window--preferences--java--Installed JREs. 然后看右边的框,鼠标点击 ...
- NYOJ-1036 非洲小孩(贪心)
非洲小孩 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 家住非洲的小孩,都很黑.为什么呢?第一,他们地处热带,太阳辐射严重.第二,他们不经常洗澡.(常年缺水,怎么洗 ...
- Session和Cookie的使用总结
Session和Cookie的使用总结: Session和cookie都是asp.Net中的内置对象,至于他们有什么区别,在这里就不在多说,现在来说说一些比较实用点的东西: 我们知道网站都有一个后台管 ...
- 正则表达式:reg.test is not a function
正则中 比如 var reg = "/^[0-9]$/" 会报 reg.test is not a function 如果 var reg = /^[0-9]$/ 就不会有错 因为 ...
- JQuery_图片未加载!
JQuery_图片未加载! <html> <head> <script type="text/javascript" src="/jquer ...
- 图片(img标签)大小自适应
$(function(){ var myimg,oldwidth,oldheight; var maxwidth=249; var maxheight=187; var imgs = document ...
- Python识别网站验证码
http://drops.wooyun.org/tips/6313 Python识别网站验证码 Manning · 2015/05/28 10:57 0x00 识别涉及技术 验证码识别涉及很多方面的内 ...
- hdu_1181_变形课(dfs)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1181 题意:中文题,不解释 题解:直接DFS #include<cstdio> #incl ...
- hdu_5677_ztr loves substring(回文+二维多重背包)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5677 题意:给你N个串,问能否选出小于K个回文字符串使得选出的字符串的长度之和为L. 题解:很容易想到 ...
- lua学习
在lua中,一切都是变量,除了关键字. 1.注释: 单行注释: 连续两个减号“--”表示注释的开始,一直延续到行末.相当于C语言中的“//” 多行注释:由“--[[”表示注释开始, “]]”表示注释结 ...