前言
Spring Cloud Bus用轻量级消息代理连接分布式系统的节点。然后可以使用此代理广播状态更改(如配置更改)或其他管理指令。一个关键的想法是,总线就像一个扩展的Spring引导应用程序的分布式执行器。不过,它也可以用作应用程序之间的通信通道。该项目为AMQP经纪人或Kafka提供启动器作为运输工具。
快速启动
如果Spring Cloud Bus检测到自己在类路径上,那么它通过添加Spring Boot autconfiguration来工作。要启用总线,请将A或B添加到依赖项管理中。其余的工作由Spring Cloud完成。确保代理(RabbitMQ或Kafka)可用并已配置。在本地主机上运行时,不需要做任何事情。如果您远程运行,请使用Spring Cloud连接器或Spring引导约定来定义代理凭据,如下面的Rabbit示例所示:
application.yml
spring:
rabbitmq:
host: mybroker.com
port: 5672
username: user
password: secret
总线目前支持向侦听特定服务的所有节点或所有节点发送消息(由Eureka定义)。/bus/*
执行器名称空间有一些HTTP端点。目前,已经实现了两个。第一个,/bus/env
,发送键/值对来更新每个节点的Spring环境。第二次是/bus/refresh
,它重新加载每个应用程序的配置,就像它们都在它们的/refresh
端点上被选中一样。
总线的端点
Spring Cloud Bus提供了两个端点,/actuator/bus-refresh
和/actuator/bus-env
,分别对应于Spring Cloud Commons中的单个执行器端点,/actuator/refresh
和/actuator/env
。
总线刷新端点
/actuator/bus-refresh
端点清除RefreshScope缓存并重新绑定@ConfigurationProperties。有关更多信息,请参见RefreshScope文档。
要公开/actuator/bus-refresh
端点,需要在应用程序中添加以下配置:
management.endpoints.web.exposure.include=bus-env
总线Env端点
/actuator/bus-env
端点使用指定的键/值对跨多个实例更新每个实例环境。
要公开/actuator/bus-env
端点,您需要在应用程序中添加以下配置:
management.endpoints.web.exposure.include=bus-env
/actuator/bus-env端点接受以下形状的POST请求:
{
"name": "key1",
"value": "value1"
}
寻址一个实例
应用程序的每个实例都有一个service 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”路径参数,例如/bus-refresh/customers:9000
,其中destination
是一个服务ID。如果该ID为总线上的实例所拥有,它将处理该消息,而所有其他实例将忽略它。
寻址服务的所有实例
“destination”参数在Spring PathMatcher
中使用(路径分隔符为冒号-:
)来确定实例是否处理消息。使用前面的示例,/bus-env/customers:**
针对“customers”服务的所有实例,而不考虑服务ID的其余部分。
服务ID必须是唯一的
总线尝试两次消除处理事件—一次从原始ApplicationEvent中删除,另一次从队列中删除。为此,它检查发送服务ID和当前服务ID。如果一个服务的多个实例具有相同的ID,则不处理事件。在本地机器上运行时,每个服务位于不同的端口上,该端口是ID的一部分。Cloud Foundry提供一个index来区分。为了确保这个ID在Cloud Foundry外部是唯一的,设置spring.application.index为服务的每个实例建立唯一的索引。
定制消息代理
Spring Cloud总线使用Spring Cloud Stream广播消息。因此,要让消息流,您只需要在类路径中包含您选择的绑定器实现。使用AMQP (RabbitMQ)和Kafka (spring-cloud-starter-bus-[amqp|kafka]
)可以方便地启动总线。一般来说,Spring Cloud Stream依赖于Spring引导自动配置约定来配置中间件。例如,AMQP代理地址可以用spring.rabbitmq.*
更改配置属性。spring Cloud Bus在spring.cloud.bus .*
中有一些本地配置属性(例如,spring.cloud.bus.destination
是用作外部中间件的主题的名称)。通常,默认值就足够了。
要了解关于如何定制message broker设置的更多信息,请参阅Spring Cloud Stream文档。
跟踪总线事件
通过设置spring.cloud.bus.trace.enabled=true
,可以跟踪总线事件(RemoteApplicationEvent的子类)。如果这样做,Spring Boot TraceRepository
(如果存在)将显示发送的每个事件和来自每个服务实例的所有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信号,可以为AckRemoteApplicationEvent和SentApplicationEvent类型添加一个@EventListener(并启用跟踪)。或者,您可以访问TraceRepository并从中挖掘数据。
任何总线应用程序都可以跟踪acks。但是,有时在中央服务中执行这些操作是很有用的,因为中央服务可以对数据执行更复杂的查询,或者将数据转发到专门的跟踪服务。
广播自定义活动
总线可以携带RemoteApplicationEvent类型的任何事件。默认传输是JSON,反序列化器需要提前知道将使用哪些类型。要注册一个新类型,必须将其放在org.springframework.cloud.bus.event
的子包中。
要定制事件名,可以在定制类上使用@JsonTypeName,或者依赖于默认策略,即使用简单的类名。
生产者和消费者都需要访问类定义。
在自定义包中注册事件
如果您不能或不想使用org.springframework.cloud.bus的子包。对于您的自定义事件,您必须通过使用@RemoteApplicationEventScan注释来指定要扫描哪些包来获取类型为RemoteApplicationEvent的事件。用@RemoteApplicationEventScan指定的包包括子包。
例如,考虑以下自定义事件,称为MyEvent:
package com.acme;
public class MyEvent extends RemoteApplicationEvent {
...
}
你可以用下面的方法向反序列化器注册那个事件:
package com.acme;
@Configuration
@RemoteApplicationEventScan
public class BusConfiguration {
...
}
如果不指定值,则注册使用@RemoteApplicationEventScan的类的包。在这个例子中,com.acme是使用BusConfiguration包注册的。
你也可以通过@RemoteApplicationEventScan上的值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上指定包来注册的。
您可以指定要扫描的多个基本包。
配置属性
要查看所有总线相关配置属性的列表,请查看附录页。