[Spring Cloud] 6 Spring Cloud Bus

为什么80%的码农都做不了架构师?>>>   hot3.png

Spring Cloud Bus

总线

Spring Cloud Bus 通过一个轻量级的消息代理把分布式系统中各个节点串联起来。 这样就可以方便的进行广播或者其他管理操作。

其核心概念就类似在一个Spring Boot Actuator的分布式实现之上,并在此基础之上提供应用之间互相通讯的能力。

通讯以AMQP协议为基础,并在此基础之上提供路标跟踪。

6.1 Quick Start

Spring Cloud Bus是通过Spring Boot自动配置机制来加载的,所以只要在classpath中有相应的jar就行。 Spring Cloud提供相应的依赖管理,所以使用时,只需要添加:spring-cloud-starter-bus-amqp或者spring-cloud-starter-bus-kafka就行了。 如果仅是本地运行,那依赖引入后,只需要配置好消息代理(RabbitMQ 或者 Kafka)就行。如果是使用Spring Cloud Connectors远程运行,或者是需要按Spring Boot方式配置密码,则需要手工加入一些配置。比如,使用Rabbit时:

application.yml

spring:
  rabbitmq:
    host: mybroker.com
    port: 5672
    username: user
    password: secret

总线支持消息发送到所有已监听的节点,或者某个特定服务的所有节点。以后会加入更多的选择策略。 同样的,总线也提供了一些HTTP接口:/bus/*。当前版本有两个接口实现,第一个:/bus/env,发送键值对去更新每个节点的Spring Environment;第二个:/bus/refresh,重新加载每一个应用的配置信息,类似于/refresh

注意: 由于都是最常用的,Bus的starter会自动带上Rabbit和Kafka启动器,但是Spring Cloud Stream是很灵活的,可以很方便的整合到spring-cloud-bus

6.2 Addressing an Instance

HTTP接口接受一个“destination”参数作为一个ApplicationContext的ID,例如:/bus/refresh?destination=customers:9000。如果这个ID的实例在总线上,则会被处理,否则忽略。 Spring Boot可以通过ContextIdApplicationContextInitializer设置ID,默认ID是由spring.application.name,配置的分隔符(:)以及server.port三部分拼接而成。

6.3 Addressing all instances of a service

"destination"参数会被Spring的PathMatcher来决定实例是否需要处理此消息。在上面的例子中,/bus/refresh?destination=customers:**将会让所有"customers"服务的实例处理,而不按ApplicationContext的ID来处理。

6.4 Application Context ID must be unique

总线会避免让一个事件重复被处理,一个原始ApplicationEvent就像从队列中取出一样。 为了达到这个目的,发送事件时,会检查目标ApplicationContext的ID和当前ApplicationContext的ID。如果服务的多个实例拥有着相同的ApplicationContext ID,事件将不会被处理。本地机器上跑着的每一个服务,都会有一个不同的端口,所以默认ID也会不一样。 Cloud Foundry提供一个索引,来确保ApplicationContext的ID唯一,可以在服务的每一个实例设置spring.application.index。例如:在application.properties或者bootstrap.properties(使用配置服务时)中,设置spring.application.index=${INSTANCE_INDEX}

6.5 Customizing the Message Broker

Spring Cloud Bus 使用 Spring Cloud Stream来进行消息广播。Bus提供了方便的starter来适配AMQP(RabbitMQ)和Kafka(spring-cloud-starter-bus-[amqp,kafka])。

通常来说Spring Cloud Stream 依靠Spring Boot 的自动配置机制来进行集成,因此,对于AMQP代理的地址可以通过spring.rabbitmq.*等配置项进行设置。Spring Cloud Bus有一些自己的配置项在spring.cloud.bus.*中(例如:spring.cloud.bus.destination可以指定topic的名字)。一般用默认的就行了。

更多定制消息代理的设置,可以参考Spring Cloud Stream相关文档。

6.6 Tracing Bus Events

总线事件(都继承于RemoteApplicationEvent)是可被追踪的,只需要设置spring.cloud.bus.trace.enabled=true。配置后,可以在Spring Boot的TraceRepository(如果有的话)中看到每一个事件的发送以及每一个服务实例的确认信息。例如:调用/trace接口(Spring Boot Actuator)

{
  "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": "*:**"
  }
}

追踪信息展示了RefreshRemoteApplicationEventcustomers:9000发送,广播到所有服务,然后被customers:9000stores:8081接收到。

可以自己添加@EventListener来处理ack信号,对于应用来说,有两种事件类型:AckRemoteApplicationEventSentApplicationEvent。还可以直接获得TraceRepository并从中得到数据。

注意: 任何总线上的应用都可以追踪acks,对于中心服务来说,这样对于数据来说可以进行更复杂的查询。也可以转发到一个特定的追踪服务上。

6.7 Broadcasting Your Own Events

总线可以传输任何RemoteApplicationEvent类型,但是默认转换协议是JSON,并且反序列化需要知道使用时的目标类型。当需要注册一个新的事件类型时,可以参见org.springframework.cloud.bus.event包中的API。 自定义类型时可以通过@JsonTypeName来指定事件的名字,默认策略只需要制定class的简称就行。注意,事件消息的产生者和消费者都需要能够访问这个class。

6.7.1 Registering events in custom packages

如果不想使用org.springframework.cloud.bus.event包中的事件类型,而想要使用自定义事件类型,那必须使用@RemoteApplicationEventScan指定哪一个包来扫描RemoteApplicationEvent@RemoteApplicationEventScan会扫描子包。

例如:如果自定义了FooEvent事件:

package com.acme;

public class FooEvent extends RemoteApplicationEvent {
    ...
}

可以通过下面的方式来注册这个事件:

package com.acme;

@Configuration
@RemoteApplicationEventScan
public class BusConfiguration {
    ...
}

如果不指定包,则以@RemoteApplicationEventScan的当前包为默认值。在这个例子中,com.acme就是扫描BusConfiguration所在的包。

也可以通过这个@RemoteApplicationEventScanvalue,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包都会被扫描。 注意,你可以指定来扫描多个包。

转载于:https://my.oschina.net/roccn/blog/832059

你可能感兴趣的:(java,大数据,json)