spring-cloud-bus.md 10.8 KB
Newer Older
茶陵後's avatar
茶陵後 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
# Spring 云总线

Spring 云总线将分布式系统的节点与轻量级消息代理连接起来。然后可以使用此代理来广播状态更改(例如配置更改)或其他管理指令。一个关键的想法是,总线就像是 Spring 启动应用程序的分布式执行器,该应用程序是按比例扩展的。然而,它也可以用作应用程序之间的沟通渠道。该项目为 AMQP 代理或 Kafka 提供了作为传输的启动器。

|   |Spring 云是在非限制性的 Apache2.0 许可下发布的。如果你想对文档的这一部分做出贡献,或者你发现了一个错误,请在[github](https://github.com/spring-cloud/spring-cloud-bus)上找到项目中的源代码和问题追踪器。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## [](#quick-start)[1. Quick Start](#quick-start)

Spring 如果云总线在 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 云总线启动器覆盖 Rabbit 和 Kafka,因为这是两个最<br/>的常见实现。然而, Spring 云流是相当灵活的,并且活页夹<br/>`spring-cloud-bus`一起工作。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## [](#bus-endpoints)[2.总线端点](#bus-endpoints)

Spring 云总线提供了两个端点,`/actuator/busrefresh``/actuator/busenv`,这两个端点分别对应于 Spring 云共享空间中的各个执行器端点,`/actuator/refresh``/actuator/env`

### [](#bus-refresh-endpoint)[2.1.总线刷新端点](#bus-refresh-endpoint)

`/actuator/busrefresh`端点清除`RefreshScope`缓存并重新绑定 @configrationProperties`。有关更多信息,请参见[Refresh Scope](#refresh-scope)文档。

要公开`/actuator/busrefresh`端点,需要向应用程序添加以下配置:

```
management.endpoints.web.exposure.include=busrefresh
```

### [](#bus-env-endpoint)[2.2.总线 ENV 端点](#bus-env-endpoint)

`/actuator/busenv`端点使用跨多个实例的指定键/值对更新每个实例环境。

要公开`/actuator/busenv`端点,需要向应用程序添加以下配置:

```
management.endpoints.web.exposure.include=busenv
```

`/actuator/busenv`端点接受具有以下形状的`POST`请求:

```
{
    "name": "key1",
    "value": "value1"
}
```

## [](#addressing-an-instance)[3.寻址实例](#addressing-an-instance)

应用程序的每个实例都有一个服务 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 由总线上的一个实例拥有,那么它将处理消息,而所有其他实例将忽略它。

## [](#addressing-all-instances-of-a-service)[4.处理服务的所有实例](#addressing-all-instances-of-a-service)

在 Spring `PathMatcher`(路径分隔符为冒号—`:`)中使用“destination”参数来确定实例是否处理消息。使用前面的示例,`/busenv/customers:**`的目标是“Customers”服务的所有实例,而不考虑服务 ID 的其余部分。

## [](#service-id-must-be-unique)[5.服务 ID 必须是唯一的](#service-id-must-be-unique)

总线尝试两次消除处理一个事件——一次从原始的“ApplicationEvent”中删除,一次从队列中删除。为此,它会根据当前的服务 ID 检查发送服务 ID。如果一个服务的多个实例具有相同的 ID,则不会对事件进行处理。当在本地机器上运行时,每个服务都位于不同的端口上,而该端口是 ID 的一部分。Cloud Foundry 提供了一个用于区分的索引。要确保 ID 在 Cloud Foundry 之外是唯一的,请将`spring.application.index`设置为服务的每个实例都是唯一的。

## [](#customizing-the-message-broker)[6.自定义消息代理](#customizing-the-message-broker)

Spring 云总线使用[Spring Cloud Stream](https://cloud.spring.io/spring-cloud-stream)来广播消息。因此,要使消息流起来,你只需要在 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` 是要用作外部中间件的主题的名称)。通常情况下,默认值就足够了。

要了解有关如何自定义 Message Broker 设置的更多信息,请参阅 Spring Cloud Stream 文档。

## [](#tracing-bus-events)[7.追踪总线事件](#tracing-bus-events)

可以通过设置 ` 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”添加<gtr="72"/>类型和<gtr="73"/>类型到你的应用程序(并启用跟踪)。或者,你可以利用`TraceRepository`并从那里挖掘数据。

|   |任何总线应用程序都可以跟踪 ACK。然而,有时,在可以对数据执行更复杂的<br/>查询或将其转发给专门的跟踪服务的中心服务中执行此操作是很有用的。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## [](#broadcasting-your-own-events)[8.播放自己的活动](#broadcasting-your-own-events)

总线可以承载`RemoteApplicationEvent`类型的任何事件。默认传输是 JSON,反序列化器需要提前知道将使用哪些类型。要注册一个新类型,你必须将其放入“org.springframework.cloud.bus.event”的子包中。

要自定义事件名,你可以在自定义类上使用`@JsonTypeName`,也可以使用默认策略,即使用类的简单名称。

|   |生产者和消费者都需要访问类定义。|
|---|-----------------------------------------------------------------------|

### [](#registering-events-in-custom-packages)[8.1.在自定义包中注册事件](#registering-events-in-custom-packages)

如果不能或不想使用`org.springframework.cloud.bus.event`的子包处理自定义事件,则必须使用`@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`上使用`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`的所有示例都是等效的,因为通过在 `@remoteApplicationEventScan’上显式指定包,可以注册 `com.acme’包。

|   |你可以指定要扫描的多个基包。|
|---|-----------------------------------------------|

## [](#configuration-properties)[9.配置属性](#configuration-properties)

要查看所有与总线相关的配置属性的列表,请检查[附录页](appendix.html)