Spring boot+RabbitMQ环境
Spring boot+RabbitMQ环境
消息队列在目前分布式系统下具备非常重要的地位,如下的场景是比较适合消息队列的:
- 跨系统的调用,异步性质的调用最佳。
- 高并发问题,利用队列串行特点。
- 订阅模式,数据被未知数量的消费者订阅,比如某种数据的变更会影响多个系统的数据,订单数据就是比较好理解的。
之前有一个场景是商品数据在修改后需要推送到elasticsearch中,由于修改产品的并发量以及数据量均不大,所以对于消息未做持久化,而且为了快速上线简化系统,生产者与消费者更是部署在一个应用中,自生产自消费。这篇将从头搭建RabbitMQ环境,并且将之集成在Spring boot中。
搭建RabbitMQ环境

erlang
由于RabbitMQ是基于erlang开发的,所以要安装RabbitMQ先必须安装erlang。
更换软件源
使用apt-get时默认的软件源是us.archive.ubuntu.com,这会经常发生安装问题,比如速度特别慢或者由于下载不了造成不能安装。

可以更换成国内的数据源cn.archive.ubuntu.com,速度那是不用说的了(这里感谢我的同事的提醒)。找到下面这个文件然后进行替换。
/etc/apt/sources.list :%s/us.archive/cn.archive/g
在没有更新软件源时,我采取的是源码编译安装方法,参考这篇文章。我安装的是最新19.2版本,安装过程中还遇到各种问题就不一一记录了。
测试erlang安装是否正确,输入erl,如果看到如下图所示就说明安装成功了。

安装RabbitMQ

在未更换软件源之前我也是选择了源码编译安装方法,安装的最新的3.6.6,但手动启动时总是不成功,错误信息如下:

版本问题
RabbitMQ 3.6.6+ erlang 19.2 启动失败的问题暂时未解决,有谁知道的可以告诉我。
由于启动不成功,最后在更新成国内软件源之后,再次通过 apt-get 安装RabbitMQ,默认的版本是3.5.7,好像也可以选版本,以后再尝试。可喜的是通过apt-get安装的RabbitMQ成功的启动起来了。可以通过如下命令查看RabbitMQ状态。
./rabbitmqctl stauts
RabbitMQ管理工具

这是自带的一个web插件,可以用来管理消息队列,启动它的方法比较简单:
rabbitmq-plugins enable rabbitmq_management
然后重启RabbitMQ即可生效。默认生成了guest用户,但这个guest用户只能在RabbitMQ所在主机才能访问,所以要想远程访问就需要重新分配一个用户,有两种办法:
- 通过网页,以guest登录然后在页面上完成操作。
- 通过命令,创建用户,授权也可以。
创建用户,指定用户名以及密码
./rabbitmqctl add_user root root //用户名密码都是root
分配角色,administrator是可以操作和guest本地用户一样的功能,当登录上rabbitmq_management之后,里面的所有功能都可以使用。
rabbitmqctl set_user_tags root administrator
授权,队列的操作管理权限。如果不配置,那么客户端在连接消息队列时会出问题。
rabbitmqctl set_permissions -p / root ".*" ".*" ".*"
上面语句我没有执行成功,后续再研究下是不是写法问题
Spring boot集成RabbitMQ
我们在rabbitmq_management上面可以正常访问操作后,就可以放心的写demo了,这里采用spring boot。先看简单看下RabbitMQ的简易架构图,容易理解下面提到的一些组件。
生产者,消息,消费者

消息内部:Exchange,Binding,Queues

