Spring Cloud Bus – Spring的云总线

最后修改: 2017年 7月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’re going to look at the new Spring Cloud Bus project. Spring Cloud Bus uses lightweight message broker to link distributed system nodes. The primary usage is to broadcast configuration changes or other management information. We can think about it as a distributed Actuator.

在这篇文章中,我们要看一下新的Spring Cloud Bus项目。Spring Cloud Bus使用轻量级的消息代理来连接分布式系统节点。其主要用途是广播配置变化或其他管理信息。我们可以把它看成是一个分布式的Actuator

The project uses AMQP broker as the transport, but Apache Kafka or Redis can be utilized instead of RabbitMQ. Other transports are not supported yet.

该项目使用AMQP代理作为传输,但可以利用Apache Kafka或Redis来代替RabbitMQ。目前还不支持其他的传输方式。

Over the course of this tutorial, we’re going to use RabbitMQ as our main transport – which we’ll naturally have running already.

在本教程的过程中,我们将使用 RabbitMQ 作为我们的主要传输工具–我们自然已经运行了它。

2. Prerequisites

2.先决条件

Before we begin, it’s recommended to have already completed “Quick Intro to Spring Cloud Configuration“. We’re going to take an existing cloud config server and client to extend them and add automatic notifications about configuration changes.

在我们开始之前,建议已经完成”Quick Intro to Spring Cloud Configuration“。我们将采用现有的云配置服务器和客户端来扩展它们,并添加关于配置更改的自动通知。

2.1. RabbitMQ

2.1.RabbitMQ

Let’s start with RabbitMQ, which we recommend running as RabbitMQ as a docker image. This is quite simple to set up – to get RabbitMQ running locally, we need to install Docker and run following commands once Docker is installed successfully:

让我们从 RabbitMQ 开始,我们建议以 RabbitMQ 作为 docker 镜像运行。这方面的设置非常简单 – 为了让 RabbitMQ 在本地运行,我们需要安装 Docker,并在 Docker 安装成功后运行以下命令。

docker pull rabbitmq:3-management

This command pulls RabbitMQ docker image together with management plugin installed and enabled by default.

此命令将 RabbitMQ docker 镜像与默认安装并启用的管理插件拉到一起。

Next, we can run RabbitMQ:

接下来,我们可以运行 RabbitMQ。

docker run -d --hostname my-rabbit --name some-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management

Once we executed the command, we can go to the web browser and open http://localhost:15672, which will show the management console login form. The default username is: ‘guest’; password: ‘guest’. RabbitMQ will also listen on port 5672.

一旦我们执行了该命令,我们就可以到网络浏览器中打开http://localhost:15672,这将显示管理控制台的登录表格。默认的用户名是。‘guest’;密码。‘guest’。RabbitMQ 还将在端口 5672 上进行监听。

3. Adding Actuator to Cloud Config Client

3.将执行器添加到云配置客户端

We should have cloud config server and cloud config client both running. To refresh configuration changes a restart of the client is required every time – which is not ideal.

我们应该有云配置服务器和云配置客户端同时运行。为了刷新配置变化,每次都需要重新启动客户端–这并不理想。

Let’s stop config client and annotate ConfigClient controller class with @RefreshScope:

让我们停止配置客户端,用@RefreshScope注解ConfigClient控制器类。

@SpringBootApplication
@RestController
@RefreshScope
public class SpringCloudConfigClientApplication {
    // Code here...
}

Finally, let’s update the pom.xml file and add Actuator:

最后,让我们更新pom.xml文件并添加Actuator。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

The latest version can be found here.

最新版本可以在这里找到。

By default, all sensitive endpoints added by the actuator are secured. This includes ‘/refresh’ endpoint. For simplicity, we will turn off security by updating application.yml:

默认情况下,由执行器添加的所有敏感端点都是安全的。这包括‘/refresh’端点。为了简单起见,我们将通过更新application.yml来关闭安全。

management:
  security:
    enabled: false

