服务发现:Eureka Server
本节介绍如何设置 Eureka 服务器。
如何包含 Eureka 服务器
要在项目中包含 Eureka Server,请使用组 ID 为 org.springframework.cloud 和工件 ID 为 spring-cloud-starter-netflix-eureka-server 的启动器。
如果你的项目已使用 Thymeleaf 作为其模板引擎,则可能无法正确加载 Eureka 服务器的 Freemarker 模板,在这种情况下,有必要手动配置模板加载器:
application.yml
spring:
freemarker:
template-loader-path: classpath:/templates/
prefer-file-system-access: false
如何运行 Eureka 服务器
以下示例显示了最小的 Eureka 服务器:
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
服务器有一个 UI 主页和在 /eureka/* 下用于正常 Eureka 功能的 HTTP API 端点。
以下链接有一些 Eureka 背景阅读:flux capacitor 和谷歌小组讨论。
由于 Gradle 的依赖关系解析规则和缺少父 bom 特性,依赖 spring-cloud-starter-netflix-eureka-server 可能导致应用程序启动失败,要解决此问题,请添加 Spring Boot Gradle 插件并导入 Spring cloud starter parent 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}”
}
}
高可用性、Zones 和 Regions
Eureka 服务器没有后端存储,但注册表中的服务实例都必须发送心跳以使其注册保持最新(因此可以在内存中完成),客户端还有一个 Eureka 注册的内存缓存(因此,它们不必对服务的每个请求都去注册表)。
默认情况下,每个 Eureka 服务器也是 Eureka 客户端,并且需要(至少一个)服务 URL 来定位对等体,如果你不提供该服务,该服务将运行并工作,但它会在你的日志中填充很多关于无法向对等方注册的噪音。
独立模式
两个缓存(客户端和服务器)的组合和心跳使独立的 Eureka 服务器能够很好地应对故障,只要有某种监视器或弹性运行时(例如 Cloud Foundry)保持活着。在独立模式下,你可能更愿意关闭客户端行为,以便它不会继续尝试并且无法访问其对等方,以下示例显示如何关闭客户端行为:
application.yml(独立 Eureka 服务器)。
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
请注意,serviceUrl 指向与本地实例相同的主机。
对等感知
通过运行多个实例并要求它们相互注册,可以使 Eureka 更具弹性和可用性,实际上,这是默认行为,因此你需要做的就是将有效的 serviceUrl 添加到对等体,如以下示例所示:
application.yml(两个 Peer Aware Eureka 服务器)。
—
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 来解析主机名来测试单个主机上的对等感知(在生产中执行此操作没有太大价值)。实际上,如果你在知道自己的主机名的计算机上运行,则不需要 eureka.instance.hostname(默认情况下,使用 java.net.InetAddress 查找它)。
你可以将多个对等体添加到一个系统中,并且只要它们通过至少一个边缘彼此连接,它们就会在它们之间同步注册,如果对等体在物理上是分开的(在数据中心内或在多个数据中心之间),那么系统原则上可以在“裂脑”类型故障中存活,你可以向一个系统添加多个对等体,只要它们彼此直接连接,它们就会在它们之间同步注册。
application.yml(三个 Peer Aware Eureka 服务器)。
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
何时首选 IP 地址
在某些情况下,Eureka 最好公布服务的 IP 地址而不是主机名,将 eureka.instance.preferIpAddress 设置为 true,当应用程序向 eureka 注册时,它使用其 IP 地址而不是其主机名。
如果 Java 无法确定主机名,则将 IP 地址发送给 Eureka,设置主机名的明确方法是只有设置 eureka.instance.hostname 属性,你可以使用环境变量在运行时设置主机名 — 例如,eureka.instance.hostname=${HOST_NAME}。
保护 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 存储库中找到 Eureka Server demo。
JDK 11 支持
在 JDK 11 中删除了 Eureka 服务器所依赖的 JAXB 模块,如果你打算在运行 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>