相关项目下载地址
RabbitMQ概述
1、何为消息中间件
消息中间件(Message Queue Middleware)简称MQ,它是将消息(即需要被传输的数据,格式可以是纯文本、JSON或对象等)通过高效、可靠的消息传输机制,接收、存储并转发到处理该消息的应用上的一款中间件。目前,市面上常用的MQ有RabbitMQ、RocketMQ、ActiveMQ、Kafka等。一般消息中间件都支持两种消息传递模式:点对点模式(P2P)和发布-订阅模式(Pub/Sub)。
(1)点对点生产者将消息发送到MQ中指定的队列中,然后消息者就从该队列中取出数据并消费。
(2)发布-订阅
生产者将消息发送到MQ指定的主题(Topic)上,然后订阅该主题的消费者就会接收到该主题中的消息。
2、消息中间件的优缺点
MQ最重要的三大优点功能就是异步、解耦和削峰。当然还有其他的功能如存储、可扩展性等
- 异步:使得一些不需要及时交互的信息留待后面慢慢处理,这样请求耗时将变的更低,加快响应时间。
- 解耦:举两个例子来解释:(1)当用户请求A应用,A应用请求B应用进行处理,若没有MQ,则当B服务出现故障时,此时A应用就会提示用户系统出现异常,请稍后重试,那用户怎么知道啥时候服务可用呢?当加了MQ,当B应用故障时,因为在MQ保存了用户的请求信息,当B应用服务可用时,利用重试机制可以再次处理用户的请求。(2)现A应用需要调BCD应用,后面又有新的应用E需要用A应用的数据、B应用又不用A应用数据,这样会出现频繁的修改源代码。使用MQ后,A应用只管发数据,哪个应用想用数据就从MQ中拿,不想用了就不拿,维护起来很方便。
- 削峰:当公司对外提供的服务存在瞬时访问量剧增的时候,此时后台的服务大概率会出现处理请求不过来而出现宕机等情况。而MQ具有存储功能能将所有的请求保存在自身,然后平稳的向消息处理者转发待处理的请求。
MQ缺点有
降低系统可用性、系统复杂性提高、数据一致性等。
- 降低系统可用性:整个系统中加入一个节点MQ,肯定会降低系统的可用性。最怕出现MQ节点宕机,导致依赖MQ的整体服务都不可用了,又或则是出现网络分区问题。
- 系统复杂性提高:我们需要考虑怎么控制消息被重复消费,怎么保证消息顺序性消费,怎么保证消息不丢失等问题。
- 数据一致性:如何保证数据正确的存储到每个使用该数据的节点,不能出现某个节点数据不一致情况。
3、主流MQ的对比
特定\产品 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
单机吞吐量 | 万级 | 万级 | 10万级 | 10万级 |
时效性 | ms级 | 微秒级 | ms级 | ms级 |
可用性 | 高,基于主从架构 | 高,基于主从架构 | 非常高,分布式架构 | 非常高,分布式架构 |
可靠性 | 有较低的概率丢失数据 | 经过参数配置,可以做到0丢失 | 经过参数优化配置,可以做到0丢失 | 经过参数优化配置,可以做到0丢失 |
开发语言 | Java | Erlang | Java | Scala |
功能特性 | MQ功能很完备,但社区活跃性不强。不建议使用 | 并发能力强,延迟低,支持多种协议,管理界面功能丰富,社区活跃。适用于中小型公司 | 阿里出品,扩展性较好,社区活跃度不高。适用于大型公司(能够修改源码) | MQ功能较完备,主要适用于大数据领域 |
3、RabbitMQ的特点
下面将罗列一些RabbitMQ的特点:
- 可靠性:可以通过生产者发送消息确认、持久化、消费确认等机制
- 高可用性:多个RabbitMQ可以组成集群,开启镜像队列满足节点挂了仍对外服务。
- 支持多种协议:默认使用的是AMQP协议,也支持STOMP、MQTT等多种协议
- 支持多种语言客户端:几乎支持常见的客户端开发语言,如Java、Python、PHP等。
- 管理平台:提供功能丰富的管理平台
- 插件机制:提供其他功能性插件,满足特殊应用场景
RabbitMQ入门
RabbitMQ的安装可以参考[Docker概述与入门]中教程。下面我们就简单的练习一下如何使用RabbitMQ(此处笔者就直接使用Java操作RabbitMQ,也可以直接使用其管理界面进行入门体验)。客户端开发依赖:
<dependency> <groupId>com.rabbitmqgroupId> <artifactId>amqp-clientartifactId> <version>4.2.1version>dependency>
1、消息生产者
下面是一个简单的main方法中定义的消息生产者,关键代码如下:
//创建连接工厂ConnectionFactory factory=new ConnectionFactory();factory.setHost("119.45.6.66");//笔者腾讯云服务器factory.setPort(5672);factory.setUsername("guest");factory.setPassword("guest");try { //创建链接实例 Connection connection = factory.newConnection(); //创建通道实例 Channel channel = connection.createChannel(); //添加交换器 channel.exchangeDeclare("demo1_myExchangeName","direct",true,false,null); //添加队列 channel.queueDeclare("demo1_myQueneName",true,false,false,null); //使用路由键将交换器与队列链接 channel.queueBind("demo1_myQueneName","demo1_myExchangeName","demo1_myRoutingKey"); //向通道内发送消息:消息格式为纯文本 channel.basicPublish("demo1_myExchangeName","demo1_myRoutingKey", MessageProperties.TEXT_PLAIN,"hello World".getBytes()); //通道关闭 channel.close(); //连接关闭 connection.close();} catch (IOException e) { e.printStackTrace();} catch (TimeoutException e) { e.printStackTrace();}
2、消息消费者
下面是一个简单的main方法中定义的消息消费者,关键代码如下:
//创建连接工厂ConnectionFactory factory=new ConnectionFactory();factory.setUsername("guest");factory.setPassword("guest");try { //创建链接实例,与生产者不同 Connection connection = factory.newConnection(new Address[]{new Address("119.45.6.66",5672)}); //创建通道实例 Channel channel = connection.createChannel(); //创建消费者实例 Consumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //处理消息 System.out.println("Msg="+new String(body)); //消息消费手动确认:非批量 channel.basicAck(envelope.getDeliveryTag(),false); } }; //执行消费(basicConsume是推模式,后面会介绍) channel.basicConsume("demo1_myQueneName",consumer);} catch (IOException e) { e.printStackTrace();} catch (TimeoutException e) { e.printStackTrace();}
我们先启动生产者,然后进入管理界面,可以看到当前的连接实例、交换器以及自己定义的队列及消息。然后我们启动消费者,控制台就输出消息内容。