先说下自己开发的实例。

最近在使用 Spring Cloud Config 做分布式配置中心(基于 SVN/Git),当所有服务启动后,SVN/Git 中的配置文件更改后,客户端服务读取的还是旧的配置,并不能实时读取(配置信息会缓存在客户端),Spring Boot 提供了一种方式进行更新(通过spring-boot-starter-actuator监控模块),然后 Post 访问客户端服务的/refresh接口(也可以命令执行curl -X POST http://worker2:8115/refresh),这样客户端会重新从配置中心获取新的配置信息,请求命令可以写在 Git 的 Webhooks 脚本中(修改提交 Push 后执行)。

如果客户端服务比较少的话,这样的解决方式没问题,如果客户端服务多的话,执行的请求脚本就会非常多,而且单个服务的解决方式,也不利于后期的维护(点对点的方式),那该怎么解决上面的问题呢?答案就是通过 Spring Cloud Bus

Spring Cloud Bus 翻译为消息总线,使用轻量级的消息代理来构建一个共用的消息主题让系统中所有微服务实例都能连接上来,由于该主题中产生的消息会被所有实例监听和消费,所以我们称它为消息总线。在总线上的各个实例都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息,例如配置信息的变更或者其他一些管理操作等。

架构示意图(引用来源):

下面,我们需要利用 Spring Cloud Bus 来改造 Spring Cloud Config 的服务端和客户端,其实非常简单。

添加下面的依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

然后在bootstrap.yml中添加下面配置:

spring:
rabbitmq:
host: manager1
port: 5672
username: admin
password: admin123
management:
security:
enabled: false

上面的配置信息都是新增的,并且都需要配置在服务端和客户端,通过上面的示例图可以看到,配置信息更新后请求的是服务端,那么客户端我们就不需要配置management.security.enabled(也不需要配置spring-boot-starter-actuator监控模块)。

服务端和客户端的任何 Java 代码都不需要编写,重新启动服务,当配置信息更新后,通过 Git 的 Webhooks 执行请求脚本:curl -X POST http://manager1:port/bus/refresh服务端接受到请求之后,会通过 Spring Cloud Bus 通知所有的客户端(通过 RabbitMQ),重新从配置中心获取配置信息,达到实时更新配置的目的。

上面的实例描述就到这里。

RabbitMQ 的基本概念

RabbitMQ,是一个使用 erlang 编写的 AMQP(高级消息队列协议)的服务实现,简单来说,就是一个功能强大的消息队列服务。

RabbitMQ 最基本模型

RabbitMQ 的基本概念

  • Producer:消息生产者。
  • Consumer:消息消费者。
  • Connection(连接):Producer 和 Consumer 通过TCP 连接到 RabbitMQ Server。
  • Channel(信道):基于 Connection 创建,数据流动都是在 Channel 中进行。
  • Exchange(交换器):生产者将消息发送到 Exchange(交换器),由 Exchange 将消息路由到一个或多个 Queue 中(或者丢弃);Exchange 并不存储消息;Exchange Types 常用有 Fanout、Direct、Topic 三种类型,每种类型对应不同的路由规则。
  • Queue(队列):是 RabbitMQ 的内部对象,用于存储消息;消息消费者就是通过订阅队列来获取消息的,RabbitMQ 中的消息都只能存储在 Queue 中,生产者生产消息并最终投递到 Queue 中,消费者可以从 Queue 中获取消息并消费;多个消费者可以订阅同一个 Queue,这时 Queue 中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。
  • Binding(绑定):是 Exchange(交换器)将消息路由给 Queue 所需遵循的规则。
  • Routing Key(路由键):消息发送给 Exchange(交换器)时,消息将拥有一个路由键(默认为空), Exchange(交换器)根据这个路由键将消息发送到匹配的队列中。
  • Binding Key(绑定键):指定当前 Exchange(交换器)下,什么样的 Routing Key(路由键)会被下派到当前绑定的 Queue 中。

另外,再说下 Exchange Types(交换器类型)的三种常用类型

  • Direct:完全匹配,消息路由到那些 Routing Key 与 Binding Key 完全匹配的 Queue 中。比如 Routing Key 为cleint-key,只会转发cleint-key,不会转发cleint-key.1,也不会转发cleint-key.1.2
  • Topic:模式匹配,Exchange 会把消息发送到一个或者多个满足通配符规则的 routing-key 的 Queue。其中*表号匹配一个 word,#匹配多个 word 和路径,路径之间通过.隔开。如满足a.*.c的 routing-key 有a.hello.c;满足#.hello的 routing-key 有a.b.c.helo
  • Fanout:忽略匹配,把所有发送到该 Exchange 的消息路由到所有与它绑定 的Queue 中。

下面通过一段代码,理解一下消息发布的流程代码引用):

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel() channel.exchange_declare(exchange='first', type='topic')
channel.queue_declare(queue='A')
channel.queue_declare(queue='B') channel.queue_bind(exchange='first', queue='A', routing_key='a.*.*')
channel.queue_bind(exchange='first', queue='B', routing_key='a.#') channel.basic_publish(exchange='first',
routing_key='a',
body='Hello World!') channel.basic_publish(exchange='first',
routing_key='a.b.c',
body='Hello World!')

