java什么是服务治理平台_Java | Spring Cloud 是如何实现服务治理的

Spring Cloud 是如何实现服务治理的

Table of Contents

建议提前阅读

Spring Cloud Commons 之服务治理浅析

Spring 在设计的时候,通常会考虑方便扩展和消除样板代码,在 Spring Clond 同样存在这样的设计。

在 Spring Cloud 体系中,Spring Cloud Commons 是最重要的一个项目,其中定义了服务注册、服务发现、复杂均衡相关的接口以及一些公共组件,通过看这个项目,我们可以简单的理解一下 Spring Cloud 注册发现的核心流程。

Spring Clond Commons 项目中提供了如下的项目结构(在这里省略了部分代码文件和结构)

└── src

├── main

│ ├── java

│ │ └── org

│ │ └── springframework

│ │ └── cloud

│ │ ├── client

│ │ │ ├── DefaultServiceInstance.java

│ │ │ ├── ServiceInstance.java Spring Cloud 对服务实例信息的定义

│ │ │ ├── discovery 服务发现相关

│ │ │ │ ├── DiscoveryClient.java

│ │ │ │ ├── EnableDiscoveryClient.java

│ │ │ │ ├── EnableDiscoveryClientImportSelector.java

│ │ │ │ ├── ManagementServerPortUtils.java

│ │ │ │ ├── ReactiveDiscoveryClient.java

│ │ │ │ ├── composite

│ │ │ │ │ ├── CompositeDiscoveryClient.java

│ │ │ │ │ ├── CompositeDiscoveryClientAutoConfiguration.java

│ │ │ │ │ └── reactive

│ │ │ │ │ ├── ReactiveCompositeDiscoveryClient.java

│ │ │ │ │ └── ReactiveCompositeDiscoveryClientAutoConfiguration.java

│ │ │ │ ├── health 健康检查相关

│ │ │ │ ├── DiscoveryClientHealthIndicator.java

│ │ │ │ ├── DiscoveryClientHealthIndicatorProperties.java

│ │ │ │ ├── DiscoveryCompositeHealthContributor.java

│ │ │ │ ├── DiscoveryHealthIndicator.java

│ │ │ │ └── reactive

│ │ │ │ ├── ReactiveDiscoveryClientHealthIndicator.java

│ │ │ │ ├── ReactiveDiscoveryCompositeHealthContributor.java

│ │ │ │ └── ReactiveDiscoveryHealthIndicator.java

│ │ │ ├── loadbalancer 这下面是负载均衡相关逻辑

│ │ │ └── serviceregistry 服务注册相关

│ │ │ ├── AbstractAutoServiceRegistration.java

│ │ │ ├── AutoServiceRegistration.java

│ │ │ ├── AutoServiceRegistrationAutoConfiguration.java

│ │ │ ├── AutoServiceRegistrationConfiguration.java

│ │ │ ├── AutoServiceRegistrationProperties.java

│ │ │ ├── Registration.java

│ │ │ ├── ServiceRegistry.java

│ │ │ ├── ServiceRegistryAutoConfiguration.java

│ │ ├── commons

│ │ ├── httpclient http 工厂类,在配置中可以选择使用 Apache Http 还是 OKHttp

│ │ │ ├── ApacheHttpClientFactory.java

│ │ │ └── OkHttpClientFactory.java

│ │ └── util

│ │ ├── IdUtils.java 通过这工具类来生成实例 id

│ │ └── InetUtils.java Spring Cloud 就是通过这个工具类是获取服务项目的 ip 地址的

│ └── resources

│ └── META-INF

│ ├── additional-spring-configuration-metadata.json

│ └── spring.factories

└── test

├── java 测试相关代码

在项目结构中可以看出各个部分对应的源码,在服务治理中,首先是服务信息 ServiceInstance , 其中包括

服务名 ServiceId 这个就是我们类似的 xxx-server (spring.application.name)

服务实例唯一标识符 InstanceId

host

port

一些扩展信息 metadata, 这个主要用来提供给三方实现增加以下扩展信息

// 为了缩短篇幅,删除了一些注释

