# Spring Cloud 总线
Spring Cloud总线将分布式系统的节点与轻量级消息代理连接起来。然后可以使用此代理来广播状态更改(例如配置更改)或其他管理指令。一个关键的想法是,总线就像是 Spring 启动应用程序的分布式执行器,该应用程序是按比例扩展的。然而,它也可以用作应用程序之间的沟通渠道。该项目为 AMQP 代理或 Kafka 提供了作为传输的启动器。
Spring Cloud是在非限制性的 Apache2.0 许可下发布的。如果你想对文档的这一部分做出贡献,或者你发现了一个错误,请在github (opens new window)的项目中找到源代码和问题追踪器。 |
---|
# 1.快速启动
Spring Cloud总线的工作原理是,如果在 Classpath 上检测到自身,则添加 Spring 引导自动配置。要启用总线,请将spring-cloud-starter-bus-amqp
或spring-cloud-starter-bus-kafka
添加到依赖项管理中。 Spring 剩下的事由云来解决。确保代理(RabbitMQ 或 Kafka)可用并进行了配置。在 LocalHost 上运行时,你不需要做任何事情。如果远程运行,请使用 Spring Cloud Connectors 或 Spring Boot 约定来定义代理凭据,如下面的 Rabbit 示例所示:
应用程序.yml
spring:
rabbitmq:
host: mybroker.com
port: 5672
username: user
password: secret
总线目前支持将消息发送到监听的所有节点或特定服务的所有节点(由 Eureka 定义)。执行器名称空间/bus/*
具有一些 HTTP 端点。目前,有两个项目已经实施。第一种是/bus/env
,它发送键/值对来更新每个节点的 Spring 环境。第二种是/bus/refresh
,重新加载每个应用程序的配置,就好像它们都在其/refresh
端点上被 pinged 了一样。
Spring Cloud总线启动器覆盖 Rabbit 和 Kafka,因为这是两个最 的常见实现。然而, Spring Cloud流是相当灵活的,并且活页夹 与 spring-cloud-bus 一起工作。 |
---|
# 2.总线端点
Spring Cloud Bus 提供了两个端点,/actuator/busrefresh
和/actuator/busenv
,它们分别对应于 Spring Cloud Commons 中的单个执行器端点,/actuator/refresh
和/actuator/env
。
# 2.1.总线刷新端点
/actuator/busrefresh
端点清除RefreshScope
缓存并重新绑定@ConfigurationProperties
。有关更多信息,请参见刷新范围文档。
要公开/actuator/busrefresh
端点,需要向应用程序添加以下配置:
management.endpoints.web.exposure.include=busrefresh
# 2.2.总线 ENV 端点
/actuator/busenv
端点使用跨多个实例的指定键/值对更新每个实例环境。
要公开/actuator/busenv
端点,需要向应用程序添加以下配置:
management.endpoints.web.exposure.include=busenv
/actuator/busenv
端点接受具有以下形状的POST
请求:
{
"name": "key1",
"value": "value1"
}
# 3.寻址实例
应用程序的每个实例都有一个服务 ID,其值可以用spring.cloud.bus.id
设置,其值应该是一个以冒号分隔的标识符列表,顺序从最不特定到最特定。默认值是作为spring.application.name
和server.port
(或spring.application.index
,如果设置)的组合从环境构造的。ID 的默认值以app:index:id
的形式构造,其中:
app
是vcap.application.name
,如果它存在,或者spring.application.name
index
是vcap.application.instance_index
,如果存在,spring.application.index
,local.server.port
,server.port
,或0
(按此顺序排列)。id
是vcap.application.instance_id
,如果它存在,或者是一个随机值。
HTTP 端点接受一个“destination”路径参数,例如/busrefresh/customers:9000
,其中destination
是一个服务 ID。如果 ID 由总线上的一个实例拥有,那么它将处理消息,而所有其他实例将忽略它。
# 4.处理服务的所有实例
在 Spring PathMatcher
(路径分隔符为冒号—:
)中使用“destination”参数来确定实例是否处理消息。使用前面的示例,/busenv/customers:**
以“客户”服务的所有实例为目标,而不考虑服务 ID 的其余部分。
# 5.服务 ID 必须是唯一的
总线尝试两次消除处理一个事件——一次来自原始ApplicationEvent
,一次来自队列。为此,它会根据当前的服务 ID 检查发送服务 ID。如果一个服务的多个实例具有相同的 ID,则不会对事件进行处理。当在本地机器上运行时,每个服务都位于不同的端口上,而该端口是 ID 的一部分。Cloud Foundry 提供了一个用于区分的索引。要确保 ID 在 Cloud Foundry 之外是唯一的,请将spring.application.index
设置为服务的每个实例都是唯一的。
# 6.自定义消息代理
Spring Cloud总线使用Spring Cloud Stream (opens new window)来广播消息。因此,要使消息流起来,你只需要在 Classpath 中包含你选择的绑定器实现。对于具有 AMQP 和 Kafka(spring-cloud-starter-bus-[amqp|kafka]
)的总线,有方便的启动器。一般来说, Spring Cloud Stream 依赖于 Spring Boot AutoConfiguration 约定来配置中间件。例如,可以使用spring.rabbitmq.*
配置属性更改 AMQP 代理地址。 Spring Cloud Bus 在spring.cloud.bus.*
中具有少量的本机配置属性(例如,spring.cloud.bus.destination
是用作外部中间件的主题的名称)。通常情况下,默认值就足够了。
要了解有关如何自定义消息代理设置的更多信息,请参阅 Spring Cloud Stream 文档。
# 7.追踪总线事件
总线事件(RemoteApplicationEvent
的子类)可以通过设置spring.cloud.bus.trace.enabled=true
来跟踪。如果这样做, Spring bootTraceRepository
(如果存在)将显示发送的每个事件和来自每个服务实例的所有 ACK。以下示例来自/trace
端点:
{
"timestamp": "2015-11-26T10:24:44.411+0000",
"info": {
"signal": "spring.cloud.bus.ack",
"type": "RefreshRemoteApplicationEvent",
"id": "c4d374b7-58ea-4928-a312-31984def293b",
"origin": "stores:8081",
"destination": "*:**"
}
},
{
"timestamp": "2015-11-26T10:24:41.864+0000",
"info": {
"signal": "spring.cloud.bus.sent",
"type": "RefreshRemoteApplicationEvent",
"id": "c4d374b7-58ea-4928-a312-31984def293b",
"origin": "customers:9000",
"destination": "*:**"
}
},
{
"timestamp": "2015-11-26T10:24:41.862+0000",
"info": {
"signal": "spring.cloud.bus.ack",
"type": "RefreshRemoteApplicationEvent",
"id": "c4d374b7-58ea-4928-a312-31984def293b",
"origin": "customers:9000",
"destination": "*:**"
}
}
前面的跟踪显示,一个RefreshRemoteApplicationEvent
从customers:9000
发送,广播到所有服务,并由customers:9000
和stores:8081
接收。
要自己处理 ACK 信号,可以在应用程序中添加@EventListener
和SentApplicationEvent
类型的@EventListener
(并启用跟踪)。或者,你可以利用TraceRepository
并从那里挖掘数据。
任何总线应用程序都可以跟踪 ACK。然而,有时,在可以对数据执行更复杂的 查询或将其转发给专门的跟踪服务的中心服务中执行此操作是很有用的。 |
---|
# 8.播放自己的活动
总线可以承载类型RemoteApplicationEvent
的任何事件。默认传输是 JSON,反序列化器需要提前知道要使用哪些类型。要注册一个新类型,必须将其放入org.springframework.cloud.bus.event
的子包中。
要自定义事件名,你可以在自定义类上使用@JsonTypeName
,也可以使用默认策略,即使用类的简单名称。
生产者和消费者都需要访问类定义。 |
---|
# 8.1.在自定义包中注册事件
如果你不能或不想使用org.springframework.cloud.bus.event
的子包来表示你的自定义事件,那么你必须指定要使用RemoteApplicationEvent
注释来扫描类型为@RemoteApplicationEventScan
的事件的包。用@RemoteApplicationEventScan
指定的包包括子包。
例如,考虑以下自定义事件,称为MyEvent
:
package com.acme;
public class MyEvent extends RemoteApplicationEvent {
...
}
你可以通过以下方式向反序列化器注册该事件:
package com.acme;
@Configuration
@RemoteApplicationEventScan
public class BusConfiguration {
...
}
在不指定值的情况下,注册了使用@RemoteApplicationEventScan
的类的包。在本例中,com.acme
通过使用BusConfiguration
的包进行注册。
还可以在@RemoteApplicationEventScan
上使用value
、basePackages
或basePackageClasses
属性显式地指定要扫描的包,如以下示例所示:
package com.acme;
@Configuration
//@RemoteApplicationEventScan({"com.acme", "foo.bar"})
//@RemoteApplicationEventScan(basePackages = {"com.acme", "foo.bar", "fizz.buzz"})
@RemoteApplicationEventScan(basePackageClasses = BusConfiguration.class)
public class BusConfiguration {
...
}
前面的@RemoteApplicationEventScan
的所有示例都是等效的,因为com.acme
包是通过在@RemoteApplicationEventScan
上显式指定包来注册的。
你可以指定要扫描的多个基包。 |
---|
# 9.配置属性
要查看所有与总线相关的配置属性的列表,请检查附录页。