springcloud下的微服务-消息总线spring cloud bus

参考
史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)

springcloud(九):配置中心和消息总线(配置中心终结版)

Config Server——使用Spring Cloud Bus自动刷新配置

Spring cloud bus通过轻量消息代理连接各个分布的节点。这会用在广播状态的变化(例如配置变化)或者其他的消息指令。Spring bus的一个核心思想是通过分布式的启动器对spring boot应用进行扩展,也可以用来建立一个多个应用之间的通信频道。目前唯一实现的方式是用AMQP(Advanced Message Queuing Protocol,高级消息队列协议)消息代理作为通道,同样特性的设置(有些取决于通道的设置)在更多通道的文档中。

关于AMQP可以看文档
RabbitMQ 中文文档
RabbitMQ与AMQP协议详解
AMQP协议(经典)

本质是利用了MQ的广播机制在分布式的系统中传播消息,目前常用的有Kafka和RabbitMQ。利用bus的机制可以做很多的事情,其中配置中心客户端刷新就是典型的应用场景之一

因为一般来说更新了配置,就要重启服务,但是在实际应用中这是不可取的,所以使用spring cloud bus可以做到不重启服务即可得到更新后的配置

springcloud下的微服务-消息总线spring cloud bus_第1张图片

1、提交代码触发post给客户端A发送bus/refresh
2、客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus
3、Spring Cloud bus接到消息并通知给其它客户端
4、其它客户端接收到通知,请求Server端获取最新配置
5、全部客户端均获取到最新的配置

为了验证一个client刷新后,其他client也可以得到最新的配置,我创建了两个client

两个都添加依赖

<dependency>
     <groupId>org.springframework.cloudgroupId>
     <artifactId>spring-cloud-starter-bus-amqpartifactId>
dependency>

该依赖要先安装rabbitMQ,参加下面
RabbitMQ系列(一):Windows下RabbitMQ安装及入门
RabbitMQ安装教程(Windows/Linux都有)

在引入依赖的过程中,maven老是报Failed to read artifact descriptor spring-cloud-starter-bus-amqp 1.3.0.RELEASE ,这个又是一个大坑,浪费我好多时间,最后无奈上maven看最新的的version为1.3.3,添加后就解决了这个问题

<version>1.3.3.RELEASEversion>

我看到网上有其他maven命令行解决的方法,没有试过,在此贴出来供参考
Maven: Failed to read artifact descriptor

两个client都在bootstrap.yml中添加以下内容:

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

启动后发现console有这么一句

[           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/bus/refresh],methods=[POST]}" onto public void org.springframework.cloud.bus.endpoint.RefreshBusEndpoint.refresh(java.lang.String)

说明此时有一个/bus/refresh 端点,引入的依赖生效

注意,/bus/refresh只支持POST方法
此时用postman或curl 发送POST请求,会发现返回401 ,这个时候需要先关闭验证,在application.properties中加入

另外对于springboot里面的spring-boot-starter-actuator包,需要在配置一次management: security: enabled: false 否则请求reflash会报权限问题

#关闭验证
management.security.enabled=false

但是我感觉到很奇怪,我如果不引入spring-boot-starter-actuator也会有这个问题,不知道是否哪里的问题

因为我使用的spring cloud是Dalston.RELEASE版本,其支持的springboot 版本是1.5.x,而我看到有些网友说在springboot 2.0中spring-boot-starter-actuatorendpoints默认全部隐藏的
需要在配置文件里加上
management.endpoints.web.exposure.include=*
当然安全起见不一定全部暴露,可以[“health”,”mappings”,”bus-refresh”]这样指定暴露哪些端点,默认路径也变成了/actuator开头,比如这里的bus/refresh变成了
http://host:port/actuator/bus-refresh
可以通过management.endpoints.web.base-path来配置这个”/actuator”

重新启动server和client,改动git上的文件,POST /bus/refresh 后发现并未生效,这是因为你未添加@RefreshScope,这个注解一定要注解到获取配制文件的类上,这样子的话springboot才会自动刷新配制文件里面的属性值,reflash才起作用,我把它添加到了启动类上,注意,两个client都要添加,这样两个client才会自动刷新配制文件里面的属性值,reflash才起作用

再次重新启动server和两个client,改动git上的文件,其中一个client POST /bus/refresh 后,可以看到两个client都能得到最新的属性值

你可以看到rabbitMQ的变化
springcloud下的微服务-消息总线spring cloud bus_第2张图片

局部刷新

某些场景下(例如灰度发布),我们可能只想刷新部分微服务的配置,此时可通过/bus/refresh端点的destination参数来定位要刷新的应用程序。

例如:/bus/refresh?destination=customers:9000 ,这样消息总线上的微服务实例就会根据destination参数的值来判断是否需要要刷新。其中,customers:9000 指的是各个微服务的ApplicationContext ID。

destination参数也可以用来定位特定的微服务。例如:/bus/refresh?destination=customers:** ,这样就可以触发customers微服务所有实例的配置刷新。

将spring-cloud-bus配置在config-server上

在前面的示例中,我们通过请求某个微服务的/bus/refresh端点的方式来实现配置刷新,但这种方式并不优雅。原因如下:

(1) 打破了微服务的职责单一性。微服务本身是业务模块,它本不应该承担配置刷新的职责。

(2) 破坏了微服务各节点的对等性。

(3) 有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就不得不修改WebHook的配置。

我们将Config Server也加入到消息总线中,并使用Config Server的/bus/refresh端点来实现配置的刷新。这样,各个微服务只需要关注自身的业务,而不再承担配置刷新的职责。

springcloud下的微服务-消息总线spring cloud bus_第3张图片

跟踪总线事件

一些场景下,我们可能希望知道Spring Cloud Bus事件传播的细节。此时,我们可以跟踪总线事件

跟踪总线事件非常简单,只需设置spring.cloud.bus.trace.enabled=true ,这样在/bus/refresh端点被请求后,访问/trace端点就可获得类似如下的结果:

 {
        "timestamp": 1523347161999,
        "info": {
            "signal": "spring.cloud.bus.sent",
            "type": "RefreshRemoteApplicationEvent",
            "id": "cd1f6198-8ff7-4134-bc0c-1a5592aea125",
            "origin": "config-server:8888",
            "destination": "**:**"
        }
    },
    {
        "timestamp": 1523347161997,
        "info": {
            "signal": "spring.cloud.bus.ack",
            "event": "RefreshRemoteApplicationEvent",
            "id": "cd1f6198-8ff7-4134-bc0c-1a5592aea125",
            "origin": "config-server:8888",
            "destination": "**"
        }
    },
    {
        "timestamp": 1523347104203,
        "info": {
            "method": "GET",
            "path": "/haha/dev/master",
            "headers": {
                "request": {
                    "accept": "application/json, application/*+json",
                    "user-agent": "Java/1.8.0_121",
                    "host": "my-pc:8888",
                    "connection": "keep-alive"
                },
                "response": {
                    "X-Application-Context": "config-server:8888",
                    "Content-Type": "application/json;charset=UTF-8",
                    "Transfer-Encoding": "chunked",
                    "Date": "Tue, 10 Apr 2018 07:58:24 GMT",
                    "status": "200"
                }
            }
        }
    },

此时的server的application.yml如下

spring:
  application:
    name: config-server

  cloud:
    config:
      label: master
      server:
        git:
          uri: https://github.com/MyBrokenHeart/springcloudconfig.git
          search-paths: test1,test2
          username:
          password:
    bus:
      trace:
        enabled: true

  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest


server:
  port: 8888

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

management:
  security:
      enabled: false

你可能感兴趣的:(springcloud)