public interface ServiceInstance {

default String getInstanceId() {

return null;

}

String getServiceId();

String getHost();

int getPort();

boolean isSecure();

URI getUri();

Map getMetadata();

default String getScheme() {

return null;

}

}

服务注册

Registration 是 Spring Cloud 提供的一个注册实现

public interface Registration extends ServiceInstance {

// 这里面是真没有代码

}

服务注册的实际接口是 ServiceRegistry

public interface ServiceRegistry {

/**

* Registers the registration. A registration typically has information about an

* instance, such as its hostname and port.

* @param registration registration meta data

*/

void register(R registration);

/**

* Deregisters the registration.

* @param registration registration meta data

*/

void deregister(R registration);

/**

* Closes the ServiceRegistry. This is a lifecycle method.

*/

void close();

/**

* Sets the status of the registration. The status values are determined by the

* individual implementations.

* @param registration The registration to update.

* @param status The status to set.

* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint

*/

void setStatus(R registration, String status);

/**

* Gets the status of a particular registration.

* @param registration The registration to query.

* @param The type of the status.

* @return The status of the registration.

* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint

*/

T getStatus(R registration);

}

通过实现 ServiceRegistry 即可完成一个简单服务注册功能

服务发现

在 discovery 下存在两个服务发现定义接口 DiscoveryClient 和 ReactiveDiscoveryClient

其提供了如下功能:

获取所有的服务名称

根据服务名称获取对应的服务实例列表

public interface DiscoveryClient extends Ordered {

/**

* Default order of the discovery client.

*/

int DEFAULT_ORDER = 0;

/**

* A human-readable description of the implementation, used in HealthIndicator.

* @return The description.

*/

String description();

/**

* Gets all ServiceInstances associated with a particular serviceId.

* @param serviceId The serviceId to query.

* @return A List of ServiceInstance.

*/

List getInstances(String serviceId);

/**

* @return All known service IDs.

*/

List getServices();

/**

* Default implementation for getting order of discovery clients.

* @return order

*/

@Override

default int getOrder() {

return DEFAULT_ORDER;

}

}

通过实现 DiscoveryClient 即可完成服务发现

健康检测

ReactiveDiscoveryClientHealthIndicator 提供了健康检测功能

从 DiscoveryClient 中获取所有的服务名列表

根据服务名列表获取对应的服务实例列表

对每个实例进行健康检测,如果响应成功则 UP 否则为 DOWN

public class ReactiveDiscoveryClientHealthIndicator

implements ReactiveDiscoveryHealthIndicator, Ordered, ApplicationListener> {

private final ReactiveDiscoveryClient discoveryClient;

private final DiscoveryClientHealthIndicatorProperties properties;

private final Log log = LogFactory.getLog(ReactiveDiscoveryClientHealthIndicator.class);

private AtomicBoolean discoveryInitialized = new AtomicBoolean(false);

private int order = Ordered.HIGHEST_PRECEDENCE;

public ReactiveDiscoveryClientHealthIndicator(ReactiveDiscoveryClient discoveryClient,

DiscoveryClientHealthIndicatorProperties properties) {

this.discoveryClient = discoveryClient;

this.properties = properties;

}

@Override

public void onApplicationEvent(InstanceRegisteredEvent> event) {

if (this.discoveryInitialized.compareAndSet(false, true)) {

this.log.debug("Discovery Client has been initialized");

}

}

@Override

public Mono health() {

if (this.discoveryInitialized.get()) {

return doHealthCheck();

}

else {

return Mono.just(

Health.status(new Status(Status.UNKNOWN.getCode(), "Discovery Client not initialized")).build());

}

}

private Mono doHealthCheck() {

// @formatter:off

return Mono.justOrEmpty(this.discoveryClient)

.flatMapMany(ReactiveDiscoveryClient::getServices)

.collectList()

.defaultIfEmpty(emptyList())

.map(services -> {

ReactiveDiscoveryClient client = this.discoveryClient;

String description = (this.properties.isIncludeDescription())

? client.description() : "";

return Health.status(new Status("UP", description))

.withDetail("services", services).build();

})

.onErrorResume(exception -> {

this.log.error("Error", exception);

return Mono.just(Health.down().withException(exception).build());

});

// @formatter:on

}

@Override

public String getName() {

return discoveryClient.description();

}

@Override

public int getOrder() {

return this.order;

}

public void setOrder(int order) {

this.order = order;

}

}

