热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

RabbitMQ运用负载均衡与消息持久化的实现

 Rabbitmq是对AMQP协议的一种实现。使用范围也比较广泛,主要用于消息异步通讯。

 

Rabbitmq 是对AMQP协议的一种实现。使用范围也比较广泛,主要用于消息异步通讯。



一,默认情况下Rabbitmq使用轮询(round-robin)方式转发消息。为了较好实现负载,可以在消息接收方指定,每次接收到一条,这样可以缓解单一服务器压力。

代码如下:



ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
cOnnection= factory.newConnection();
final Channel channel = connection.createChannel();
channel.basicQos(1);//设置每次接收一条
为了保证消息不丢失,取消自动ACK,改为只有在完全处理消息后再ACK。
如:

Consumer cOnsumer= new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
try {
Thread.sleep(10000);
}
catch(Exception ex)
{
}
System.out.println("received Message:" + message);
channel.basicAck(envelope.getDeliveryTag(), false);//处理完成后ACK
}
};
channel.basicConsume(QUEUE_NAME, false, consumer);//取消自动ACK
二,为了保证在Rabbitmq在宕机后,仍不丢失消息,需要将队列和发布的消息都声明为可持久化的。
如:

channel.queueDeclare(QUEUE_NAME, true, false, false, null);

channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, bytes);

三,Rabbitmq 的MessageModel(消息模型)
在Rabbitmq的消息模型中,我们决不应该将消息直接发送到queue.事实上,消息发送者并不关心消息是否被路由或被入队列或被接收并处理。
生产者应只与Exchange(交换器)打交道,
Exchange的作用:从生产者接受消息,向消费者发送消息。
The exchange must know exactly what to do with a message it receives. Should it be appended to a particular queue? Should it be appended to many queues? Or should it get discarded. The rules for that are defined by the exchange type.【所以交换器必须准确地知道怎样处理消息,是否应该加到一个指定的队列,还是发送到多个队列,还是应该抛弃该消息。】
指定Exchange的Rule,即以何种方式转发消息。
Rabbitmq共有四种:direct,topic ,headers和 fanout,NamelessExchange.

fanout,这种方式很简单,就是一个广播,把消息转给所有的订阅者;有几个订阅者,消息就会被复制几份。

NamelessExchange,无Exchange,消息以轮询(round-robin)方式,发送给消费者,通过routingKey识别对应的消费者。

【提示】:

rabbitmqctl list_exchanges ,用于查看当前Rabbitmq正在运行的交换器;rabbitmqctl list_bindings,查看当前绑定数
eg:
生产者只负责发送消息,而不关心这些消息是否被处理,也不关心消息是否被抛弃;消息由Exchange根据具体rule处理。

private static final String EXCHANGE_NAME = "logs";
private static final String EXCHANGE_TYPE="fanout";
public static void main(String[] argv)
throws java.io.IOException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection cOnnection= factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME,EXCHANGE_TYPE);
String message = getMessage(argv);
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
channel.close();
connection.close();
}

 如:以fanout方式处理消息:消息会发送给所有的订阅者,(与routingKey无关)

private static final String exchangeName="logs";
private static final String exchangeType = "fanout";
public static void main(String[] args) throws IOException, InterruptedException, TimeoutException {
Connection cOnnection= null;
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
cOnnection= factory.newConnection();
final Channel channel = connection.createChannel();
int prefetchCount = 1;
channel.basicQos(prefetchCount);
channel.exchangeDeclare(exchangeName,exchangeType);
//创建一个队列,用于接收消息
String queueName= channel.queueDeclare().getQueue();
channel.queueBind(queueName,exchangeName,"");
System.out.println("Waiting for messages...,over it ,Press CTRL+C ");
Consumer cOnsumer= new DefaultConsumer(channel) {
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println("received Message:" + message);
try {
doWork(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queueName, false, consumer);
} finally {
}
}

Bindings,将队列绑定到Exchange,说明可以从Exchange接收消息。【A binding is a relationship between an exchange and a queue. This can be simply read as: the queue is interested in messages from this exchange.】

channel.queueBind(queueName, EXCHANGE_NAME, "routingKey");
direct,只有当routingKey,与bindingKey相同Exchange才能会推送消息。
如:
生产者:

channel.basicPublish(exchangeName, "routingKey", MessageProperties.PERSISTENT_TEXT_PLAIN, bytes);//片断

生产者在发送消息时指定routingKey.
消费者:可以绑定多个Key,以接收来自多个routingKey的消息

for (String bindingKey : typeArr) {
channel.queueBind(queueName, exchangeName, bindingKey);
}
//接收者绑定Key.
topic ,生产者在发送消息时,指定准确的routingKey(多个单词以.号分隔),当bindingKey模式匹配到routingKey时,则接收消息。
注意:routingKey和bindingKey的长度不能超过255.
*(star),只匹配一个单词。#(hash),能匹配0个或多个单词
三RPC
分布式远程调用。

 

 



   



推荐阅读
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • Netty源代码分析服务器端启动ServerBootstrap初始化
    本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 本文介绍了在C#中SByte类型的GetHashCode方法,该方法用于获取当前SByte实例的HashCode。给出了该方法的语法和返回值,并提供了一个示例程序演示了该方法的使用。 ... [详细]
author-avatar
张伊韵育财育信
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有