java什么是服务治理平台_Java | Spring Cloud 是如何实现服务治理的
Spring Cloud 是如何實現(xiàn)服務治理的
Table of Contents
建議提前閱讀
Spring Cloud Commons 之服務治理淺析
Spring 在設計的時候,通常會考慮方便擴展和消除樣板代碼,在 Spring Clond 同樣存在這樣的設計。
在 Spring Cloud 體系中,Spring Cloud Commons 是最重要的一個項目,其中定義了服務注冊、服務發(fā)現(xiàn)、復雜均衡相關的接口以及一些公共組件,通過看這個項目,我們可以簡單的理解一下 Spring Cloud 注冊發(fā)現(xiàn)的核心流程。
Spring Clond Commons 項目中提供了如下的項目結構(在這里省略了部分代碼文件和結構)
└── src
├── main
│ ├── java
│ │ └── org
│ │ └── springframework
│ │ └── cloud
│ │ ├── client
│ │ │ ├── DefaultServiceInstance.java
│ │ │ ├── ServiceInstance.java Spring Cloud 對服務實例信息的定義
│ │ │ ├── discovery 服務發(fā)現(xiàn)相關
│ │ │ │ ├── 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, 這個主要用來提供給三方實現(xiàn)增加以下擴展信息
// 為了縮短篇幅,刪除了一些注釋
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 提供的一個注冊實現(xiàn)
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);
}
通過實現(xiàn) ServiceRegistry 即可完成一個簡單服務注冊功能
服務發(fā)現(xiàn)
在 discovery 下存在兩個服務發(fā)現(xiàn)定義接口 DiscoveryClient 和 ReactiveDiscoveryClient
其提供了如下功能:
獲取所有的服務名稱
根據(jù)服務名稱獲取對應的服務實例列表
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;
}
}
通過實現(xiàn) DiscoveryClient 即可完成服務發(fā)現(xiàn)
健康檢測
ReactiveDiscoveryClientHealthIndicator 提供了健康檢測功能
從 DiscoveryClient 中獲取所有的服務名列表
根據(jù)服務名列表獲取對應的服務實例列表
對每個實例進行健康檢測,如果響應成功則 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;
}
}
通過上面的接口定義和自帶的健康檢測邏輯可以看出做一個服務治理需要實現(xiàn)的最簡單的邏輯
實現(xiàn) ServiceRegistry 功能
實現(xiàn) DiscoveryClient 功能
Spring Cloud Consul 實現(xiàn)
實現(xiàn) ServiceRegistry 功能
在 Spring Cloud Consul 中,首先自定義了 Registration 的實現(xiàn)
其中 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 實現(xiàn) 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);
}
}
// 服務實例狀態(tài)
@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 實現(xiàn) DiscoveryClient
在發(fā)現(xiàn)邏輯中也是通過 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 還要處理大量的細節(jié),代碼還是很多的
在 Spring Cloud 體系中 Consul 并不提供服務請求轉發(fā)的功能,只是提供對服務信息的保存、查詢、健康檢測剔除功能
參考
總結
以上是生活随笔為你收集整理的java什么是服务治理平台_Java | Spring Cloud 是如何实现服务治理的的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java高版本编译低版本运行_Java高
- 下一篇: java+@api_Java 常用的ap