大致步骤

  • 先获取一个 Connection(连接)。
  • 从 Connection(连接)上获取一个 Channel(信道)。
  • 声明一个 Exchange(交换器),只会创建一次。
  • 声明两个 Queue,只会创建一次。
  • 把 Queue 绑定到 Exchange(交换器)上.
  • 向指定的 Exchange(交换器)发送一条消息.

因为基于 Exchage Topic 模式,在上面发出的两条消息当中,消息a只会被a.#匹配到,而a.b.c会被两个都匹配到。所以,最终的结果会是队列 A 中有一条消息,队列 B 中有两条消息。

从队列取出消息代码:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='A') def callback(ch, method, properties, body):
print body channel.basic_consume(callback, queue='A', no_ack=True)
channel.start_consuming()

服务消费者取出消息,需要重新创建 Connection(连接)和 Exchange(交换器),但 Queue 并不会创建,只需要从 Channel 中获取对应的 Queue 消息即可。

通过实例理解 RabbitMQ 基本概念

上面实例服务部署的情况是:三台管理服务器(config-server-git/config-server-svn)和一台工作服务器(config-client-git/config-server-svn),因为做了集群,服务的具体情况

  • config-server-git:3 个服务。
  • config-server-svn:3 个服务。
  • config-client-git:1 个服务。
  • config-client-svn:1 个服务。

所以,总的部署服务有 8 个

我们通过 RabbitMQ Server 管理界面中的内容,说下 Connection(连接)、Channel(信道)、Exchange(交换器)和 Queue(队列)的具体使用情况(根据数量理解)。

1. Connection(连接)

为什么 Connection(连接)数量为 16 个?因为部署的 8 个服务,各自发布和接受消息(即作为小心发布者,也作为消息接受者),计算公式:16 = 8 * 2

2. Channel(信道)

为什么 Channel(信道)数量为 16 个?因为 Connection(连接)数量为 16 个,Channel(信道)是在 Connection(连接)基础上创建的。

3. Exchange(交换器)

为什么 Exchange(交换器)数量为 1 个?因为都是使用的同一个 Exchange(交换器),名字为springCloudBus,Exchange Type 为topic,Routing Key 为#

4. Queue(队列)

为什么 Queue(队列)数量为 8 个?因为部署的 8 个服务,各自发布和接受的 Queue 是同一个,一个服务对应一个 Queue。

参考资料:

通过实例理解 RabbitMQ 的基本概念的更多相关文章

  1. 快速掌握RabbitMQ(一)——RabbitMQ的基本概念、安装和C#驱动

    1 RabbitMQ简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现,官网地址:http://www.rabbitmq.com.Ra ...

  2. 消息中间件——RabbitMQ(六)理解Exchange交换机核心概念!

    前言 来了解RabbitMQ一个重要的概念:Exchange交换机 1. Exchange概念 Exchange:接收消息,并根据路由键转发消息所绑定的队列. 蓝色框:客户端发送消息至交换机,通过路由 ...

  3. Effective Objective-C 2.0 — 第二章 对象、消息、运行期 - 第六条:理解“属性”这一概念

    开发者通过对象来 存储并传递数据. 在对象之间传递数据并执行任务的过程就叫做“消息传递”. 这两条特性的工作原理? Objective-C运行期环境(Objective-C runtime) ,提供了 ...

  4. oracle 实例名,数据库名概念

    拷贝于https://www.cnblogs.com/ahudyan-forever/p/6016784.html 在实际的开发应用中,关于Oracle数据库,经常听见有人说建立一个数据库,建立一个I ...

  5. [学习笔记]一个实例理解Lingo的灵敏性分析

    一个实例理解Lingo的灵敏性分析     线性规划问题的三个重要概念:    最优解就是反应取得最优值的决策变量所对应的向量.    最优基就是最优单纯形表的基本变量所对应的系数矩阵如果其行列式是非 ...

  6. 理解RabbitMQ中的AMQP-0-9-1模型

    前提 之前有个打算在学习RabbitMQ之前,把AMQP详细阅读一次,挑出里面的重点内容.后来找了下RabbitMQ的官方文档,发现了有一篇文档专门介绍了RabbitMQ中实现的AMQP模型部分,于是 ...

  7. 理解maven的核心概念

    原文出处:http://www.cnblogs.com/holbrook/archive/2012/12/24/2830519.html 好久没进行java方面的开发了,最近又完成了一个java相关的 ...

  8. 理解 UWP 视图的概念,让 UWP 应用显示多个窗口(多视图)

    原文 理解 UWP 视图的概念,让 UWP 应用显示多个窗口(多视图) UWP 应用多是一个窗口完成所有业务的,事实上我也推荐使用这种单一窗口的方式.不过,总有一些特别的情况下我们需要用到不止一个窗口 ...

  9. Spark Job-Stage-Task实例理解

    Spark Job-Stage-Task实例理解 基于一个word count的简单例子理解Job.Stage.Task的关系,以及各自产生的方式和对并行.分区等的联系: 相关概念 Job:Job是由 ...

随机推荐

  1. Extensions in UWP Community Toolkit - Overview

    概述 UWP Community Toolkit  中有一个 Extensions 的集合,它们可以帮助开发者实现很多基础功能,省去自己造轮子的过程,本篇我们先来看一下 Extensions 的功能都 ...

  2. js判断语句关于true和false后面跟数字或字符串的问题

    我经常在代码中看到很长串判断,看到就头疼,简单的整理一下. 比如:(client.top>=0&&client.left>=0&&client.bottom ...

  3. angular2 学习笔记 ( 第3方插件 jQuery and ckeditor )

    refer : https://forums.meteor.com/t/importing-ckeditor-using-npm/28919/2   (ckeditor) https://github ...

  4. Scala入门(1)Linux下Scala(2.12.1)安装

    Scala入门(1)Linux下Scala(2.12.1)安装 一.文件准备 1.1 文件名称 scala-2.12.1.tgz 1.2 下载地址 http://www.scala-lang.org/ ...

  5. s遇到错误不要慌,教你方法走四方

    我觉得不管是新手还是老手,他们都会出错,有些错误控制台会报错,而有些错误控制台不会报错 面对不会报错的时候,就有一些人烦恼,不知道怎么办了,久而久之,就失去了对学习的乐趣. 所以我在这里说一下对错误处 ...

  6. Python基础(函数-递归)

    本章内容: 深浅拷贝 函数(全局与局部变量) 内置函数 文件处理 三元运算 lambda 表达式 递归(斐波那契数列) 冒泡排序 深浅拷贝 一.数字和字符串 对于 数字 和 字符串 而言,赋值.浅拷贝 ...

  7. Android P新功能特性抢先看

    2018年3月8日,Google推出了Android P Preview版本,并提供官方镜像下载. 为了让广大开发者能够及时了解Android P的新功能特性,提前为您的app进行良好适配,WeTes ...

  8. AFNetworking 源码解读

    最近开始看第三方库优秀源码的计划,这是第一个,AFNetworking来和大家分享一下. AFNetworking 是一个十分优秀的网络框架,简单易用. 在开始之前,最好先了解一下NSURLSessi ...

  9. 使用REST风格完成MVC前后端分离

    一个具有REST风格项目的基本特征: 具有统一响应结构 前后台数据流转机制(HTTP消息与Java对象的互相转化机制) 统一的异常处理机制 参数验证机制 Cors跨域请求机制 鉴权机制 一:统一响应结 ...

  10. Python 学习开篇

    前言 最近看到一张图,有点意思: 蓝色是(成长+付出),红色是回报.有多久可以达到这个红心,要看我们自已的努力,付出了多少专注与汗水.我想说的是,水平轴并不是时间,如果不能坚持努力,可能永远都到不了那 ...