spring-cloud-eureka

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Spring Cloud Eureka - Quick Reference

Spring Cloud Eureka - 快速参考

Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
spring-cloud-eureka
for comprehensive documentation.
深度知识:调用
mcp__documentation__fetch_docs
工具,指定技术为
spring-cloud-eureka
即可获取完整文档。

Eureka Server Setup

Eureka Server 搭建

Dependencies

依赖

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

Main Application

启动类

java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

application.yml (Server)

application.yml (服务端配置)

yaml
server:
  port: 8761

spring:
  application:
    name: eureka-server

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false  # Don't register itself
    fetch-registry: false         # Don't fetch registry
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enable-self-preservation: true
    eviction-interval-timer-in-ms: 5000
    renewal-percent-threshold: 0.85
yaml
server:
  port: 8761

spring:
  application:
    name: eureka-server

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false  # 不向注册中心注册自身
    fetch-registry: false         # 不拉取注册中心列表
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enable-self-preservation: true
    eviction-interval-timer-in-ms: 5000
    renewal-percent-threshold: 0.85

High Availability (Peer Replication)

高可用(节点间同步)

yaml
undefined
yaml
undefined

eureka-server-1

eureka-server-1 配置

server: port: 8761
eureka: instance: hostname: eureka1.mycompany.com client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka2.mycompany.com:8762/eureka/,http://eureka3.mycompany.com:8763/eureka/

server: port: 8761
eureka: instance: hostname: eureka1.mycompany.com client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka2.mycompany.com:8762/eureka/,http://eureka3.mycompany.com:8763/eureka/

eureka-server-2

eureka-server-2 配置

server: port: 8762
eureka: instance: hostname: eureka2.mycompany.com client: service-url: defaultZone: http://eureka1.mycompany.com:8761/eureka/,http://eureka3.mycompany.com:8763/eureka/
undefined
server: port: 8762
eureka: instance: hostname: eureka2.mycompany.com client: service-url: defaultZone: http://eureka1.mycompany.com:8761/eureka/,http://eureka3.mycompany.com:8763/eureka/
undefined

Eureka Client Setup

Eureka Client 搭建

Dependencies

依赖

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml (Client)

application.yml (客户端配置)

yaml
spring:
  application:
    name: user-service

server:
  port: 8081

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    registry-fetch-interval-seconds: 5
    initial-instance-info-replication-interval-seconds: 5
  instance:
    instance-id: ${spring.application.name}:${random.value}
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 10
    lease-expiration-duration-in-seconds: 30
    metadata-map:
      version: ${project.version:unknown}
      zone: zone-a
yaml
spring:
  application:
    name: user-service

server:
  port: 8081

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    registry-fetch-interval-seconds: 5
    initial-instance-info-replication-interval-seconds: 5
  instance:
    instance-id: ${spring.application.name}:${random.value}
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 10
    lease-expiration-duration-in-seconds: 30
    metadata-map:
      version: ${project.version:unknown}
      zone: zone-a

Instance Health

实例健康检查配置

yaml
eureka:
  instance:
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info
yaml
eureka:
  instance:
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info

Service Discovery

服务发现

Using DiscoveryClient

使用DiscoveryClient

java
@Service
@RequiredArgsConstructor
public class ServiceDiscoveryService {

    private final DiscoveryClient discoveryClient;

    public List<ServiceInstance> getInstances(String serviceName) {
        return discoveryClient.getInstances(serviceName);
    }

    public String getServiceUrl(String serviceName) {
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
        if (instances.isEmpty()) {
            throw new ServiceNotFoundException(serviceName);
        }
        // Simple random selection
        ServiceInstance instance = instances.get(
            ThreadLocalRandom.current().nextInt(instances.size()));
        return instance.getUri().toString();
    }

    public List<String> getAllServices() {
        return discoveryClient.getServices();
    }
}
java
@Service
@RequiredArgsConstructor
public class ServiceDiscoveryService {

    private final DiscoveryClient discoveryClient;

    public List<ServiceInstance> getInstances(String serviceName) {
        return discoveryClient.getInstances(serviceName);
    }

    public String getServiceUrl(String serviceName) {
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
        if (instances.isEmpty()) {
            throw new ServiceNotFoundException(serviceName);
        }
        // 简单随机负载策略
        ServiceInstance instance = instances.get(
            ThreadLocalRandom.current().nextInt(instances.size()));
        return instance.getUri().toString();
    }

    public List<String> getAllServices() {
        return discoveryClient.getServices();
    }
}

Using RestTemplate with LoadBalancer

配合负载均衡使用RestTemplate

java
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@Service
@RequiredArgsConstructor
public class UserClient {

    private final RestTemplate restTemplate;

    public User getUser(Long id) {
        // Uses service name instead of hostname
        return restTemplate.getForObject(
            "http://USER-SERVICE/api/users/{id}",
            User.class, id);
    }
}
java
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@Service
@RequiredArgsConstructor
public class UserClient {

    private final RestTemplate restTemplate;

    public User getUser(Long id) {
        // 使用服务名代替主机地址
        return restTemplate.getForObject(
            "http://USER-SERVICE/api/users/{id}",
            User.class, id);
    }
}

