*:first-child {
margin-top: 0 !important;
}

body>*:last-child {
margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}

h1 {
font-size: 28px;
color: #000;
}

h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}

h3 {
font-size: 18px;
}

h4 {
font-size: 16px;
}

h5 {
font-size: 14px;
}

h6 {
color: #777;
font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
color: #4183C4;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
padding-left: 30px;
}

ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}

dl {
padding: 0;
}

dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}

dl dt:first-child {
padding: 0;
}

dl dt>:first-child {
margin-top: 0px;
}

dl dt>:last-child {
margin-bottom: 0px;
}

dl dd {
margin: 0 0 15px;
padding: 0 15px;
}

dl dd>:first-child {
margin-top: 0px;
}

dl dd>:last-child {
margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}

pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}

pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}

pre code, pre tt {
background-color: transparent;
border: none;
}

kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}

blockquote>:first-child {
margin-top: 0px;
}

blockquote>:last-child {
margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}

/* IMAGES
=============================================================================*/

img {
max-width: 100%
}
-->

消息队列在目前分布式系统下具备非常重要的地位,如下的场景是比较适合消息队列的:

  • 跨系统的调用,异步性质的调用最佳。
  • 高并发问题,利用队列串行特点。
  • 订阅模式,数据被未知数量的消费者订阅,比如某种数据的变更会影响多个系统的数据,订单数据就是比较好理解的。

之前有一个场景是商品数据在修改后需要推送到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版本,安装过程中还遇到各种问题就不一一记录了。

http://erlang.org/doc/installation_guide/INSTALL.html

测试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环境的更多相关文章

  1. 从头开始搭建一个Spring boot+ActiveMQ高可用分布式环境

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  2. Spring boot+RabbitMQ环境

    Spring boot+RabbitMQ环境 消息队列在目前分布式系统下具备非常重要的地位,如下的场景是比较适合消息队列的: 跨系统的调用,异步性质的调用最佳. 高并发问题,利用队列串行特点. 订阅模 ...

  3. 快速搭建一个Spring Boot + MyBatis的开发框架

    前言:Spring Boot的自动化配置确实非常强大,为了方便大家把项目迁移到Spring Boot,特意总结了一下如何快速搭建一个Spring Boot + MyBatis的简易文档,下面是简单的步 ...

  4. 从零开始的Spring Boot(1、搭建一个Spring Boot项目Hello World)

    搭建一个Spring Boot项目Hello World 写在前面 从零开始的Spring Boot(2.在Spring Boot中整合Servlet.Filter.Listener的方式):http ...

  5. 如何搭建一个spring boot项目

    什么是springboot? Spring Boot俗称微服务.Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特 ...

  6. Spring Boot从入门到精通(一)搭建第一个Spring Boot程序

    Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过 ...

  7. spring boot学习01【搭建环境、创建第一个spring boot项目】

    1.给eclipse安装spring boot插件 Eclipse中安装Spring工具套件(STS): Help -> Eclipse Marketplace... 在Search标签或者Po ...

  8. spring boot 开发环境搭建(Eclipse)

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  9. Spring Boot简单环境搭建

    #### 一.创建一个简单的Maven项目 使用`Maven`,通过导入`Spring Boot`的`starter`模块,可以将许多程序依赖的包自动导入到工程中.使用`Maven`的`parent ...

随机推荐

  1. LPC2478中断控制器以及串口详解

    LPC2478的中断系统 LPC2478使用的是ARM PrimeCell向量中断控制器,一共支持32个中断向量,处于AHB空间便于系统快速访问,在中断向量的硬件优先级上还有一层可以用户自己设计的软件 ...

  2. 浅谈IOS8之size class

    文章目录 1. 简介 2. 实验 3. 实战 3.1. 修改 Constraints 3.2. 安装和卸载 Constraints 3.3. 安装和卸载 View 3.4. 其他 4. 后话 以前和安 ...

  3. 在MVC中添加拦截器实现登录后的权限验证

    1.新建一个类 (以下实现了打印日志功能) using System; using System.Collections.Generic; using System.Linq; using Syste ...

  4. 2781: [JSOI2007]文本生成器

    2781: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 8  Solved: 4[Submit][Status][We ...

  5. centos 修改/etc/fstab后无法启动

    今天做实验,增加了一个磁盘sdb1,而且也增加了自动挂载的功能/etc/fstab里增加了记录. 重新启动服务器的时候,系统启动不了了. 系统提示: 按提示 输入 root的密码,进入以Repair ...

  6. js架构设计模式——由项目浅谈JS中MVVM模式

    1.    背景 最近项目原因使用了durandal.js和knockout.js,颇有受益.决定写一个比较浅显的总结. 之前一直在用SpringMVC框架写后台,前台是用JSP+JS+标签库,算是很 ...

  7. Windows Server 2012的配置与部署

    一. 背景 这里以阿里云Windows Server 2012系统的服务器为主,介绍服务器的配置以及.Net程序的发布顺序,在后续的项目管理文章中,会介绍<运维手册>的写法. 二. 步骤 ...

  8. CFD-post的奇技淫巧

    此处记录两个后处理美化的技巧:1.关于contour显示的美化:2.关于legend的显示美化 1. 直接举例说明,现在cfd-post里导入了一个二维case,先建立一个plane: apply以后 ...

  9. 《深度探索C++对象模型》笔记——Function语意学

    member的各种调用方式 C++支持三种类型的member functions:static.nonstatic和virtual. nonstatic member functions会被编译器转换 ...

  10. Canvas贝塞尔二级曲线

    当前点到控制点,控制点到末尾点的两个连线,与这两个连线相切:<!DOCTYPE html> <html lang="en"> <head> &l ...