引用amqp的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
增加配置信息
这里没有采用自动配置
mq.rabbit.host=192.168.21.128
mq.rabbit.port=5672
mq.rabbit.virtualHost=/
mq.rabbit.username=root
mq.rabbit.password=root
创建RabbitMQConfig
- ConnectionFactory,类似于数据库连接等。
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(this.mqRabbitHost,this.mqRabbitPort); connectionFactory.setUsername(this.mqRabbitUserName);
connectionFactory.setPassword(this.mqRabbitPassword);
connectionFactory.setVirtualHost(this.mqRabbitVirtualHost);
connectionFactory.setPublisherConfirms(true); return connectionFactory;
}
- RabbitTemplate,用来发送消息。
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
return template;
}
- DirectExchange
@Bean
public DirectExchange defaultExchange() {
return new DirectExchange(EXCHANGE_NAME);
}
- Queue,构建队列,名称,是否持久化之类
@Bean
public Queue queue() {
return new Queue(QUEUE_NAME, true);
}
- Binding,将DirectExchange与Queue进行绑定
@Bean
public Binding binding() {
return BindingBuilder.bind(queue()).to(defaultExchange()).with(ROUTING_KEY);
}
- SimpleMessageListenerContainer,消费者
需要将ACK修改为手动确认,避免消息在处理过程中发生异常造成被误认为已经成功消费的假象。
@Bean
public SimpleMessageListenerContainer messageContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
container.setQueues(queue());
container.setExposeListenerChannel(true);
container.setMaxConcurrentConsumers(1);
container.setConcurrentConsumers(1);
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
container.setMessageListener(new ChannelAwareMessageListener() { public void onMessage(Message message, com.rabbitmq.client.Channel channel) throws Exception {
byte[] body = message.getBody();
logger.info("消费端接收到消息 : " + new String(body));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
});
return container;
}
服务端,业务逻辑,调用消息队列。
为了让客户端知道消息是否已经成功,消息队列提供了回调机制(需要实现ConfirmCallback),当消息服务器接收到消息之后会给客户端一个通知,此时客户端根据消息应答来决定后续的流程。
@Service
public class ProductServiceImpl extends BaseService implements ProductService, RabbitTemplate.ConfirmCallback { @Autowired
private ProductMapper productMapper; private RabbitTemplate rabbitTemplate; public ProductServiceImpl(RabbitTemplate rabbitTemplate){
this.rabbitTemplate=rabbitTemplate;
this.rabbitTemplate.setConfirmCallback(this);
} public void confirm(CorrelationData correlationData, boolean ack, String cause) {
this.logger.info(" 消息id:" + correlationData);
if (ack) {
this.logger.info("消息发送确认成功");
} else {
this.logger.info("消息发送确认失败:" + cause); }
} @Override
public void save(Product product) { //执行保存
String uuid = UUID.randomUUID().toString();
CorrelationData correlationId = new CorrelationData(uuid);
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, RabbitMQConfig.ROUTING_KEY, product.getName(),correlationId);
}
}
执行结果
可以清晰的看到RabbitMQ发给生产者的信息收到的确认信息,也能看到消息被消费端消费后的信息。