Using WebClient with LoadBalancer

配合负载均衡使用WebClient

java
@Configuration
public class WebClientConfig {

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

@Service
public class UserWebClient {

    private final WebClient webClient;

    public UserWebClient(WebClient.Builder builder) {
        this.webClient = builder.baseUrl("http://USER-SERVICE").build();
    }

    public Mono<User> getUser(Long id) {
        return webClient.get()
            .uri("/api/users/{id}", id)
            .retrieve()
            .bodyToMono(User.class);
    }
}
java
@Configuration
public class WebClientConfig {

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

@Service
public class UserWebClient {

    private final WebClient webClient;

    public UserWebClient(WebClient.Builder builder) {
        this.webClient = builder.baseUrl("http://USER-SERVICE").build();
    }

    public Mono<User> getUser(Long id) {
        return webClient.get()
            .uri("/api/users/{id}", id)
            .retrieve()
            .bodyToMono(User.class);
    }
}

Custom Load Balancer

自定义负载均衡器

java
@Configuration
public class CustomLoadBalancerConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory clientFactory) {

        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

        return new RoundRobinLoadBalancer(
            clientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
            name);
    }
}

// Apply to specific service
@LoadBalancerClient(name = "USER-SERVICE", configuration = CustomLoadBalancerConfig.class)
public class UserServiceConfig {
}
java
@Configuration
public class CustomLoadBalancerConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory clientFactory) {

        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

        return new RoundRobinLoadBalancer(
            clientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
            name);
    }
}

// 对指定服务生效
@LoadBalancerClient(name = "USER-SERVICE", configuration = CustomLoadBalancerConfig.class)
public class UserServiceConfig {
}

Zone-Aware Routing

可用区感知路由

yaml
undefined
yaml
undefined

Service in zone-a

部署在zone-a的服务配置

eureka: instance: metadata-map: zone: zone-a client: prefer-same-zone-eureka: true availability-zones: region1: zone-a,zone-b region: region1

```java
@Bean
public ServiceInstanceListSupplier zonePreferenceSupplier(
        ConfigurableApplicationContext context) {
    return ServiceInstanceListSupplier.builder()
        .withDiscoveryClient()
        .withZonePreference()
        .build(context);
}
eureka: instance: metadata-map: zone: zone-a client: prefer-same-zone-eureka: true availability-zones: region1: zone-a,zone-b region: region1

```java
@Bean
public ServiceInstanceListSupplier zonePreferenceSupplier(
        ConfigurableApplicationContext context) {
    return ServiceInstanceListSupplier.builder()
        .withDiscoveryClient()
        .withZonePreference()
        .build(context);
}

Health and Status

健康与状态

Custom Status

自定义健康状态

java
@Component
public class CustomHealthIndicator extends AbstractHealthIndicator {

    @Override
    protected void doHealthCheck(Health.Builder builder) {
        // Custom health logic
        if (isHealthy()) {
            builder.up().withDetail("custom", "OK");
        } else {
            builder.down().withDetail("custom", "FAILING");
        }
    }
}
java
@Component
public class CustomHealthIndicator extends AbstractHealthIndicator {

    @Override
    protected void doHealthCheck(Health.Builder builder) {
        // 自定义健康检查逻辑
        if (isHealthy()) {
            builder.up().withDetail("custom", "OK");
        } else {
            builder.down().withDetail("custom", "FAILING");
        }
    }
}

Force Status

强制修改实例状态

java
@Autowired
private ApplicationInfoManager applicationInfoManager;

public void setOutOfService() {
    applicationInfoManager.setInstanceStatus(InstanceStatus.OUT_OF_SERVICE);
}

public void setUp() {
    applicationInfoManager.setInstanceStatus(InstanceStatus.UP);
}
java
@Autowired
private ApplicationInfoManager applicationInfoManager;

public void setOutOfService() {
    applicationInfoManager.setInstanceStatus(InstanceStatus.OUT_OF_SERVICE);
}

public void setUp() {
    applicationInfoManager.setInstanceStatus(InstanceStatus.UP);
}

REST Endpoints

REST 接口

bash
undefined
bash
undefined

Eureka Server Dashboard

Eureka Server 控制台

Apps registered

查询所有注册的服务

Specific app

查询指定服务

Specific instance

查询指定实例

Instance status

修改实例状态

Delete instance

删除实例

Security

安全配置

Secure Eureka Server

加固Eureka Server

yaml
undefined
yaml
undefined

application.yml

application.yml

spring: security: user: name: eureka password: ${EUREKA_PASSWORD}

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.ignoringRequestMatchers("/eureka/**"))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/actuator/health").permitAll()
                .anyRequest().authenticated())
            .httpBasic(Customizer.withDefaults());
        return http.build();
    }
}
spring: security: user: name: eureka password: ${EUREKA_PASSWORD}

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.ignoringRequestMatchers("/eureka/**"))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/actuator/health").permitAll()
                .anyRequest().authenticated())
            .httpBasic(Customizer.withDefaults());
        return http.build();
    }
}

Secure Client Connection

