先说下自己开发的实例。

最近在使用 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: manager1port: 5672username: adminpassword: 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 pikaconnection = 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 pikaconnection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='A')def callback(ch, method, properties, body):print bodychannel.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 消息队列 - RabbitMQ 消息队列架构与基本概念(推荐
  • RabbitMQ 使用参考(推荐
  • RabbitMq(一)走进 RabbitMq
  • RabbitMQ 基本概念和使用(推荐
  • 分布式消息队列 RabbitMQ 之一:基本概念理解
  • RabbitMQ 基础概念详细介绍
  • RabbitMQ 基本概念

通过实例理解 RabbitMQ 的基本概念相关推荐

  1. 理解系统底层的概念是多么重要

    理解系统底层的概念是多么重要                                --趋势科技邹飞评<程序员的自我修养>   关于<程序员的自我修养>这本书,最初是在 ...

  2. 通过实例理解Go Execution Tracer

    本文永久链接[1] - https://tonybai.com/2021/06/28/understand-go-execution-tracer-by-example Netflix(奈飞公司)的性 ...

  3. 理解五个基本概念,让你更像机器学习专家

    理解五个基本概念,让你更像机器学习专家 https://www.jianshu.com/p/ca37ea88a757 摘要: 这篇文章主要讲述了机器学习的相关内容,阐述了机器学习的主要意义和形成过程. ...

  4. 深入理解正则表达式环视的概念与用法

    在<深入理解正则表达式高级教程-环视>中已经对环视做了简单的介绍,但是,可能还有一些读者比较迷惑,今天特意以专题的形式,深入探讨一下正则表达式的环视的概念与用法. 深入理解正则表达式环视的 ...

  5. 通过实例理解 JDK8 的 CompletableFuture

    转载自 通过实例理解 JDK8 的 CompletableFuture 前言 Java 5 并发库主要关注于异步任务的处理,它采用了这样一种模式,producer 线程创建任务并且利用阻塞队列将其传递 ...

  6. 【计算视觉】理解图像中基本概念:色调、色相、饱和度、对比度、亮度

    理解图像中基本概念:色调.色相.饱和度.对比度.亮度 对比度: 对比度指不同颜色之间的差别.对比度越大,不同颜色之间的反差越大,即所谓黑白分明,对比度过大,图像就会显得很刺眼.对比度越小,不同颜色之间 ...

  7. 理解操作系统的进程的概念就如吃饭一样简单

    进程作为操作系统基础,想要学好操作系统的理论知识,首先要掌握进程的概念.进程的理解可以抽象的思维来理解,也可以直接去挖掘 Linux 的源码来看看林纳斯大神是怎么用数据结构来描述进程的.对于大部分初学 ...

  8. 使用JDBC实例理解数据库的事务隔离

    使用JDBC实例理解数据库的事务隔离 数据库的事务是用来处理数据的一个机制,作为一个整体,要么全部提交,要么全部回滚.     事务的4大特性(ACID): 原子性(Atomicity):事务是数据库 ...

  9. java猫抓老鼠_用猫抓老鼠的实例理解java中面向对象的编程与类和对象以及方法的概念...

    今天看到马士兵讲的关于面向对象编程的思路,用了一个猫抓老鼠的例子,我觉得这个例子非常形象,于是写在这里,方便学习理解和以后查看 class cat{ //声明一个类–"猫" int ...

最新文章

  1. 根据status信息对MySQL服务器进行优化-2
  2. Nature Methods:快速准确的微生物来源追溯工具FEAST
  3. 如何从字符串中删除文本?
  4. Go []byte to a C *char
  5. POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘...
  6. 如何采用锂离子电池提高数据中心电源效率
  7. 区块链成熟度评测报告
  8. [MySQL 优化] 移除多余的checksum
  9. CodeForces - 1437G Death DBMS(AC自动机fail树上树链剖分建线段树/暴跳fail)
  10. Kafka消息序列化和反序列化(上)
  11. u-boot.lds文件简介
  12. 在javascript中调用java
  13. 学习使用Visual studio 时碰到的坑
  14. Java魔法堂:JVM的运行模式
  15. Java基础,Java的main方法与构造方法之间的联系,以及构造方法的联系和使用,栈堆理解
  16. 从自建服务器到选择阿里云 慎重选择
  17. 一篇Chat(沉迷机器人操作系统(ROS)的一个理由和四种修仙秘籍)
  18. 最新王通《搜索排名引爆点》课值得学习吗
  19. 【DDNS更新】--公云的DDNS自动更新
  20. python生成中文字符画_python制作字符画

热门文章

  1. Java时间和时间戳的相互转换
  2. jQuery学习随笔(一)
  3. Maven实战系列文章目录
  4. ETL工具调度之中美PK
  5. ASP.NET中常用的js代码
  6. WCF duplex service + silverlight 聊天代码
  7. Scrapy 框架 中间件,信号,定制命令
  8. C语言指针的一些题目
  9. “六神”——技术提高开发效率的一个方案
  10. box unboxing(装箱 拆箱) C#编程指南