spring-cloud-eureka
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSpring Cloud Eureka - Quick Reference
Spring Cloud Eureka - 快速参考
Deep Knowledge: Usewith technology:mcp__documentation__fetch_docsfor comprehensive documentation.spring-cloud-eureka
深度知识:调用工具,指定技术为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.85yaml
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.85High Availability (Peer Replication)
高可用(节点间同步)
yaml
undefinedyaml
undefinedeureka-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/
undefinedserver:
port: 8762
eureka:
instance:
hostname: eureka2.mycompany.com
client:
service-url:
defaultZone: http://eureka1.mycompany.com:8761/eureka/,http://eureka3.mycompany.com:8763/eureka/
undefinedEureka 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-ayaml
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-aInstance Health
实例健康检查配置
yaml
eureka:
instance:
health-check-url-path: /actuator/health
status-page-url-path: /actuator/infoyaml
eureka:
instance:
health-check-url-path: /actuator/health
status-page-url-path: /actuator/infoService 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
undefinedyaml
undefinedService 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
undefinedbash
undefinedEureka Server Dashboard
Eureka Server 控制台
Apps registered
查询所有注册的服务
Specific app
查询指定服务
Specific instance
查询指定实例
Instance status
修改实例状态
Delete instance
删除实例
undefinedundefinedSecurity
安全配置
Secure Eureka Server
加固Eureka Server
yaml
undefinedyaml
undefinedapplication.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=trueyaml
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=trueKubernetes (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
最佳实践
| Do | Don't |
|---|---|
| Use prefer-ip-address in containers | Use hostname in dynamic environments |
| Configure HA with peer replication | Single Eureka server in production |
| Set proper lease intervals | Use default intervals in production |
| Use zone-aware routing | Ignore network topology |
| Enable self-preservation | Disable 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-Pattern | Problem | Solution |
|---|---|---|
| Single Eureka instance | Single point of failure | Deploy peer-aware cluster |
| No health checks | Unhealthy services listed | Enable health indicator |
| Wrong renewal interval | Late detection of down services | Tune heartbeat settings |
| Ignoring self-preservation | Services removed unexpectedly | Understand and tune |
| No secure registry | Unauthorized registrations | Add Spring Security |
| 反模式 | 问题 | 解决方案 |
|---|---|---|
| 单节点Eureka部署 | 单点故障 | 部署支持节点同步的集群 |
| 未配置健康检查 | 不健康的服务仍会被列入注册列表 | 开启健康检查指示器 |
| 心跳间隔不合理 | 服务宕机后发现不及时 | 调整心跳配置 |
| 关闭自我保护机制 | 服务被意外移除 | 理解机制后调整阈值 |
| 注册中心未做安全加固 | 存在未授权注册风险 | 接入Spring Security |
Quick Troubleshooting
快速排查
| Problem | Diagnostic | Fix |
|---|---|---|
| Service not registering | Check Eureka dashboard | Verify eureka.client.serviceUrl |
| Service listed as DOWN | Check health endpoint | Fix health indicator |
| Stale registrations | Check lease settings | Reduce renewal interval |
| Self-preservation mode | Check network | Tune or disable if appropriate |
| Cannot connect to peers | Check peer URLs | Verify cluster configuration |
| 问题 | 排查方向 | 解决方案 |
|---|---|---|
| 服务无法注册 | 查看Eureka控制台 | 校验eureka.client.serviceUrl配置 |
| 服务状态显示为DOWN | 检查健康检查端点 | 修复健康检查逻辑 |
| 注册信息过期 | 检查租约配置 | 缩短心跳间隔 |
| 触发自我保护模式 | 检查网络连通性 | 调整阈值或在合适场景下关闭 |
| 节点间无法同步 | 检查 peer 地址配置 | 校验集群配置 |