Additionally, starting with Spring Boot 2, actuator endpoints are not exposed by default. To make them available for access, we need to add this in an application.yml:

此外,从Spring Boot 2开始,actuator端点默认不公开。为了使它们可以被访问,我们需要在application.yml中添加这个。

management:
  endpoints:
    web:
      exposure:
        include: "*"

Let’s start the client first and update user role from existing ‘Developer’ to ‘Programmer’ in the properties file on GitHub. Config server will show updated values straight away; however, the client won’t. To make client see new files we just need to send an empty POST request to ‘/refresh’ endpoint, which was added by actuator:

让我们先启动客户端,在GitHub上的属性文件中将用户角色从现有的‘Developer’更新为‘Programmer’。配置服务器会直接显示更新后的值,但客户端不会。为了让客户端看到新文件,我们只需要向‘/refresh’端点发送一个空的POST请求,这个端点是由actuator添加的。

$> curl -X POST http://localhost:8080/actuator/refresh

We will get JSON file back showing updated properties:

我们将得到显示更新属性的JSON文件。

[
  "user.role"
]

Finally, we can check if the user role was updated:

最后,我们可以检查用户角色是否被更新。

$> curl http://localhost:8080/whoami/Mr_Pink
Hello Mr_Pink! You are a(n) Programmer and your password is 'd3v3L'.

The user role was updated successfully and by calling ‘/refresh’ endpoint. Client updated configuration without restarting.

通过调用‘/refresh’端点,用户角色已成功更新。客户端更新了配置,没有重新启动。

4. Spring Cloud Bus

4.Spring Cloud Bus

By using Actuator, we can refresh clients. However, in the cloud environment, we would need to go to every single client and reload configuration by accessing actuator endpoint.

通过使用Actuator,我们可以刷新客户端。然而,在云环境中,我们需要到每一个客户端,通过访问actuator端点来重新加载配置。

To solve this problem, we can use Spring Cloud Bus.

为了解决这个问题,我们可以使用Spring Cloud Bus。

4.1. Client

4.1.客户端

We need to update cloud config client so that it can subscribe to RabbitMQ exchange:

我们需要更新云配置客户端,以便它能够订阅 RabbitMQ 交换。

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

The latest version can be found here.

最新版本可以在这里找到。

To complete config client changes we need to add RabbitMQ details and enable cloud bus in an application.yml file:

为了完成配置客户端的更改,我们需要在application.yml文件中添加RabbitMQ的详细信息并启用云总线。

---
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    bus:
      enabled: true
      refresh:
        enabled: true

Please note that we are using default username and password. This needs to be updated for real life, production applications. For this tutorial this is fine.

请注意,我们使用的是默认的用户名和密码。对于现实生活中的生产应用,这需要更新。对于本教程来说,这很好。

Now, the client will have another endpoint ‘/bus-refresh’. Calling this endpoint will cause:

现在,客户端将有另一个端点‘/bus-refresh’。调用这个端点将导致。

  • get the latest configuration from the config server and update its configuration annotated by @RefreshScope
  • send a message to AMQP exchange informing about refresh event
  • all subscribed nodes will update their configuration as well

This way, we don’t need to go to individual nodes and trigger configuration update.

这样一来,我们就不需要到各个节点去触发配置更新。

4.2. Server

4.2.服务器

Finally, let’s add two dependencies to config server to automate configuration changes fully.

最后,让我们为配置服务器添加两个依赖项,使配置变化完全自动化。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-monitor</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

The latest version can be found here.

最新版本可以在这里找到。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
    <version>3.0.4.RELEASE</version>
</dependency>

The most recent version can be found here.

最新的版本可以在这里找到。

We will use spring-cloud-config-monitor to monitor configuration changes and broadcast events using RabbitMQ as transport.

我们将使用spring-cloud-config-monitor来监控配置变化,并使用RabbitMQ作为传输方式广播事件。

We just need to update application.properties and give RabbitMQ details:

