12. 服务发现:Eureka 服务器

本节介绍如何设置 Eureka 服务器。

12.1 如何包含 Eureka 服务器

要在项目中包含 Eureka 服务器,请使用 group ID 为 org.springframework.cloud 和 artifact ID 为 spring-cloud-starter-netflix-eureka-server 的 starter。了解有关使用当前 Spring Cloud Release Train 构建系统设置的详细信息请参阅 Spring Cloud 项目页面。

[Note] Note

如果你的项目已经使用 Thymeleaf 作为模板引擎,则可能无法正确加载 Eureka 服务器的 Freemarker 模板。在这种情况下,需要手动配置模板加载器:

application.yml. 

spring:
  freemarker:
    template-loader-path: classpath:/templates/
    prefer-file-system-access: false

12.2 如何运行 Eureka 服务器

以下示例示例了最小的 Eureka 服务器:

@SpringBootApplication
@EnableEurekaServer
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

服务器有一个主页,在 /eureka/* 下有一个用于正常 eureka 功能的 UI 和 HTTP API 端点。

以下链接有一些 Eureka 背景阅读:flux capacitor 和 google 小组讨论。

[Tip] Tip

由于 Gradle 的依赖解析规则和缺少父 bom 功能,依赖于 spring-cloud-starter-netflix-eureka-server 可能会导致应用程序启动失败。要解决此问题,请添加 Spring Boot Gradle 插件并导入 Spring Cloud Starter 父 BOM,如下所示:

build.gradle. 

buildscript {
  dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-docs-version}")
  }
}

apply plugin: "spring-boot"

dependencyManagement {
  imports {
    mavenBom "org.springframework.cloud:spring-cloud-dependencies:{spring-cloud-version}"
  }
}

12.3 高可用性、区域和分区

Eureka 服务器没有后台存储,但是注册表中的服务实例都必须发送心跳以使其注册保持最新(这样可以在内存中完成)。客户端也有一个内存中的 Eureka 注册缓存(因此他们不必为每个对服务的请求都去注册表)。

默认情况下,每个 Eureka 服务器也是一个 Eureka 客户端,需要(至少一个)服务 URL 来定位对等机。如果你不提供它,服务将运行并工作,但它会在日志中充满关于无法向对等机注册的大量噪音。

有关区域和分区的客户端功能区支持的详细信息,请参阅下面的内容。

12.4  独立模式

两个缓存(客户端和服务器)和心跳的结合使得一个独立的 Eureka 服务器能够很好地抵御故障,只要有某种类型的监视器或弹性运行时(如 Cloud Foundry)使其保持活动状态。在独立模式下,你可能更喜欢关闭客户端行为,这样它就不会一直尝试并未能到达其对等端。以下示例展示如何关闭客户端行为:

application.yml (Standalone Eureka Server). 

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

请注意,serviceUrl 指向的主机与本地实例相同。

12.5 同伴意识

通过运行多个实例并要求它们彼此注册,Eureka 可以变得更具弹性和可用性。实际上,这是默认行为,因此要使其正常工作,只需向对等端添加一个有效的 serviceUrl,如下例所示:

application.yml (Two Peer Aware Eureka Servers). 

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: http://peer2/eureka/

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1/eureka/

在前面的示例中,我们有一个 YAML 文件,可以通过在不同的 Spring 配置组中运行它来在两个主机(peer1 和 peer2)上运行同一个服务器。通过操纵 /etc/hosts 解析主机名,可以使用此配置测试单个主机上的对等意识(在生产环境中这样做没有太大价值)。事实上,如果你在一台知道自己主机名的机器上运行(在默认情况下,它是通过使用 java.net.InetAddress),则不需要 eureka.instance.hostname。

你可以向一个系统添加多个对等点,只要它们都通过至少一个边缘彼此连接,它们就可以在彼此之间同步注册。如果对等点是物理上分开的(在一个数据中心内或在多个数据中心之间),那么系统原则上可以经受 “split-brain” 类型的故障。你可以向一个系统中添加多个对等点,只要它们都直接连接在一起,它们就可以在彼此之间同步注册。

application.yml (Three Peer Aware Eureka Servers). 

eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1/eureka/,http://peer2/eureka/,http://peer3/eureka/

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2

---
spring:
  profiles: peer3
eureka:
  instance:
    hostname: peer3

12.6 何时首选 IP 地址

在某些情况下,Eureka 最好公布服务的 IP 地址,而不是主机名。将 eureka.instance.preferIpAddress 设置为 true,当应用程序使用 eureka 注册时,它使用其 IP 地址而不是其主机名。

[Tip] Tip

如果主机名不能用 Java 来确定,那么 IP 地址就被发送到 Eureka。唯一明确的设置主机名的方法是设置 eureka.instance.hostname 属性。你可以使用环境变量  —  在运行时设置主机名,例如 eureka.instance.hostname=${HOST_NAME}。

12.7 保护 Eureka 服务器

你可以通过 spring-boot-starter-security 将 Spring Security 添加到服务器的类路径来保护你的 Eureka 服务器。默认情况下,当 Spring Security 在类路径上时,它将要求在向应用程序发送每个请求时发送一个有效的 CSRF 令牌。Eureka 客户端通常不会拥有有效的跨站点请求伪造(CSRF)令牌,你需要禁用 /eureka/** 端点的此要求。例如:

@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}

有关 CSRF 的更多信息,请参阅 Spring Security 文档。

在 Spring Cloud Samples repo 中可以找到一个 Eureka 服务器的演示。

12.8 JDK 11 支持

Eureka 服务器所依赖的 JAXB 模块在 JDK 11 中被删除。如果你打算在运行 Eureka 服务器时使用JDK 11,则必须在 POM 或 Gradle 文件中包含这些依赖项。

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.3.0</version>
</dependency>