существуетпредыдущая статьяПредставлено, как использовать компоненты обнаружения регистрации службы: Eureka, и приведены примеры использования. Исходя из этого, в этой статье будет объяснена внутренняя история реализации клиента Eureka в сочетании с подробностями углубленной реализации исходного кода, чтобы понять, почему. Клиенты должны сосредоточиться на следующем:
- Получить информацию о реестре с сервера Eureka
- Полная информация о вытягиваемом реестре
- Инкрементное извлечение информации реестра
- Таймер обновления кэша реестра и таймер продления аренды (пульс)
- Регистрация службы и регистрация службы по запросу
- Автономный режим экземпляра службы
Эта статья взята из книги, опубликованной автором«Продвинутая архитектура микросервисов Spring Cloud»
Структура клиента Эврика
В версии SpringCloud для Finchley вы можете зарегистрироваться как клиент Eureka без добавления каких-либо дополнительных аннотаций, просто добавьте в файл pomspring-cloud-starter-netflix-eureka-client
зависимость.
Чтобы отслеживать работающий механизм Eureka, читатели могут включить режим отладки SpringBoot, чтобы просмотреть больше выходных журналов:
logging:
level:
org.springframework: DEBUG
Проверитьspring-cloud-netflix-eureka-client
изsrc/main/resource.META-INF/spring.factories
, чтобы увидеть, какие классы автоматической настройки есть у Eureka Client:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
За исключением классов автоматической настройки, связанных с центром настройки, можно найти три класса автоматической настройки, тесно связанные с Eureka Client:
- EurekaClientAutoConfiguration
- RibbonEurekaAutoConfiguration
- EurekaDiscoveryClientConfiguration
Далее мы проанализируем эти классы, чтобы увидеть, какую начальную настройку должен выполнить обычный клиент Eureka.
EurekaClientAutoConfiguration
Класс автоматической настройки Eureka Client отвечает за настройку и инициализацию ключевых бинов в EurekaClient.Ниже приводится введение и функции наиболее важных бинов в нем.
EurekaClientConfig
Предоставляет информацию о конфигурации, необходимую клиенту Eureka для регистрации на сервере Eureka, а SpringCloud предоставляет для него класс конфигурации по умолчанию.EurekaClientConfigBean
, может иметь префикс в файле конфигурацииeureka.client
+ имя свойства для переопределения.
ApplicationInfoManager
Этот класс управляет информационным классом экземпляра службы.InstanceInfo
, который включает информацию, требуемую реестром на сервере Eureka, представляющую данные, отправленные каждым клиентом Eureka в реестр для обнаружения службы. Также управляет информацией о конфигурации экземпляраEurekaInstanceConfig
, SpringCloud предоставляетEurekaInstanceConfigBean
Класс конфигурации для конфигурации по умолчанию также можно настроить в файле конфигурации.application.yml
прошедшийeureka.instance
+ Имя свойства для пользовательской конфигурации.
EurekaInstanceConfigBean
наследоватьEurekaInstanceConfig
Интерфейс — это соответствующая информация о самом экземпляре службы, которую клиент Eureka должен предоставить для регистрации на сервере. Он в основном используется для обнаружения службы:
Обычно эта информация находится в конфигурационном файлеeureka.instance
Под префиксом SpringCloud прошелEurekaInstanceConfigBean
Класс конфигурации предоставляет соответствующую конфигурацию по умолчанию. Ниже приведены некоторые из дополнительных ключевых атрибутов, эта информация будет зарегистрирована в реестре.
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware {
// 服务实例的应用名
private String appname;
// 服务实例的Id,通常和appname共同唯一标记一个服务实例
private String instanceId;
// 自定义添加的元数据,由用户使用以适配扩展业务需求
private Map<String, String> metadataMap;
// 如果服务实例部署在AWS上,该类将持有服务实例部署所在的数据中心的准确信息
private DataCenterInfo dataCenterInfo;
// 服务实例的Ip地址
private String ipAddress;
// 服务实例主页地址
private String homePageUrl;
// 服务实例健康检查地址
private String healthCheckUrlPath;
// 服务实例的状态地址
private String statusPageUrlPath
.....
}
DiscoveryClient
Это интерфейс верхнего уровня, определенный SpringCloud для обнаружения сервисов. В Netflix Eureka или консуле есть соответствующие конкретные классы реализации. Предоставляются следующие методы:
public interface DiscoveryClient {
// 获取实现类的描述
String description();
// 通过服务Id获取服务实例的信息
List<ServiceInstance> getInstances(String serviceId);
// 获取所有的服务实例的Id
List<String> getServices();
}
Соответствующая схема структуры класса его реализации в Eureka:
EurekaDiscoveryClient
наследоватьDiscoveryClient
, но глядя наEurekaDiscoveryClient
в коде вы обнаружите, что это делается путем объединения классаEurekaClient
Реализовать функции интерфейса следующим образомgetInstance
интерфейс:
@Override
public List<ServiceInstance> getInstances(String serviceId) {
List<InstanceInfo> infos = this.eurekaClient.getInstancesByVipAddress(serviceId,false);
List<ServiceInstance> instances = new ArrayList<>();
for (InstanceInfo info : infos) {
instances.add(new EurekaServiceInstance(info));
}
return instances;
}
EurekaClient
Отcom.netflix.discovery
пакет, его реализация по умолчаниюcom.netflix.discovery.DiscoveryClient
, который относится к исходному коду eureka-client, который обеспечивает множество ключевых функций, таких как регистрация Eureka Client на сервере, продление аренды, переход в автономный режим и получение информации реестра на сервере. SpringCloud вызывает метод обнаружения сервисов в Eureka комбинированно, примерноEurekaClient
Подробный анализ кода будет представлен в основном коде клиента. подходитьspring-cloud
, пружина обеспечиваетCloudEurekaClient
наследоватьcom.netflix.discovery.DiscoveryClient
, прикрываяonCacheRefreshed
предотвратить вspring-boot
Интерфейс вызывается, когда он не был инициализированNullPointException
.
Отношения между вышеуказанными классами конфигурации очень тесные, и между данными существует определенная связь, поэтому отношения между ними представлены ниже.
прежде всегоEurekaInstanceConfig
, код находится наEurekaClientAutoConfiguration
@Bean
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {
// 从配置文件中读取属性
String hostname = getProperty("eureka.instance.hostname");
boolean preferIpAddress = Boolean.parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
String ipAddress = getProperty("eureka.instance.ipAddress");
boolean isSecurePortEnabled = Boolean.parseBoolean(getProperty("eureka.instance.secure-port-enabled"));
String serverContextPath = env.getProperty("server.context-path", "/");
int serverPort = Integer.valueOf(env.getProperty("server.port", env.getProperty("port", "8080")));
Integer managementPort = env.getProperty("management.server.port", Integer.class);// nullable. should be wrapped into optional
String managementContextPath = env.getProperty("management.server.context-path");// nullable. should be wrapped into optional
Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port", Integer.class);//nullable
EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
// 设置非空属性
instance.setNonSecurePort(serverPort);
instance.setInstanceId(getDefaultInstanceId(env));
instance.setPreferIpAddress(preferIpAddress);
if (StringUtils.hasText(ipAddress)) {
instance.setIpAddress(ipAddress);
}
if(isSecurePortEnabled) {
instance.setSecurePort(serverPort);
}
if (StringUtils.hasText(hostname)) {
instance.setHostname(hostname);
}
String statusPageUrlPath = getProperty("eureka.instance.status-page-url-path");
String healthCheckUrlPath = getProperty("eureka.instance.health-check-url-path");
if (StringUtils.hasText(statusPageUrlPath)) {
instance.setStatusPageUrlPath(statusPageUrlPath);
}
if (StringUtils.hasText(healthCheckUrlPath)) {
instance.setHealthCheckUrlPath(healthCheckUrlPath);
}
ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort, serverContextPath, managementContextPath, managementPort);
.....
return instance;
}
Как видно из приведенного выше кода,EurekaInstanceConfig
Свойства в основном черезEurekaInstanceConfigBean
Реализация обеспечивает, а также пытается прочитать часть конфигурации из файла конфигурации, например.eureka.instance.hostname
,eureka.instance.status-page-url-path
,eureka.instance.health-check-url-path
Подождите, он представляет информацию, которая должна быть у экземпляра приложения, а затем эта часть информации будет инкапсулирована какInstanceInfo
, зарегистрирован на Eureka Server.
InstanceInfo
черезInstanceInfoFactory
(org.springframework.cloud.netflix.eureka) пакетEurekaInstanceConfig
создан со свойствами в , гдеInstanceInfo
Свойства в основномvolatile
, что обеспечивает непротиворечивость и атомарность этого типа информации в памяти.
Код находится наInstanceInfoFactory
.
public InstanceInfo create(EurekaInstanceConfig config) {
LeaseInfo.Builder leaseInfoBuilder = LeaseInfo.Builder.newBuilder()
.setRenewalIntervalInSecs(config.getLeaseRenewalIntervalInSeconds())
.setDurationInSecs(config.getLeaseExpirationDurationInSeconds());
// 创建服务实例的信息用来注册到eureka server上
InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder();
String namespace = config.getNamespace();
if (!namespace.endsWith(".")) {
namespace = namespace + ".";
}
builder.setNamespace(namespace).setAppName(config.getAppname())
.setInstanceId(config.getInstanceId())
.setAppGroupName(config.getAppGroupName())
.setDataCenterInfo(config.getDataCenterInfo())
.setIPAddr(config.getIpAddress()).setHostName(config.getHostName(false))
.setPort(config.getNonSecurePort())
.enablePort(InstanceInfo.PortType.UNSECURE,
config.isNonSecurePortEnabled())
.setSecurePort(config.getSecurePort())
.enablePort(InstanceInfo.PortType.SECURE, config.getSecurePortEnabled())
.setVIPAddress(config.getVirtualHostName())
.setSecureVIPAddress(config.getSecureVirtualHostName())
.setHomePageUrl(config.getHomePageUrlPath(), config.getHomePageUrl())
.setStatusPageUrl(config.getStatusPageUrlPath(),
config.getStatusPageUrl())
.setHealthCheckUrls(config.getHealthCheckUrlPath(),
config.getHealthCheckUrl(), config.getSecureHealthCheckUrl())
.setASGName(config.getASGName());
....
InstanceInfo instanceInfo = builder.build();
instanceInfo.setLeaseInfo(leaseInfoBuilder.build());
return instanceInfo;
}
с последующимApplicationInfoManager
, код находится наEurekaClientAutoConfiguration
.
@Bean
@ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT)
public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
return new ApplicationInfoManager(config, instanceInfo);
}
комбинируяEurekaInstanceConfig
а такжеInstanceInfo
созданныйApplicationInfoManager
, который принадлежит Application Information Manager.
@Bean
@ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
public EurekaClientConfigBean eurekaClientConfigBean() {
EurekaClientConfigBean client = new EurekaClientConfigBean();
if ("bootstrap".equals(propertyResolver.getProperty("spring.config.name"))) {
// We don't register during bootstrap by default, but there will be another
// chance later.
client.setRegisterWithEureka(false);
}
return client;
}
Как упоминалось ранее,EurekaClientConfig
Держите клиент Eureka, чтобы взаимодействовать с Eureka Server, аналогичнымserviceUrl
(Адрес сервера),EurekaClient
пройти черезEurekaClientConfig
Информация о конфигурации и сервер Eureka для регистрации и обнаружения служб.
Ну наконец тоEurekaClient
,пройти черезApplicationInfoManager
а такжеEurekaClientConfig
Создание комбинации, т.е.EurekaClient
В то же время информация об экземпляре службы Клиента хранится для обнаружения службы, а конфигурация, зарегистрированная на сервере EUREKA, используется для регистрации службы.
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config){
return new CloudEurekaClient(manager, config, this.optionalArgs, this.context);
}
Общая структура классов выглядит следующим образом
ЭврикаРегистрация, ЭврикаСервисРеестри, ЭврикаАвтоСервисРегистрацияЭто связанный класс, добавленный Spring Cloud для адаптации Eureka для регистрации службы в реестре служб.Давайте сначала рассмотрим структуру связанного класса.
Registration
наследоватьServiceInstance
, представляет экземпляр службы, зарегистрированный в системе обнаружения служб, и должен содержать такую информацию, как имя хоста, порт и т. д.Registration
даServiceInstance
класс фасада
public interface ServiceInstance {
//获取服务实例的serviceId
String getServiceId();
//获取服务实例的hostname
String getHost();
//获取服务实例的端口号
int getPort();
boolean isSecure();
//获取服务实例的uri地址
URI getUri();
//获取服务实例的元数据key-value对
Map<String, String> getMetadata();
}
Соответствует Эврике,EurekaRegistration
ДостигнутоRegistration
, посмотри в нем код, только что скопировалEurekaInstanceConfigBean
информация о конфигурации в , при введенииEurekaClient
, который обеспечивает реализацию регистрации службы Eureka Client.
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, ObjectProvider<HealthCheckHandler> healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.with(healthCheckHandler)
.build();
}
ServiceRegistry
Он предоставляет соответствующий интерфейс для регистрации экземпляра службы в реестре службы:
public interface ServiceRegistry<R extends Registration> {
//注册服务实例,registration当中通常有关于服务实例的信息,例如hostname和port
void register(R registration);
//注销服务实例
void deregister(R registration);
//关闭ServiceRegistry,通常在服务关闭的时候被调用
void close();
//设置服务实例的状态
void setStatus(R registration, String status);
//获取服务实例的状态
<T> T getStatus(R registration);
}
из которых вEurekaServiceRegistry
Реализация регистрации и офлайн выглядит следующим образом:
@Override
public void register(EurekaRegistration reg) {
// 初始化EurekaRegistration中的EurekaClient,如果为null
maybeInitializeClient(reg);
// 修改服务的状态为UP
reg.getApplicationInfoManager()
.setInstanceStatus(reg.getInstanceConfig().getInitialStatus());
// 设置健康检查
reg.getHealthCheckHandler().ifAvailable(healthCheckHandler ->
reg.getEurekaClient().registerHealthCheck(healthCheckHandler));
}
private void maybeInitializeClient(EurekaRegistration reg) {
reg.getApplicationInfoManager().getInfo();
reg.getEurekaClient().getApplications();
}
@Override
public void deregister(EurekaRegistration reg) {
if (reg.getApplicationInfoManager().getInfo() != null) {
// 设置服务的状态为DOWN
reg.getApplicationInfoManager().setInstanceStatus(InstanceInfo.InstanceStatus.DOWN);
}
}
В приведенном выше коде видно, что регистрация и автономный режим службы изменяют только текущий статус службы.EurekaClient
Класс реализации интерфейса имеет специальныеInstanceStatus
Мониторинг изменения состояния, при изменении информации об экземпляре службы будут инициироваться различные события для обработки.
EurekaAutoServiceRegistration
, как видно из названия, это автоматическая регистрация экземпляров сервиса.Как видно из предыдущей диаграммы классов, этот класс наследуетSmartLifecycle
интерфейс, которыйorg.springframework.context
Соответствующие классы в пакете, описаниеEurekaAutoServiceRegistration
Классы управляются жизненным циклом Spring.
...
@EventListener(ServletWebServerInitializedEvent.class)
public void onApplicationEvent(ServletWebServerInitializedEvent event) {
int localPort = event.getWebServer().getPort();
if (this.port.get() == 0) {
log.info("Updating port to " + localPort);
this.port.compareAndSet(0, localPort);
start();
}
}
@EventListener(ContextClosedEvent.class)
public void onApplicationEvent(ContextClosedEvent event) {
if( event.getApplicationContext() == context ) {
stop();
}
}
В приведенном выше коде класс прослушиваетServletWebServerInitializedEvent
а такжеContextClosedEvent
Два события, вызываемые на этапе инициализации приложения.start()
и вызов фазы закрытия контекста приложенияstop()
, по сути, это автоматическая операция регистрации сервиса и офлайн при запуске и закрытии приложения соответственно.
EurekaAutoServiceRegistration
Регистрация службы и автономный режим напрямую называются методами в EurekaServiceRegistry.
@Override
public void start() {
// only set the port if the nonSecurePort or securePort is 0 and this.port != 0
if (this.port.get() != 0) {
if (this.registration.getNonSecurePort() == 0) {
this.registration.setNonSecurePort(this.port.get());
}
if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
this.registration.setSecurePort(this.port.get());
}
}
if (!this.running.get() && this.registration.getNonSecurePort() > 0) {
// 注册服务
this.serviceRegistry.register(this.registration);
this.context.publishEvent(
new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
this.running.set(true);
}
}
@Override
public void stop() {
// 服务下线
this.serviceRegistry.deregister(this.registration);
this.running.set(false);
}
EurekaDiscoveryClientConfiguration
EurekaDiscoveryClientConfiguration
Просто сделайте две вещи, мониторRefreshScopeRefreshedEvent
события и инъекцииEurekaHealthCheckHandler
Класс реализации интерфейса.
RefreshScopeRefreshedEvent
Событие обычно вызывается при обновлении компонента, управляемого пружиной, что означает, что конфигурация и параметры среды приложения могут измениться, поэтому необходимо перерегистрировать службу, чтобы предотвратить несоответствие информации об экземпляре службы в реестре местная информация.
@EventListener(RefreshScopeRefreshedEvent.class)
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
// 保证了一个刷新事件发生后client的重新注册
if(eurekaClient != null) {
eurekaClient.getApplications();
}
if (autoRegistration != null) {
// 重新注册防止本地信息与注册表中的信息不一致
this.autoRegistration.stop();
this.autoRegistration.start();
}
}
RibbonEurekaAutoConfiguration
Конфигурационный класс для настройки балансировки нагрузки в Eureka Конкретное содержание Ribbon будет объяснено в других главах, которые мы здесь пропустим.
Основной код клиента
Пакетная структура
Основной код находится наeureka-client
, модуль проектаeureka-client
, версия v1.8.7, которая является версией eureka, от которой зависит версия Finchley Spring Cloud.
Структура пакета выглядит следующим образом
Краткое введение пакета:
-
com.netflix.appinfo
: В основном о классе информации о конфигурации eureka-client, как упоминалось выше.EurekaInstanceConfig
,InstanceInfo
, который также содержит аналогичныеAmazonInfo
,DataCenterInfo
Интерфейсы, тесно связанные с адаптацией архитектуры в AWS, здесь подробно описываться не будут, и заинтересованные читатели могут разобраться сами. -
com.netflix.discovery
: в основном реализует функции обнаружения и регистрации служб Eureka-Client.-
com.netflix.discovery.converters
: в основном решает вопросы кодирования и декодирования передачи данных между службами Eureka и поддерживает JSON, XML и другие форматы. -
com.netflix.discovery.guice
:Google
изguice
Пакет конфигурации внедрения зависимостей, аналогичныйSpring
конфигурация. -
com.netflix.discovery.provider
: предоставленная реализация сериализации и десериализации запросов и ответов в Джерси, реализация по умолчаниюDefaultJerseyProvider
. -
com.netflix.discovery.providers
: В настоящее время толькоDefaultEurekaClientConfigProvider
,поставкаEurekaClientConfig
Заводской метод. -
com.netflix.discovery.shared
: Eureka Client совместно использует повторно используемые методы с Eureka Server.-
com.netflix.discovery.shared.dns
: преобразователь DNS. -
com.netflix.discovery.shared.resolver
: парсер конечной точки Euraka,EurekaEndpoint
Относится к конечной точке службы, обычно относится к адресу доступа сервера Eureka, реализация по умолчанию:DefaultEndpoint
,ClusterResolver
Разрешите настроенный адрес сервера Eureka дляEurekaEndpoint
, в котором используется шаблон проектирования делегатора.Схема классов выглядит следующим образом, и процесс обработки запроса делегирования очевиден. -
com.netflix.discovery.shared.transport
: клиент для HTTP-связи между клиентом Eureka и сервером Eureka, а также класс инкапсуляции для запроса и ответа на связь.
-
-
DiscoveryClient
DiscoveryClient
Можно сказать, что основной класс клиента Eureka, отвечающий за ключевую логику взаимодействия с сервером Eureka и имеет следующие функции:
- Зарегистрируйте экземпляр службы на Eureka Server;
- Обновите договор с Eureka Server;
- Отменить контракт с Eureka Server при отключении службы;
- Запросите список сервисов/экземпляров, зарегистрированных в Eureka Server.
DiscoverClient
Диаграмма основных классов выглядит следующим образом:
DiscoveryClient
Интерфейс верхнего уровняLookupService
, основная цель — обнаружить активные экземпляры службы.
public interface LookupService<T> {
//根据服务实例注册的appName来获取,获取一个封装有相同appName的服务实例信息的容器
Application getApplication(String appName);
//返回当前注册的所有的服务实例信息
Applications getApplications();
//根据服务实例的id获取
List<InstanceInfo> getInstancesById(String id);
//获取下一个可能的Eureka Server来处理当前对注册表信息的处理,一般是通过循环的方式来获取下一个Server
InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
}
Application
Список нескольких экземпляров, содержащих определенное приложение, можно понимать как информацию о кластере одной и той же службы, и все они висят под одним и тем же именем службы appName.InstanceInfo
Представляет экземпляр службы, часть кода выглядит следующим образом:
public class Application {
private static Random shuffleRandom = new Random();
//服务名
private String name;
@XStreamOmitField
private volatile boolean isDirty = false;
@XStreamImplicit
private final Set<InstanceInfo> instances;
private final AtomicReference<List<InstanceInfo>> shuffledInstances;
private final Map<String, InstanceInfo> instancesMap;
.....
}
Чтобы обеспечить атомарные операции и уникальность данных и предотвратить грязные данные,Application
средняя параInstanceInfo
Операции все синхронные операции, чувствуюApplication.addInstance
метод.
public void addInstance(InstanceInfo i) {
instancesMap.put(i.getId(), i);
synchronized (instances) {
instances.remove(i);
instances.add(i);
isDirty = true;
}
}
Синхронизируя блок кода, гарантируется, что только один поток изменяет экземпляры за раз, и обратите внимание, что instancesMap используетConcurrentHashMap
Реализация гарантирует атомарную работу, поэтому ее не нужно контролировать синхронизированными блоками кода.
Applications
Представляет информацию о коллекции зарегистрированных экземпляров службы в Eureka Server, в основном дляApplication
Большинство операций внутри также являются синхронными операциями.
EurekaClient
наследоватьLookupService
интерфейс, дляDiscoveryClient
Предоставляет интерфейс верхнего уровня в попытке облегчить переход от eureka 1.x к eureka 2.x, что объясняетEurekaClient
Этот интерфейс является относительно стабильным интерфейсом и будет сохранен даже на следующем крупном этапе.
EurekaCient
существуетLookupService
Благодаря расширению большего количества интерфейсов он предоставляет более богатые функции для получения экземпляров службы, в основном в том числе:
- Предоставляет различные способы получения
InstanceInfo
, например, по региону, адресу Eureka Server и т. д.; - Предоставляет данные для локальных клиентов (регион, зона доступности и т.д.), что тесно связано с AWS;
- Обеспечить регистрацию клиентов и приобретение процессоров проверки здоровья;
Удалите интерфейсы, связанные с запросами, и сосредоточьтесь наEurekaClient
Следующие два интерфейса в:
// 为Eureka Client注册健康检查处理器
// 一旦注册,客户端将通过调用新注册的健康检查处理器来对注册中instanceInfo
// 进行一个按需更新,随后按照eurekaclientconfig.getinstanceinforeplicationintervalseconds()
// 中配置的指定时间调用HealthCheckHandler
public void registerHealthCheck(HealthCheckHandler healthCheckHandler);
// 为eureka client注册一个EurekaEventListener(事件监听器)
// 一旦注册,当eureka client的内部状态发生改变的时候,将会调用EurekaEventListener.onEvent()
// 触发一定的事件。可以通过这种方式监听client的更新而非通过轮询的方式询问client
public void registerEventListener(EurekaEventListener eventListener);
Eureka Server обычно идентифицирует состояние экземпляра с помощью тактов. В Eureka Client есть задание на время, которое регулярно проходитHealthCheckHandler
Определить состояние текущего клиента.Если состояние клиента изменится, будет инициировано новое событие регистрации для синхронизации соответствующей информации об экземпляре службы в реестре Eureka Server.
public interface HealthCheckHandler {
InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus);
}
существуетspring-cloud-netflix-eureka-client
Интерфейс, реализующий это,EurekaHealthCheckHandler
, основная комбинацияspring-boot-actuator
серединаHealthAggregator
а такжеHealthIndicator
правильно понялspring-boot
Определение состояния приложения.
В основном это следующие состояния:
public enum InstanceStatus {
UP, // 可以接受服务请求
DOWN, // 无法发送流量-健康检查失败
STARTING, // 正在启动,无法发送流量
OUT_OF_SERVICE, // 服务关闭,不接受流量
UNKNOWN; // 未知状态
}
Шаблон события в Eureka, это очевидный шаблон наблюдателя, ниже представлена его диаграмма классов:
Регистрация и обнаружение клиентской службы
существуетDiscoveryClient
В коде есть специальные коды, реализующие функции регистрации и обнаружения сервисов. существуетDiscoveryClient
В конструкторе клиент Eureka будет выполнять такие операции, как извлечение информации из реестра с сервера Eureka и саморегистрация.DiscoveryClient
Конструктор выглядит следующим образом:
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config,
AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider)
ApplicationInfoManager
а такжеEurekaClientConfig
Как мы видели в предыдущем введении, один — это класс, который инкапсулирует информацию о конфигурации текущего экземпляра службы, а другой — это класс, который инкапсулирует информацию о конфигурации для взаимодействия между клиентом и сервером.AbstractDiscoveryClientOptionalArgs
а такжеBackupRegistry
не вводится
BackupRegistry
Код интерфейса выглядит следующим образом:
@ImplementedBy(NotImplementedRegistryImpl.class)
public interface BackupRegistry {
Applications fetchRegistry();
Applications fetchRegistry(String[] includeRemoteRegions);
}
Он действует как резервный реестр.Если клиент Eureka не может получить информацию о реестре с какого-либо сервера Eureka,BackupRegistry
будет вызываться для получения информации о реестре, но реализация по умолчаниюNotImplementedRegistryImpl
, то есть не реализовано.
public abstract class AbstractDiscoveryClientOptionalArgs<T> {
// 生成健康检查回调的工厂类,HealthCheckCallback已废弃
Provider<HealthCheckCallback> healthCheckCallbackProvider;
// 生成健康处理器的工厂类
Provider<HealthCheckHandler> healthCheckHandlerProvider;
// 向Eureka Server注册之前的预处理器
PreRegistrationHandler preRegistrationHandler;
// Jersey过滤器集合,Jersey1和Jersey2均可使用
Collection<T> additionalFilters;
// Jersey客户端,主要用于client与server之间的HTTP交互
EurekaJerseyClient eurekaJerseyClient;
// 生成Jersey客户端的工厂
TransportClientFactory transportClientFactory;
// 生成Jersey客户端的工厂的工厂
TransportClientFactories transportClientFactories;
// Eureka事件的监听器
private Set<EurekaEventListener> eventListeners;
....
}
AbstractDiscoveryClientOptionalArgs
используется для ввода некоторых необязательных параметров, а некоторыеjersey1
а такжеjersey2
универсальный фильтр,@Inject(optional = true)
Атрибут указывает на необязательность параметра
В методе построения игнорируйте большинство операций присваивания и постепенно поймите, что свойства в классе конфигурации будут влиять наDiscoveryClient
Какое влияние оказывает ваше поведение
if (config.shouldFetchRegistry()) {
this.registryStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRY_PREFIX + "lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
if (config.shouldRegisterWithEureka()) {
this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRATION_PREFIX + "lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
config.shouldFetchRegistry() (соответствующая конфигурацияeureka.client.fetch-register
), если true, это означает, что Eureka Client будет получать информацию из реестра от Eureka Server, config.shouldRegisterWithEureka (соответствующая конфигурацияeureka.client.register-with-eureka
), если это правда, клиент Eureka будет зарегистрирован на сервере Eureka.
Если обе вышеупомянутые конфигурации являются ложными, то инициализация обнаружения завершается напрямую, указывая на то, что клиент не выполняет ни регистрацию службы, ни обнаружение службы.
Затем инициализируйте пул потоков таймера на основе пула потоков.ScheduledExecutorService
, размер пула потоков равен 2, один используется для пульса, другой — для обновления кэша, а пулы потоков пульса и обновления кэша (ThreadPoolExecutor) инициализируются одновременно. оScheduledExecutorService
а такжеThreadPoolExecutor
Отношения между ними здесь не раскрываются.
scheduler = Executors.newScheduledThreadPool(2,
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-%d")
.setDaemon(true)
.build());
heartbeatExecutor = new ThreadPoolExecutor(
1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff
cacheRefreshExecutor = new ThreadPoolExecutor(
1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff
Затем инициализируйте клиент Jersy для HTTP-взаимодействия между Eureka Client и Eureka Server иAbstractDiscoveryClientOptionalArgs
Свойства в используются для построенияEurekaTransport
.
eurekaTransport = new EurekaTransport();
scheduleServerEndpointTask(eurekaTransport, args);
EurekaTransport
даDiscoveryClient
Внутренний класс, в котором инкапсулируетсяDiscoveryClient
Клиент из Джерси делает HTTP-вызовы на сервер Eureka:
private static final class EurekaTransport {
// Server endPoint解析器
private ClosableResolver bootstrapResolver;
// Jersy客户端生成工厂
private TransportClientFactory transportClientFactory;
// 注册客户端
private EurekaHttpClient registrationClient;
// 注册客户端生成工厂
private EurekaHttpClientFactory registrationClientFactory;
// 发现服务客户端
private EurekaHttpClient queryClient;
// 发现服务客户端生成工厂
private EurekaHttpClientFactory queryClientFactory;
....
}
Об АМСregion
Соответствующая конфигурация в пропущена.
Другие клиенты будут представлены в следующей статье, так что следите за обновлениями.
Узнайте больше об этой книге:адрес