通过上面的接口定义和自带的健康检测逻辑可以看出做一个服务治理需要实现的最简单的逻辑

实现 ServiceRegistry 功能

实现 DiscoveryClient 功能

Spring Cloud Consul 实现

实现 ServiceRegistry 功能

在 Spring Cloud Consul 中,首先自定义了 Registration 的实现

其中 NewService 为 Consul 定义的一些服务实例信息

public class ConsulRegistration implements Registration {

private final NewService service;

private ConsulDiscoveryProperties properties;

public ConsulRegistration(NewService service, ConsulDiscoveryProperties properties) {

this.service = service;

this.properties = properties;

}

public NewService getService() {

return this.service;

}

protected ConsulDiscoveryProperties getProperties() {

return this.properties;

}

public String getInstanceId() {

return getService().getId();

}

public String getServiceId() {

return getService().getName();

}

@Override

public String getHost() {

return getService().getAddress();

}

@Override

public int getPort() {

return getService().getPort();

}

@Override

public boolean isSecure() {

return this.properties.getScheme().equalsIgnoreCase("https");

}

@Override

public URI getUri() {

return DefaultServiceInstance.getUri(this);

}

@Override

public Map getMetadata() {

return getService().getMeta();

}

}

NewService

其包含了服务的基本信息和 Consul 本身提供一些特有功能如:Tags、Check

// 删除了通用的 getter、setter、toString 方法

public class NewService {

@SerializedName("ID")

private String id;

@SerializedName("Name")

private String name;

@SerializedName("Tags")

private List tags;

@SerializedName("Address")

private String address;

@SerializedName("Meta")

private Map meta;

@SerializedName("Port")

private Integer port;

@SerializedName("EnableTagOverride")

private Boolean enableTagOverride;

@SerializedName("Check")

private NewService.Check check;

@SerializedName("Checks")

private List checks;

public NewService() {

}

public static class Check {

@SerializedName("Script")

private String script;

@SerializedName("DockerContainerID")

private String dockerContainerID;

@SerializedName("Shell")

private String shell;

@SerializedName("Interval")

private String interval;

@SerializedName("TTL")

private String ttl;

@SerializedName("HTTP")

private String http;

@SerializedName("Method")

private String method;

@SerializedName("Header")

private Map> header;

@SerializedName("TCP")

private String tcp;

@SerializedName("Timeout")

private String timeout;

@SerializedName("DeregisterCriticalServiceAfter")

private String deregisterCriticalServiceAfter;

@SerializedName("TLSSkipVerify")

private Boolean tlsSkipVerify;

@SerializedName("Status")

private String status;

@SerializedName("GRPC")

private String grpc;

@SerializedName("GRPCUseTLS")

private Boolean grpcUseTLS;

public Check() {

}

}

}

ConsulServiceRegistry 实现 ServiceRegistry