RabbitMQ的其它方面
高可用方案
与常见的数据库类似,都是主从模式来保证高可用,可以利用HAProxy来实现主从备份方案。
水平扩展方案
主要是为了解决垂直优化的瓶颈问题,主要有这三种:
- clustering,这是默认内置的一种集群模式,与下面两种不同的是clustering一般应用于同一局域网。
- federation,有待后续学习
- shovel,有待后续学习
不丢消息特性
这个不是RabbitMQ的专利,将消息持久化可以确保RabbitMQ重启或者死机过程中不至于丢掉没有消费的消息。
消息不被重复消费
这点要靠消费端来完成,尽管消费端可以通过ACK来通知消息队列消息已经被消费,但如果消费端消费了消息,此时ACK过程中的通知出现异常,消息队列会认为消息未被消费会继续发给消费端。
总结
初次安装可能会出现一堆问题,特别是需要安装所依赖的众多包。RabbitMQ与Erlang可能存在版本依赖问题待后续确认。spring boot下集成RabbitMQ异常简单,可以根据需求部署集群来实现可扩展高可用的消息系统。
引用
Spring boot+RabbitMQ环境的更多相关文章
- 从头开始搭建一个Spring boot+RabbitMQ环境
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- Spring Boot 多环境如何配置
Spring Boot 开发环境.测试环境.预生产环境.生产环境多环境配置 通常一个公司的应程序可能在开发环境(dev).测试环境(test).生产环境(prod)中运行.那么是不是需要拷贝不同的安装 ...
- spring boot 开发环境搭建(Eclipse)
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- Spring Boot入门系列(十五)Spring Boot 开发环境热部署
在实际的项目开发过中,当我们修改了某个java类文件时,需要手动重新编译.然后重新启动程序的,整个过程比较麻烦,特别是项目启动慢的时候,更是影响开发效率.其实Spring Boot的项目碰到这种情况, ...
- Spring Boot + RabbitMQ 配置参数解释
最近生产RabbitMQ出了几次问题,所以抽时间整理了一份关于Spring Boot 整合RabbitMQ环境下的配置参数解释,通过官网文档和网上其他朋友一些文章参考归纳整理而得,有错误之处还请指正~ ...
- kotlin web开发教程【一】从零搭建kotlin与spring boot开发环境
IDEA中文输入法的智能提示框不会跟随光标的问题 我用的开发工具是IDEA 这个版本的IDEA有一个问题: 就是中文输入法的智能提示框不会跟随光标 解决这个问题的办法很简单,只有在安装目录下把JRE文 ...
- SpringCloud入门之Spring Boot多环境配置切换指南
在 spring boot 中,有两种配置文件,一种是application.properties,另一种是application.yml,两种都可以配置spring boot 项目中的一些变量的定义 ...
- spring boot +RabbitMQ +InfluxDB+Grafara监控实践
本文需要有相关spring boot 或spring cloud 相关微服务框架的基础,如果您具备相关基础可以很容易的实现下述过程!!!!!!! 希望本文的所说对需要的您有所帮助 从这里我们开始进入闲 ...
- Spring boot+ logback环境下,日志存放路径未定义的问题
日志路径未定义 环境:Spring boot + logback 配置文件: <configuration> <springProfile name="dev"& ...
随机推荐
- Android内存优化(使用SparseArray和ArrayMap取代HashMap)
在Android开发时,我们使用的大部分都是Java的api,比方HashMap这个api,使用率非常高,可是对于Android这样的对内存非常敏感的移动平台,非常多时候使用一些java的api并不能 ...
- OC学习篇之---文件的操作
今天我们来介绍OC中文件操作,在之前的文章中,已经接触到了文件的创建了,但是那不是很具体和详细,这篇文章我们就来仔细看一下OC中是如何操作文件的: 第一.首先来看一下本身NSString类给我们提供了 ...
- 【SPOJ 694】Distinct Substrings
[链接]h在这里写链接 [题意] 给你一个长度最多为1000的字符串 让你求出一个数x,这个x=这个字符串的不同子串个数; [题解] 后缀数组题. 把原串复制一份,加在 ...
- .dmp文件导出使用示例
exp导出的几种用例,先睹为快: 1 将数据库SampleDB完全导出,用户名system 密码manager 导出到E:/SampleDB.dmp中 exp system/manager@TestD ...
- [TypeStyle] Load raw CSS in TypeStyle
TypeStyle tries to be an all in one CSS in JS management solution so you can always fall back to raw ...
- FZU 1650 1752 a^b mod c
http://acm.fzu.edu.cn/problem.php?pid=1752 http://acm.fzu.edu.cn/problem.php?pid=1650 给跪了. 我的快速幂会越界. ...
- 数据结构与算法实验题 7.1 M 商人的求救
问题描述: A 国正面临着一场残酷的战争,城市被支持不同领导的两股势力占据,作为一个商人,M先生并不太关心政治,但是他知道局势很严重,他希望你能救他出去.M 先生说:"为了安全起见,我们的路 ...
- 【53.57%】【codeforces 722D】Generating Sets
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- python implementation for Qt's QDataStream(看一下QDataStream的结构)
#!/usr/bin/env python # -*- coding: utf- -*- from __future__ import print_function from __future__ i ...
- Android 节日短信送祝福(功能篇:2-短信历史记录Fragment的编写)
因为用于展示短信记录的是一个ListView,但是为了方便,可以直接继承自ListFragment,就可以免去写ListView对应的布局了,只需要写其item对应的布局即可. item_sended ...