客户端安全连接配置

yaml
eureka:
  client:
    service-url:
      defaultZone: http://eureka:${EUREKA_PASSWORD}@localhost:8761/eureka/
yaml
eureka:
  client:
    service-url:
      defaultZone: http://eureka:${EUREKA_PASSWORD}@localhost:8761/eureka/

Docker/Kubernetes

Docker/Kubernetes 适配

Docker Compose

Docker Compose 配置

yaml
services:
  eureka:
    image: myorg/eureka-server
    ports:
      - "8761:8761"
    environment:
      - EUREKA_INSTANCE_HOSTNAME=eureka
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka:8761/eureka/

  user-service:
    image: myorg/user-service
    environment:
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka:8761/eureka/
      - EUREKA_INSTANCE_PREFER_IP_ADDRESS=true
yaml
services:
  eureka:
    image: myorg/eureka-server
    ports:
      - "8761:8761"
    environment:
      - EUREKA_INSTANCE_HOSTNAME=eureka
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka:8761/eureka/

  user-service:
    image: myorg/user-service
    environment:
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka:8761/eureka/
      - EUREKA_INSTANCE_PREFER_IP_ADDRESS=true

Kubernetes (consider using K8s native discovery)

Kubernetes 配置(建议优先使用K8s原生服务发现)

yaml
eureka:
  instance:
    prefer-ip-address: true
    ip-address: ${POD_IP}
  client:
    service-url:
      defaultZone: http://eureka-server:8761/eureka/
yaml
eureka:
  instance:
    prefer-ip-address: true
    ip-address: ${POD_IP}
  client:
    service-url:
      defaultZone: http://eureka-server:8761/eureka/

Best Practices

最佳实践

DoDon't
Use prefer-ip-address in containersUse hostname in dynamic environments
Configure HA with peer replicationSingle Eureka server in production
Set proper lease intervalsUse default intervals in production
Use zone-aware routingIgnore network topology
Enable self-preservationDisable without understanding impact
推荐做法不推荐做法
容器环境下使用prefer-ip-address动态环境下使用hostname
配置节点同步实现高可用生产环境使用单节点Eureka
设置合理的租约间隔生产环境使用默认间隔
使用可用区感知路由忽略网络拓扑结构
开启自我保护机制未理解影响的前提下关闭自我保护

Production Checklist

生产环境检查清单

  • Eureka HA configured (3+ nodes)
  • Security enabled
  • Proper lease intervals set
  • Health check URL configured
  • prefer-ip-address for containers
  • Zone configuration if multi-DC
  • Self-preservation tuned
  • Monitoring/alerting setup
  • Client retry configured
  • Service instance metadata set
  • 配置了Eureka高可用集群(3个及以上节点)
  • 开启了安全认证
  • 设置了合理的租约间隔
  • 配置了健康检查地址
  • 容器环境开启了prefer-ip-address
  • 多可用区部署的情况下配置了可用区参数
  • 调整了自我保护机制阈值
  • 配置了监控告警
  • 客户端配置了重试机制
  • 设置了服务实例元数据

When NOT to Use This Skill

不适用该方案的场景

  • Kubernetes - Use K8s native service discovery
  • Consul preferred - Use Consul for service discovery
  • Simple setup - DNS-based discovery may suffice
  • Serverless - Not applicable
  • Kubernetes环境:请使用K8s原生服务发现
  • 优先使用Consul的场景:使用Consul实现服务发现
  • 简单部署场景:DNS-based服务发现即可满足需求
  • 无服务器场景:不适用

Anti-Patterns

反模式

Anti-PatternProblemSolution
Single Eureka instanceSingle point of failureDeploy peer-aware cluster
No health checksUnhealthy services listedEnable health indicator
Wrong renewal intervalLate detection of down servicesTune heartbeat settings
Ignoring self-preservationServices removed unexpectedlyUnderstand and tune
No secure registryUnauthorized registrationsAdd Spring Security
反模式问题解决方案
单节点Eureka部署单点故障部署支持节点同步的集群
未配置健康检查不健康的服务仍会被列入注册列表开启健康检查指示器
心跳间隔不合理服务宕机后发现不及时调整心跳配置
关闭自我保护机制服务被意外移除理解机制后调整阈值
注册中心未做安全加固存在未授权注册风险接入Spring Security

Quick Troubleshooting

快速排查

ProblemDiagnosticFix
Service not registeringCheck Eureka dashboardVerify eureka.client.serviceUrl
Service listed as DOWNCheck health endpointFix health indicator
Stale registrationsCheck lease settingsReduce renewal interval
Self-preservation modeCheck networkTune or disable if appropriate
Cannot connect to peersCheck peer URLsVerify cluster configuration
问题排查方向解决方案
服务无法注册查看Eureka控制台校验eureka.client.serviceUrl配置
服务状态显示为DOWN检查健康检查端点修复健康检查逻辑
注册信息过期检查租约配置缩短心跳间隔
触发自我保护模式检查网络连通性调整阈值或在合适场景下关闭
节点间无法同步检查 peer 地址配置校验集群配置

Reference Documentation

参考文档