public class ConsulServiceRegistry implements ServiceRegistry {

private static Log log = LogFactory.getLog(ConsulServiceRegistry.class);

private final ConsulClient client;

private final ConsulDiscoveryProperties properties;

private final TtlScheduler ttlScheduler;

private final HeartbeatProperties heartbeatProperties;

public ConsulServiceRegistry(ConsulClient client, ConsulDiscoveryProperties properties, TtlScheduler ttlScheduler,

HeartbeatProperties heartbeatProperties) {

this.client = client;

this.properties = properties;

this.ttlScheduler = ttlScheduler;

this.heartbeatProperties = heartbeatProperties;

}

@Override

public void register(ConsulRegistration reg) {

log.info("Registering service with consul: " + reg.getService());

try {

// 同样是通过 consul 提供的 api 接口进行服务注册

this.client.agentServiceRegister(reg.getService(), this.properties.getAclToken());

NewService service = reg.getService();

if (this.heartbeatProperties.isEnabled() && this.ttlScheduler != null && service.getCheck() != null

&& service.getCheck().getTtl() != null) {

this.ttlScheduler.add(reg.getInstanceId());

}

}

catch (ConsulException e) {

if (this.properties.isFailFast()) {

log.error("Error registering service with consul: " + reg.getService(), e);

ReflectionUtils.rethrowRuntimeException(e);

}

log.warn("Failfast is false. Error registering service with consul: " + reg.getService(), e);

}

}

@Override

public void deregister(ConsulRegistration reg) {

if (this.ttlScheduler != null) {

this.ttlScheduler.remove(reg.getInstanceId());

}

if (log.isInfoEnabled()) {

log.info("Deregistering service with consul: " + reg.getInstanceId());

}

this.client.agentServiceDeregister(reg.getInstanceId(), this.properties.getAclToken());

}

@Override

public void close() {

}

@Override

public void setStatus(ConsulRegistration registration, String status) {

if (status.equalsIgnoreCase(OUT_OF_SERVICE.getCode())) {

this.client.agentServiceSetMaintenance(registration.getInstanceId(), true);

}

else if (status.equalsIgnoreCase(UP.getCode())) {

this.client.agentServiceSetMaintenance(registration.getInstanceId(), false);

}

else {

throw new IllegalArgumentException("Unknown status: " + status);

}

}

// 服务实例状态

@Override

public Object getStatus(ConsulRegistration registration) {

String serviceId = registration.getServiceId();

Response> response = this.client.getHealthChecksForService(serviceId,

HealthChecksForServiceRequest.newBuilder().setQueryParams(QueryParams.DEFAULT).build());

List checks = response.getValue();

for (Check check : checks) {

if (check.getServiceId().equals(registration.getInstanceId())) {

if (check.getName().equalsIgnoreCase("Service Maintenance Mode")) {

return OUT_OF_SERVICE.getCode();

}

}

}

return UP.getCode();

}

}

ConsulDiscoveryClient 实现 DiscoveryClient

在发现逻辑中也是通过 consul 提供的 api 接口进行查询

public class ConsulDiscoveryClient implements DiscoveryClient {

private final ConsulClient client;

private final ConsulDiscoveryProperties properties;

public ConsulDiscoveryClient(ConsulClient client, ConsulDiscoveryProperties properties) {

this.client = client;

this.properties = properties;

}

@Override

public String description() {

return "Spring Cloud Consul Discovery Client";

}

@Override

public List getInstances(final String serviceId) {

return getInstances(serviceId, new QueryParams(this.properties.getConsistencyMode()));

}

public List getInstances(final String serviceId, final QueryParams queryParams) {

List instances = new ArrayList<>();

addInstancesToList(instances, serviceId, queryParams);

return instances;

}

private void addInstancesToList(List instances, String serviceId, QueryParams queryParams) {

HealthServicesRequest.Builder requestBuilder = HealthServicesRequest.newBuilder()

.setPassing(this.properties.isQueryPassing()).setQueryParams(queryParams)

.setToken(this.properties.getAclToken());

String queryTag = this.properties.getQueryTagForService(serviceId);

if (queryTag != null) {

requestBuilder.setTag(queryTag);

}

HealthServicesRequest request = requestBuilder.build();

Response> services = this.client.getHealthServices(serviceId, request);

for (HealthService service : services.getValue()) {

instances.add(new ConsulServiceInstance(service, serviceId));

}

}

public List getAllInstances() {

List instances = new ArrayList<>();

Response>> services = this.client

.getCatalogServices(CatalogServicesRequest.newBuilder().setQueryParams(QueryParams.DEFAULT).build());

for (String serviceId : services.getValue().keySet()) {

addInstancesToList(instances, serviceId, QueryParams.DEFAULT);

}

return instances;

}

@Override

public List getServices() {

CatalogServicesRequest request = CatalogServicesRequest.newBuilder().setQueryParams(QueryParams.DEFAULT)

.setToken(this.properties.getAclToken()).build();

return new ArrayList<>(this.client.getCatalogServices(request).getValue().keySet());

}

@Override

public int getOrder() {

return this.properties.getOrder();

}

}

总结

简要的 Spring Cloud Consul 的服务治理逻辑大致如此,当然 Spring Cloud Consul 还要处理大量的细节,代码还是很多的

在 Spring Cloud 体系中 Consul 并不提供服务请求转发的功能,只是提供对服务信息的保存、查询、健康检测剔除功能

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值