Eureka
да Spring Netflix OSS
Основные компоненты обнаружения и регистрации служб находятся в Spring Cloud 2022.0.x
начало версии,Spring Netflix OSS
компоненты (например, Hystrix、Zuul
)Официально удалено。Spring Команда постепенно прекратила поддержку этих компонентов в пользу Spring Cloud другие решения, например Spring Cloud Gateway、Resilience4j
ждать. но Eureka
Он до сих пор поддерживается, что указывает на то, что он находится в разработке. Eureka
Регистрация и открытие по-прежнему имеют место в качестве услуг.Eureka Сервер: Являясь центром регистрации, он хранит регистрационную информацию всех услуг;
Eureka Клиент: поставщик услуг или потребитель через Eureka Server Зарегистрируйтесь или получите служебную информацию.
pom.xml
документ<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>eureka-server</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<properties>
<spring-cloud.version>2021.0.1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost # Eureka Server Имя хоста, по этому адресу будут зарегистрированы другие службы.
instance-id: ${spring.application.name}:${server.port} # Пример ID,Уникально идентифицирует услугу Пример
client:
register-with-eureka: true # давилл Eureka Server Зарегистрируйтесь как клиент регистрационного центра
fetch-registry: false # Eureka Server Не извлекайте реестр служб (предоставляйте только функцию регистрации служб)
service-url:
defaultZone: http://localhost:8761/eureka/ # Eureka Server Адрес, используемый для регистрации клиента
server:
enable-self-preservation: false # Включить режим самозащиты,предотвратить обслуживание Пример Удален из-за потери сердцебиения
eviction-interval-timer-in-ms: 60000 # Временной интервал очистки отказавших сервисов, в миллисекундах
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
pom.xml
документ<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>service-demo1</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<properties>
<spring-cloud.version>2021.0.1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 8081
spring:
application:
name: service-demo1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/ # Eureka Server Адрес, используемый для регистрации клиента
fetch-registry: true # да Нет от Eureka Server Извлеките реестр служб, поставщик услуг обычно настроен на true
register-with-eureka: true # давилл зарегистрировался сам Eureka Сервер, поставщик услуг должен быть настроен на true
registry-fetch-interval-seconds: 30 # Интервал извлечения реестра
instance:
hostname: localhost
instance-id: ${spring.application.name}:${server.port} # Пример ID,Уникально идентифицирует услугу Пример
prefer-ip-address: true # использовать IP Служба регистрации адресов, обычно устанавливается на true
lease-renewal-interval-in-seconds: 30 # интервал сердцебиения
lease-expiration-duration-in-seconds: 90 # Срок годности
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Ошибка com.netflix.discovery.AbstractDiscoveryClientOptionalArgs, которую не удалось найти. Решение: необходимо ввести Spring-boot-starter-web.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Eureka
Центр регистрации добавляет сертификациюДобавьте модуль Spring Security
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
application.yml
spring:
application:
name: eureka-security-server
security: # Конфигурация Spring Security Логин и пароль для входа
user:
name: admin
password: 123456
Добавить конфигурацию Java WebSecurityConfig
По умолчанию добавить Приложение вSpringSecurity требует добавления при каждом запросе вCSRF Доступ к токену возможен.
Клиент Eureka не будет зарегистрирован при регистрации. в, поэтому требуется путь Конфигурация/eureka/**, а CSRF не требуется. token。
package org.example.config;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/eureka/**");
super.configure(http);
}
}
Создайте кластер Eureka для достижения высокой доступности.
Создайте кластер Eureka для достижения высокой доступности.
,С одной стороны, кластеры могут обеспечить высокую доступность.,С другой стороны, он также может разделить нагрузку, связанную с регистрацией и обнаружением услуг.application.yml
Осуществить взаимную регистрацию# Конфигурация host документ
127.0.0.1 localhost1
127.0.0.1 localhost2
# eureka-server1
server:
port: 8761
eureka:
instance:
hostname: localhost1 # Eureka Server Имя хоста, по этому адресу будут зарегистрированы другие службы.
prefer-ip-address: false # использовать IP Служба регистрации адресов, обычно устанавливается на true
instance-id: ${spring.application.name}:${server.port} # Пример ID,Уникально идентифицирует услугу Пример
client:
register-with-eureka: true # Воля Eureka Server Зарегистрируйтесь как клиент регистрационного центра
fetch-registry: false # Eureka Server Не извлекайте реестр служб (предоставляйте только функцию регистрации служб)
service-url:
defaultZone: http://admin:123456@localhost2:8762/eureka/
# eureka-server2
server:
port: 8762
eureka:
instance:
hostname: localhost2 # Eureka Server Имя хоста, по этому адресу будут зарегистрированы другие службы.
prefer-ip-address: false # использовать IP Служба регистрации адресов, обычно устанавливается на true
instance-id: ${spring.application.name}:${server.port} # Пример ID,Уникально идентифицирует услугу Пример
client:
register-with-eureka: true # Воля Eureka Server Зарегистрируйтесь как клиент регистрационного центра
fetch-registry: false # Eureka Server Не извлекайте реестр служб (предоставляйте только функцию регистрации служб)
service-url:
defaultZone: http://admin:123456@localhost1:8761/eureka/
# Вышеуказанные два центра регистрации Осуществить взаимную регистрацию и изменить eureka-client Конфигурация
eureka:
client:
service-url:
defaultZone: http://admin:123456@localhost:8761/eureka/,http://admin:123456@localhost:8762/eureka/
Разные хосты
eureka
Низкоуровневое использование isThisMyUrl
Метод удаления дубликатов, если они получены host
Он будет рассматриваться как хост, будет дедуплицирован и не может быть реализован. кластера。 /**
* Checks if the given service url contains the current host which is trying
* to replicate. Only after the EIP binding is done the host has a chance to
* identify itself in the list of replica nodes and needs to take itself out
* of replication traffic.
*
* @param url the service url of the replica node that the check is made.
* @return true, if the url represents the current node which is trying to
* replicate, false otherwise.
*/
public boolean isThisMyUrl(String url) {
final String myUrlConfigured = serverConfig.getMyUrl();
if (myUrlConfigured != null) {
return myUrlConfigured.equals(url);
}
return isInstanceURL(url, applicationInfoManager.getInfo());
}
Eureka Client
После завершения запуска статус экземпляра изменится на UP
статус и попытайтесь зарегистрировать клиента. После успешной регистрации выполняются регулярные запросы подтверждения для поддержания статуса клиента. Если первая регистрация не удалась, последующие регулярные запросы возобновления подтверждения будут возвращены. 204 и повторите попытку регистрации.Eureka Client
существовать Отправить регистрацию、Сердцебиение и другие запросы,Пойду в Eureka Server
узел кластера serviceUrlList
Попробуйте один за другим. Если запрос удался, он больше не будет запрашивать другие узлы. Повторная попытка будет выполнена максимум 3 раза. Если более 3 раз, будет выдано исключение. # com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient#execute
@Override
protected <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor) {
List<EurekaEndpoint> candidateHosts = null;
int endpointIdx = 0;
// перед заказом попробуйте numberOfRetries Вы можете зарегистрировать центр Пример
for (int retry = 0; retry < numberOfRetries; retry++) {
EurekaHttpClient currentHttpClient = delegate.get();
EurekaEndpoint currentEndpoint = null;
if (currentHttpClient == null) {
if (candidateHosts == null) {
candidateHosts = getHostCandidates();
if (candidateHosts.isEmpty()) {
throw new TransportException("There is no known eureka server; cluster server list is empty");
}
}
if (endpointIdx >= candidateHosts.size()) {
throw new TransportException("Cannot execute request on any known server");
}
currentEndpoint = candidateHosts.get(endpointIdx++);
currentHttpClient = clientFactory.newClient(currentEndpoint);
}
try {
EurekaHttpResponse<R> response = requestExecutor.execute(currentHttpClient);
if (serverStatusEvaluator.accept(response.getStatusCode(), requestExecutor.getRequestType())) {
delegate.set(currentHttpClient);
if (retry > 0) {
logger.info("Request execution succeeded on retry #{}", retry);
}
return response;
}
logger.warn("Request execution failure with status code {}; retrying on another server if available", response.getStatusCode());
} catch (Exception e) {
logger.warn("Request execution failed with message: {}", e.getMessage()); // just log message as the underlying client should log the stacktrace
}
// Connection error or 5xx from the server that must be retried on another server
delegate.compareAndSet(currentHttpClient, null);
if (currentEndpoint != null) {
quarantineSet.add(currentEndpoint);
}
}
throw new TransportException("Retry limit reached; giving up on completing the request");
}
# org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient#register
@Override
public EurekaHttpResponse<Void> register(InstanceInfo info) {
String urlPath = serviceUrl + "apps/" + info.getAppName();
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.POST, new HttpEntity<>(info, headers),
Void.class);
return anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
}
service-url
Все адреса должны быть настроены насколько это возможно, а порядок должен быть произвольным.Eureka Client
Недействительное выселениеEureka Service
Он будет периодически просматривать Пример в реестре.,Узнайте, какие из них выходят за рамки срока аренды Примери Воля Удалить его из реестра。Если уже Включить режим самозащиты, затем прекратить выселение до восстановления сердцебиения, режим самозащитызакрытие。 # com.netflix.eureka.registry.AbstractInstanceRegistry#evict(long)
public void evict(long additionalLeaseMs) {
logger.debug("Running the evict task");
// суждениережим Самозащита, запускать ли: для предотвращения нештатных ситуаций, таких как перегородки сети или временные сбои в работе сети. Eureka в больших масштабах Воля Примерошибочно подумал, что срок годности истекиизгонять,Избегайте влияния на общую доступность системы.
if (!isLeaseExpirationEnabled()) {
logger.debug("DS: lease expiration is currently disabled.");
return;
}
// We collect first all expired items, to evict them in random order. For large eviction sets,
// if we do not that, we might wipe out whole apps before self preservation kicks in. By randomizing it,
// the impact should be evenly distributed across all applications.
List<Lease<InstanceInfo>> expiredLeases = new ArrayList<>();
for (Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry : registry.entrySet()) {
Map<String, Lease<InstanceInfo>> leaseMap = groupEntry.getValue();
if (leaseMap != null) {
for (Entry<String, Lease<InstanceInfo>> leaseEntry : leaseMap.entrySet()) {
Lease<InstanceInfo> lease = leaseEntry.getValue();
if (lease.isExpired(additionalLeaseMs) && lease.getHolder() != null) {
expiredLeases.add(lease);
}
}
}
}
// To compensate for GC pauses or drifting local time, we need to use current registry size as a base for
// triggering self-preservation. Without that we would wipe out full registry.
// Даже если закрытый режим самозащиты,Если не Воля renewalPercentThreshold установлен на 0 ,Пример Срок действия также будет истекать партиями.,Избегайте проблем с сетью, которые затрудняют восстановление служб.
int registrySize = (int) getLocalRegistrySize();
int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold());
int evictionLimit = registrySize - registrySizeThreshold;
int toEvict = Math.min(expiredLeases.size(), evictionLimit);
if (toEvict > 0) {
logger.info("Evicting {} items (expired={}, evictionLimit={})", toEvict, expiredLeases.size(), evictionLimit);
// 随机изгонять的方式Воля Истекший Пример的изгонять影响分布существоватьмежду различными приложениями,Предотвратите полное удаление определенного приложения.
Random random = new Random(System.currentTimeMillis());
for (int i = 0; i < toEvict; i++) {
// Pick a random item (Knuth shuffle algorithm)
int next = i + random.nextInt(expiredLeases.size() - i);
Collections.swap(expiredLeases, i, next);
Lease<InstanceInfo> lease = expiredLeases.get(i);
String appName = lease.getHolder().getAppName();
String id = lease.getHolder().getId();
EXPIRED.increment();
logger.warn("DS: Registry: expired lease for {}/{}", appName, id);
internalCancel(appName, id, false);
}
}
}
гипотеза 20 аренда, в том числе 10 Срок аренды истек.
Начинается первый раунд исполнения
int registrySize = 20;
int registrySizeThreshold = (int) (20 * 0.85) = 17;
int evictionLimit = 20 - 17 = 3;
int toEvict = Math.min(10, 3) = 3;
Первый раунд казни заканчивается, а остальные 17 аренда, в том числе 7 Срок аренды истек.
Начинается второй раунд исполнения
int registrySize = 17;
int registrySizeThreshold = (int) (17 * 0.85) = 14;
int evictionLimit = 17 - 14 = 3;
int toEvict = Math.min(7, 3) = 3;
Второй раунд казни заканчивается, и остается 14 аренда, в том числе 4 Срок аренды истек.
...и так далее,или Воля renewalPercentThreshold установлен на0 , но это не рекомендуется
Eureka
принадлежать AP Дизайн, центр регистрации полностью равноправный и независимый, а статус не полностью соответствует. Eureka Client
При запросе регистрации, продления или автономного режима для экземпляра центра регистрации экземпляр синхронизирует эту информацию с другими центрами регистрации в кластере. В качестве примера можно привести код регистрации: # com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#register
/**
* Registers the information about the {@link InstanceInfo} and replicates
* this information to all peer eureka nodes. If this is replication event
* from other replica nodes then it is not replicated.
*
* @param info
* the {@link InstanceInfo} to be registered and replicated.
* @param isReplication
* true if this is a replication event from other replica nodes,
* false otherwise.
*/
@Override
public void register(final InstanceInfo info, final boolean isReplication) {
int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
super.register(info, leaseDuration, isReplication);
// Синхронизировать с другими серверами в кластере
replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
}
# com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#replicateToPeers
/**
* Replicates all eureka actions to peer eureka nodes except for replication
* traffic to this node.
*
*/
private void replicateToPeers(Action action, String appName, String id,
InstanceInfo info /* optional */,
InstanceStatus newStatus /* optional */, boolean isReplication) {
Stopwatch tracer = action.getTimer().start();
try {
if (isReplication) {
numberOfReplicationsLastMin.increment();
}
// If it is a replication already, do not replicate again as this will create a poison replication
if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
return;
}
for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
// If the url represents this host, do not replicate to yourself.
if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
continue;
}
replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
}
} finally {
tracer.stop();
}
}
Избегайте массового оффлайна: когда количество сердцебиений внезапно падает,Прекратите удалять Пример слишком быстро.
Повышение доступности системы:существовать Дрожание сети или кратковременные проблемы с подключением Вниз,Гарантийное обслуживание в системе Примердержи как можно большесуществовать Проволока。
protected void updateRenewsPerMinThreshold() {
this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfClientsSendingRenews
* (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds())
* serverConfig.getRenewalPercentThreshold());
}
# Возьмите Пример выше в качестве примера
int(3 (Примерчисло) * (60.0 / 30(время продления))* 0.85) = 5
👋 привет, я Lorin Лорейн, один Java Разработчик бэкэнд-технологий!девиз:Technology has the power to make the world a better place.
🚀 Моя страсть к технологиям — это моя мотивация продолжать учиться и делиться ими. Мой блог — это место, посвященное экосистеме Java, серверной разработке и новейшим технологическим тенденциям.
🧠 Будучи энтузиастом серверных технологий Java, я не только с энтузиазмом изучаю новые возможности языка и глубину технологий, но также с энтузиазмом делюсь своими идеями и передовым опытом. Я верю, что обмен знаниями и сотрудничество с сообществом могут помочь нам расти вместе.
💡 В моем блоге вы найдете подробные статьи об основных концепциях Java, базовой технологии JVM, часто используемых платформах, таких как Spring и Mybatis, управлении базами данных, таких как MySQL, промежуточном программном обеспечении для обработки сообщений, таком как RabbitMQ и Rocketmq, оптимизации производительности и т. д. Я также поделюсь некоторыми советами по программированию и методами решения проблем, которые помогут вам лучше освоить программирование на Java.
🌐 Я поощряю взаимодействие и создание сообщества, поэтому, пожалуйста, оставляйте свои вопросы, предложения или запросы по темам и дайте мне знать, что вас интересует. Кроме того, я буду делиться последними новостями Интернета и технологий, чтобы вы всегда были в курсе последних событий в мире технологий. Я с нетерпением жду возможности вместе с вами двигаться вперед по пути технологий и исследовать безграничные возможности мира технологий.
📖 Следите за обновлениями моего блога и давайте вместе стремиться к техническому совершенству.