消息总线——Spring Cloud Bus

(git上的源码:https://gitee.com/rain7564/spring_microservices_study/tree/master/seventh-spring-cloud-bus)

回顾

之前的Spring Cloud入门教程系列的一篇文章分布式配置——Spring Cloud Configuration的末尾讲到当托管在Spring Cloud Config Server的配置发生变化后, 可通过调用服务暴露的"/refresh" endpoint来更新某个服务实例的配置,http方法为POST,前提是服务引入特定依赖,且不关闭动态刷新功能,所需启动依赖和支持动态刷新的配置分别如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
endpoints:
  refresh:
    enabled: true

属性endpoints.refresh.enabled默认为true。所以若不需要关闭,可以不配置该属性。

但是,这种做法有一个很致命的弊端——一次只能对指定服务的某个实例进行刷新操作。而微服务架构下,一个服务通常会同时运行多个实例,所以当需要刷新配置时,就必须知道正在运行的所有实例的地址,然后逐个去刷新。这显然与Spring Cloud的自动化、尽量减少人工干预的理念相悖,而Spring Cloud的生态这么大,肯定有对应的解决之法,所以接下来将要讲解的Spring Cloud Bus就是为了解决这一难题而存在的。

虽然有web hook这样的技术配合"/refresh"实现动态刷新,但一个云应用可不止一个微服务存在,随着微服务数量增多,需要维护的刷新列表会越来越大,所以还是不推荐使用访问服务实例的/"refresh" endpoint 来刷新服务的配置。

何为Spring Cloud Bus

官方文档的介绍如下:

Spring Cloud Bus links nodes of a distributed system with a lightweight message broker. This can then be used to broadcast state changes (e.g. configuration changes) or other management instructions. A key idea is that the Bus is like a distributed Actuator for a Spring Boot application that is scaled out, but it can also be used as a communication channel between apps. Starters are provided for an AMQP broker as the transport or for Kafka, but the same basic feature set (and some more depending on the transport) is on the roadmap for other transports.

大致的意思是:Spring Cloud Bus(消息总线)通过一个轻量级的消息中间件可以连接分布式系统中的各个节点。可以使用该总线来广播某些状态的改变(比如配置信息发生变更)或其他管理指令。可以说,消息总线是spring boot应用扩展“道路”上的推进器,而且也把它用来作应用间相互通信的消息管道。(剩下的没什么营养就略过了,哈哈)

说实在的,我经常会觉得官网的文档有时很难去理解,但有时却又不得不去看官方文档不知各位看官是不是有同感,唉。。。为了让各位看官更好理解,这里就多费些口舌了。

在上一节消息驱动——Spring Cloud Stream中,我们可以体会到异步调用能让各个服务充分解耦而且也更加灵活。而Spring Cloud Bus就是借助消息驱动来实现将消息(事件)广播到各个服务中,然后服务对这些消息进行消费。我们都知道,多个服务可以监听同一个主题,多个服务也可以将消息发送到同一个主题,所以只要构建一个共用的topic(消息主题),然后各个服务实例都连接上来,当主题中有新的消息,那么会被所有监听该主题的服务实例消费,基于这样的特点,我们称它为消息总线。

各个实例可以通过该总线广播一些需要让其他服务实例都知道的消息,或者通知指定服务实例甚至指定服务的指定实例。总之,消息总线在微服务架构中被广泛使用,就像配置中心一样。

快速入门

改造代码

这里我们使用之前介绍Spring Cloud Config时创建的项目来进行改造。上一节介绍消息驱动——Spring Cloud Stream时使用的是RabbitMQ来作为消息中间件,所以这里也同样使用RabbitMQ来做示范。

首先,在licenseservice服务的pom文件中加入如下依赖:

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

这里虽说使用RabbitMQ作为消息中间件,但可以不用加入类似spring-cloud-starter-stream-rabbit的启动依赖,因为spring-cloud-starter-bus-amqp已经引用了spring-cloud-starter-stream-rabbit依赖。

然后,为了示范的方便,加入了ExamplePropertyController,如下:

@RestController
public class ExamplePropertyController {
    @Autowired
    private ServiceConfig serviceConfig;

    @GetMapping("/example/property")
    public String example() {
        return serviceConfig.getExampleProperty();
    }
}

最后,为了能使用控制台启动多个licenseservice服务实例,将托管在config-server的licenseservice服务配置文件中的server.prot属性迁移到bootstrap.yml中。说的还不如画的,上图:

image.png

到这里,代码基本改造完毕,接下来是各位看官最关心的——验证。

接下来为了方便测试,使用config-server的classpath作为配置文件存储库,读者可以自己使用git作为存储库来测试。

动态刷新

在测试之前,有一点需要注意的,license-service服务的ServiceConfig有没有加上@RefreshScope注解,或者注解被注释掉了。

集体刷新

依次启动discovery-eureka、config-server服务,再启动两个license-service服务实例,端口号分别为10000和10001,。至于如何启动多个服务实例,可以参考另一篇文章服务注册与发现——Netflix Eureka,其中有介绍,在偏后的位置,也可以直接全局搜索-jar

启动完毕后,分别访问localhost:10000/example/propertylocalhost:10001/example/property。可以看到返回结果都是I am the default.

然后,修改config-server存储库license-service服务的application.yml文件中的example.property属性,比如修改为I am the default. And I have changed.,接着重启config-server服务,这个操作类似于git的push。接下来就是不一样的地方了。

使用postman访问license-service服务某个实例的端点/bus/refresh,http方法为POST。比如访问10000端口的实例:localhost:10000/bus/refresh

当成功返回后,可以在打印台中看到类似如下日志:


image.png

如果控制台打印了Received remote refresh request. Keys refreshed [example.property],就代表配置信息已经刷新完成。切换到10001端口实例的日志打印,同样也有刷新完成的日志打印,类似如下:

image.png

最后,分别访问localhost:10000/example/propertylocalhost:10001/example/property。现在的返回结果都是I am the default. And I have changed.

快十二点了,明天还要上班,暂时就先到这里哈。各位看官见谅,见谅~~~
(未完待续)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容