我们只需要更新application.properties并给出RabbitMQ的详细信息。

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

4.3. GitHub Webhook

4.3.GitHub Webhook

Everything is set now. Once the server gets notified about configuration changes, it will broadcast this as a message to RabbitMQ. The client will listen to messages and update its configuration when configuration change event is transmitted. However, how a server will now about the modification?

现在一切都设置好了。一旦服务器得到关于配置更改的通知,它将把这作为消息广播给 RabbitMQ。客户端将监听消息并在配置更改事件被传送时更新其配置。然而,服务器将如何了解修改情况?

We need to configure a GitHub Webhook. Let’s go to GitHub and open our repository holding configuration properties. Now, let’s select Settings and Webhook. Let’s click on Add webhook button.

我们需要配置一个GitHub Webhook。让我们去GitHub,打开保存配置属性的仓库。现在,让我们选择SettingsWebhook。让我们点击添加webhook按钮。

Payload URL is the URL for our config server ‘/monitor’ endpoint. In our case the URL will be something like this:

有效载荷URL是我们的配置服务器‘/monitor’端点的URL。在我们的例子中,这个URL将是这样的。

http://root:s3cr3t@REMOTE_IP:8888/monitor

http://root:s3cr3t@REMOTE_IP:8888/monitor

We just need to change Content type in the drop-down menu to application/json. Next, please leave Secret empty and click on Add webhook button – after that, we are all set.

我们只需要将下拉菜单中的内容类型改为application/json。接下来,请将Secret留空,并点击Add webhook按钮–之后,我们就完成了。

5. Testing

5.测试

Let’s make sure all applications are running. If we go back and check client it will show user.role as ‘Programmer’ and user.password as ‘d3v3L‘:

让我们确保所有的应用程序都在运行。如果我们回去检查客户端,它将显示user.role‘Programmer’user.password为’d3v3L‘。

$> curl http://localhost:8080/whoami/Mr_Pink
Hello Mr_Pink! You are a(n) Programmer and your password is 'd3v3L'.

Previously, we had to use ‘/refresh’ endpoint to reload configuration changes. Let’s open properties file, change user.role back to Developer and push the changes:

以前,我们必须使用‘/refresh’端点来重新加载配置变化。让我们打开属性文件,把user.role改回Developer,然后推送这些变化。

user.role=Programmer

If we check the client now, we will see:

如果我们现在检查客户端,我们会看到。

$> curl http://localhost:8080/whoami/Mr_Pink
Hello Mr_Pink! You are a(n) Developer and your password is 'd3v3L'.

Config client updated its configuration without restarting and without explicit refresh almost simultaneously. We can go back to GitHub and open the recently created Webhook. At the very bottom, there are Recent Deliveries. We can select one on the top of the list (assuming this was the first change – there will be only one anyway) and examine JSON that has been sent to config server.

配置客户端几乎同时更新了它的配置,没有重启,也没有显式刷新。我们可以回到GitHub,打开最近创建的Webhook。在最下面,有最近交付的项目。我们可以选择列表顶部的一个(假设这是第一个变化–反正只有一个),检查发送到配置服务器的JSON。

We can also check config and server logs, and we will see entries:

我们还可以检查配置和服务器日志,我们会看到条目。

o.s.cloud.bus.event.RefreshListener: Received remote refresh request. Keys refreshed []

6. Conclusion

6.结论

In this article, we took existing spring cloud config server and client and added actuator endpoint to refresh client configuration. Next, we used Spring Cloud Bus to broadcast configuration changes and automate client updates. We also configured GitHub Webhook and tested the whole setup.

在这篇文章中,我们采用了现有的Spring Cloud config服务器和客户端,并添加了执行器端点来刷新客户端配置。接下来,我们使用Spring Cloud Bus来广播配置变化并自动更新客户端。我们还配置了GitHub Webhook并测试了整个设置。

As always, the code used during the discussion can be found over on GitHub.

一如既往,讨论中所使用的代码可以在GitHub上找到over