第四章 微服务注册与发现
服务发现概述
-
服务发现组件是一个非常关键的组件。
-
服务提供者,服务消费者,服务发现组件三者关系如下:
- 各个微服务在启动时,将自己的网络地址等信息注册到服务发现组件中,服务发现组件会存储这些信息。
- 服务消费者可从服务发现组件查询服务提供者的网络地址,并使用该地址调用服务提供者的接口。
- 各个微服务与服务发现组件使用一定机制(如:心跳)通信。服务发现组件若长时间无法与某个微服务实例通信,就会注销该实例。
- 微服务网络地址发生变更(如:实例增减或者IP端口发生变化等)时,会重新注册到服务发现组件。使用这种方式,服务消费者就无须人工修改提供者的网络地址了。
服务发现组件具备的功能
- 服务注册表:是服务发现组件的核心,它用来记录各个微服务的信息,如微服务的名称,IP,端口等。服务注册表提供查询API和管理API,查询API用于查询可用的微服务实例,管理API用于服务的注册和注销。
- 服务注册与服务发现:服务注册是指微服务在启动时,将自己的信息注册到服务发现组件上的过程。服务发现是指查询可用微服务列表及其网络地址的机制。
- 服务检查:服务发现组件使用一定机制定时检测已注册的服务,如发现某实例长时间无法访问,就会从服务注册表中移除该实例。
Eureka简介
-
Eureka是Netflix开源的服务发现组件,本身是一个基于REST的服务,它包含Server和Client两部分。Spring Cloud将其整合到了子项目Spring Cloud Netflix中,从而实现微服务的注册与发现。
-
Application Service服务提供者。
-
Application Client服务消费者。
-
Make Remote Call可以理解成调用RESTful API的行为。
-
us-east-1c,us-east-1d,us-east-1e等都是zone,它们都属于us-east-1这个region。
-
Eureka包含两个组件:Eureka Server和Eureka Client,功能如下:
- Eureka Server提供服务发现的能力,各个微服务启动时,会向Eureka Server注册自己的信息(如:IP,端口,微服务名称等),Eureka Server会存储这些信息。
- Eureka Client是一个Java客户端,用于简化与Eureka Server的交互。
- 微服务启动后,会周期性(默认30s)地向Eureka Server发送心跳以续约自己的“租期”。
- 如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将注销该实例(默认90s)
- 默认情况下,Eureka Server同时也是Eureka Client。多个Eureka Server实例互相之间通过复制的方式来实现服务注册表中数据的同步。
- Eureka Client会缓存服务表中的信息。这种方式有一定的优势——首先,微服务无须每次请求都查询Eureka Server,从而降低了Eureka Server的压力;其次,即使Eureka Server所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者并完成调用。
-
Eureka通过心跳检查,客户端缓存等机制,提高了系统的灵活性,可伸缩性和可用性。
编写Eureka Server
- 创建Maven工程如下
-
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ym.cloud</groupId> <artifactId>microservice-discovery-eureka</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <!-- 引入spring boot的依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <!-- 引入spring cloud的依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 添加spring-boot的maven插件 --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
@SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); } }
-
server: port: 8761 eureka: client: registerWithEureka: false # 是否将自己注册到Eureka Server,默认为false fetchRegistry: false # 是否从Eureka Server获取组测信息,默认为true serviceUrl: defaultZone: http://localhost:8761/eureka/ #设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址, #默认为http://localhost:8761/eureka;多个地址之间可使用,分隔。
-
启动项目并访问:http://localhost:8761
将微服务注册到Eureka Server上
- 创建maven工程如下。
-
<?xml version="1.0" encoding="UTF-8"?> <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"> <groupId>com.ym.cloud</groupId> <version>0.0.1-SNAPSHOT</version> <modelVersion>4.0.0</modelVersion> <artifactId>microservice-provider-user</artifactId> <packaging>jar</packaging> <!-- 引入Spring boot依赖--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jave.version>1.8</jave.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <!-- 引入spring cloud的依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 添加spring-boot的maven插件 --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
server: port: 8000 spring: application: name: microservice-provider-user #指定注册到Eureka Server上的应用名称 jpa: generate-ddl: false show-sql: true hibernate: ddl-auto: none datasource: #指定数据源 platform: h2; #指定数据库类型 schema: classpath:schema.sql #指定h2数据库的建表语句 data: classpath:data.sql #指定h2数据库的数据脚本 logging: # 配置日志级别,让hibernate打印出执行的SQL level: root: INFO org.hibernate: INFO org.hibernate.type.descriptor.sql.BasicBinder: TRACE org.hibernate.type.descriptor.sql.BasicExtractor: TRACE ## INFO info: app: name: @project.artifactId@ encoding: @project.build.sourceEncoding@ java: source: @java.version@ target: @java.version@ management: security: enabled: false eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true #true表示将自己的ip注册到Eureka Server,若不配置该属性或将其设置为false, #则表示注册微服务所在操作系统的hostname到Eureka Server
-
@SpringBootApplication public class ProviderUserApplication { public static void main(String[] args) { SpringApplication.run(ProviderUserApplication.class,args); } }
-
这样即可将用户微服务注册到Eureka Server上,同理将电影微服务也可以注册到Eureka Server上。
-
访问http://localhost:8761/
- 可以看到用户微服务,电影微服务已经被注册到Eureka Server上了。
提高
- 在Spring Cloud Edgware之前,要想将微服务注册到Eureka Server或者其他服务发现组件上,必须在启动类上添加**@EnableEurekaClient或@EnableDiscoveryClient**。
- 在Spring Cloud Edgware以及更高版本中,只需添加相关依赖,即可自动注册。
- 若不想将服务注册到Eureka Server,只需要设置spring.cloud.service-registry.auto-registration.enabled=false,或**@EnableDiscoveryClient(autoRegister = false)**即可。
Eureka Server的高可用
- 单节点Eureka Server并不适合线上生产环境。Eureka Client会定时连接Eureka Server,获取服务注册表中的信息并缓存在本地。微服务在消费远程API时总是使用本地缓存中的数据。因此一般来说,即使Eureka Server发生宕机,也不会影响服务之间的调用。但如果Eureka Server宕机时,某些微服务也出现了不可用的情况,Eureka Client中的缓存若不被更新,就可能会影响微服务调用,甚至影响整个应用系统的高可用性。因此,在生产环境中,通常都会部署一个高可用的Eureka Server集群。
编写高可用Eureka Server
- Eureka Server可以通过运行多个实例并相互组测的方式实现高可用部署,Eureka Server实例会彼此增量地同步信息,从而确保所有节点数据一致。
- 创建Maven项目如下
-
修改电脑hosts文件添加配置如下:
-
127.0.0.1 peer1 peer2
-
-
spring: application: name: microservice-discovery-eureka-ha --- # 连字符(---)将该application.yml文件分为三段, #第二,三段分别为spring.properties指定了一个值, #该值表示它所在的那段内容应用在哪个Profile里。 #第一段由于未指定spring.profiles,因此这段内容会对所有Profile生效。 spring: profiles: peer1 # 指定profile=peer1 server: port: 8761 eureka: instance: hostname: peer1 # 指定当profile=peer1时,主机名为peer1 client: service-url: defaultZone: http://peer2:8762/eureka/ # 将自己注册到peer2这个Eureka上面去 --- spring: profiles: peer2 server: port: 8762 eureka: instance: hostname: peer2 client: service-url: defaultZone: http://peer1:8761/eureka/
-
@SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); } }
-
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ym.cloud</groupId> <artifactId>microservice-discovery-eureka-ha</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <!-- 引入spring boot的依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <!-- 引入spring cloud的依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 添加spring-boot的maven插件 --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
上面配置了peer1和peer2两个Profile。当应用以peer1这个Profile启动时,配置该Eureka Server的主机名为peer1,并将其注册到http://peer2:8762/eureka/;反之,当应用以profile=peer2时,Eureka Server会注册到peer1节点的Eureka Server。
-
接下来对项目进行打包,并运行如下命令:
-
java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
-
java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2
-
-
分别访问http://peer1:8761;http://peer2:8762
-
对application.yml进行优化
-
spring: application: name: microservice-discovery-eureka-ha eureka: client: serviceUrl: defaultZone: http://peer2:8762/eureka/,http://peer1:8761/eureka/ --- spring: profiles: peer1 server: port: 8761 eureka: instance: hostname: peer1 --- spring: profiles: peer2 server: port: 8762 eureka: instance: hostname: peer2
-
将应用注册到Eureka Server集群上
-
修改消费方的配置文件
-
eureka: client: service-url: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/
-
-
此外即使微服务只配置Eureka Server集群中的某个节点,也能正常注册到Eureka Server集群,因为多个Eureka Server之间的数据会相互同步。如下:
-
eureka: client: service-url: defaultZone: http://peer1:8761/eureka/
-
-
正常情况下,这种配置方式与配置多个Server节点的效果是一样的,但是为了避免某些极端场景问题,还是建议配置多个Eureka Server节点。
用户认证
- 在项目中可能希望必须经过用户认证才允许访问Eureka Server。
为Eureka Server添加用户认证
- 创建Maven项目如下
-
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ym.cloud</groupId> <artifactId>microservice-discovery-eureka-authenticating</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <!-- 引入spring boot的依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies> <!-- 引入spring cloud的依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 添加spring-boot的maven插件 --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
@SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); } }
-
security: basic: enabled: true # 开启基于HTTP basic的认证 user: name: user password: password123 # 配置用户名密码 #如果不设置这段内容,账号默认是user,密码是一个随机值,该值会在启动时打印出来。 server: port: 8761 eureka: client: registerWithEureka: false # 是否将自己注册到Eureka Server,默认为false fetchRegistry: false # 是否从Eureka Server获取组测信息,默认为true serviceUrl: defaultZone: http://user:password123@localhost:8761/eureka/ #将eureka.client.serviceUrl.defaultZone修改为 #http://user:password123@EUREKA_HOST:EUREKA_PORT/eureka/的形式
-
启动项目,并访问http://localhost:8761/如下,需要身份验证。输入用户名,密码即可访问Eureka Server。
将微服务注册到需认证的Eureka Server
- 如何将微服务注册到需认证的Eureka Server上呢,只需要将服务消费方的eureka.client.serviceUrl.defaultZone配置为==http://user:password@EUREKA_HOST:EUREKA_PORT/eureka/==的形式,即可将微服务注册到Eureka Server。
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka/
Eureka的元数据
- Eureka的元数据有两种,分别是标准元数据和自定义元数据。
- 标准元数据指的是主机名,IP地址,端口号,状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。
- 自定义元数据可以使用eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,但一般不会改变客户端的行为。
改造用户微服务
- 创建Maven项目
-
<?xml version="1.0" encoding="UTF-8"?> <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"> <groupId>com.ym.cloud</groupId> <version>0.0.1-SNAPSHOT</version> <modelVersion>4.0.0</modelVersion> <artifactId>microservice-provider-user-my-metadata</artifactId> <packaging>jar</packaging> <!-- 引入Spring boot依赖--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jave.version>1.8</jave.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <!-- 引入spring cloud的依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 添加spring-boot的maven插件 --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
@RestController public class UserController { @Autowired private UserRepository userRepository; @GetMapping("/{id}") public User findById(@PathVariable Long id) { User user = userRepository.findOne(id); return user; } }
-
@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column private String username; @Column private String name; @Column private Integer age; @Column private BigDecimal balance; //setter && getter }
-
@Repository public interface UserRepository extends JpaRepository<User,Long> { }
-
@SpringBootApplication public class ProviderUserApplication { public static void main(String[] args) { SpringApplication.run(ProviderUserApplication.class,args); } }
-
server: port: 8000 spring: application: name: microservice-provider-user #指定注册到Eureka Server上的应用名称 jpa: generate-ddl: false show-sql: true hibernate: ddl-auto: none datasource: #指定数据源 platform: h2; #指定数据库类型 schema: classpath:schema.sql #指定h2数据库的建表语句 data: classpath:data.sql #指定h2数据库的数据脚本 logging: # 配置日志级别,让hibernate打印出执行的SQL level: root: INFO org.hibernate: INFO org.hibernate.type.descriptor.sql.BasicBinder: TRACE org.hibernate.type.descriptor.sql.BasicExtractor: TRACE ## INFO info: app: name: @project.artifactId@ encoding: @project.build.sourceEncoding@ java: source: @java.version@ target: @java.version@ management: security: enabled: false eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true #true表示将自己的ip注册到Eureka Server,若不配置该属性或将其设置为false, #则表示注册微服务所在操作系统的hostname到Eureka Server metadata-map: my-metadata: 我自定义的元数据 #自定义的元数据,key/value都可以随便写
改造电影微服务
- 创建Maven项目
-
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ym.cloud</groupId> <artifactId>microservice-consumer-movie-understanding-metadata</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <!-- 引入spring cloud的依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!--添加maven插件--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
@SpringBootApplication public class ConsumerMovieApplication { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ConsumerMovieApplication.class, args); } }
-
@RestController public class MovieController { @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; @GetMapping("/user/{id}") public User findByUser(@PathVariable Long id) { return restTemplate.getForObject("http://localhost:8000/"+id,User.class); } /** * 查询microservice-provider-user服务的信息并返回 * @return microservice-provider-user服务的信息 */ @GetMapping("/user-instance") public List<ServiceInstance> showInfo() { return this.discoveryClient.getInstances("microservice-provider-user"); //使用DiscoveryClient.getInstances(serviceId),可查询指定列表在Eureka上的实例列表 } }
-
server: port: 8010 spring: application: name: microservice-consumer-movie eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true
测试
- 依次启动服务端,用户微服务,电影微服务。
- 访问http://:localhost:8761/eureka/apps,看查看Eureka的metadata。
- 访问http://localhost:8010/user-instance,可以看到使用DiscoveryClient的API获得了用户微服务的各种信息,其中包含了标准元数据和自定义元数据。同时,自定义的元数据my-metadata,也可以通过客户端查询到,但是并不会改变客户端的行为。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QEPc6lvi-1610621110913)(第四章 微服务注册与发现/user-instance.png)]
Eureka的自我保护模式
- 自我保护机制模式的最直观的体现,就是Eureka Server首页输出的警告。如下
- 默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将注销该实例(默认是90s)。但是当网络分区故障发生时,微服务与Eureka Server之间将无法正常通信,以上行为就可能变得非常危险-----因为微服务本身是健康的,此时不应该注销这个微服务。
- Eureka通过”自我保护模式“来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
- 可以使用
eureka.server.enable-self-preservation = false
禁用自我保护模式。
Eureka的健康状况
- 在Status一栏有个UP,表示应用程序状态正常。应用状态还有其他取值,如:DOWN,OUT_OF_SERVICE,UNKNOWN等。只有标记为”UP“的微服务会被请求。
- Eureka Server与Eureka Client之间使用心跳机制来确定Eureka Client的状态,默认情况下,服务器与客户端的心跳保持正常,应用程序就会始终保持”UP“状态。
- 但是上面机制并不能完全反映应用程序的状态,如:微服务与Eureka Server之间的心跳正常,Eureka Server认为该微服务”UP“;然而,该微服务的数据源发生了问题(如:因为网络抖动,连不上数据源),根本无法正常工作。
- 要解决这一点,只需启用Eureka的健康检查,应用程序就会将自己的健康状态传播到Eureka Server。在application.yml中配置如下。
eureka:
client:
healthcheck:
enable: true
-
某些场景下,希望更细粒度的控制健康检查,此时可实现
com.netflix.appinfo.HealthCheckHandler
接口。注:eureka.client.healthcheck.enable=true只能配置在application.yml中,如果配置在bootstrap.yml中,可能会导致一些不良的后果,如应用注册到Eureka Server上的状态是UNKNOWN。 当eureka.client.healthcheck.enable=true时,/pause端点(Spring Boot Actuator提供,用于暂停工作)无法正常工作。 当eureka.client.healthcheck.enable=true时,请求/pause端点无法将应用在Eureka Server上的状态标记为DOWN。(bug)
排除Jersey依赖
-
默认情况下,Eureka Client使用Jersey 1.x与Eureka Server交互。
-
在spring Cloud Edgware中,Jersey并非必选,可排除Jersey的相关依赖。此时,Spring Cloud将自动配置一个基于RestTemplate的HTTP客户端。
-
排除Jersey的操作方法如下。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.sum.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
中,Jersey并非必选,可排除Jersey的相关依赖。此时,Spring Cloud将自动配置一个基于RestTemplate的HTTP**客户端。
- 排除Jersey的操作方法如下。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.sum.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
- Jersey是一个流行的RESTful框架,目前,Jersey已经发行到2.x版本,2.x与1.x不兼容,因此,当你想使用Jersey 2.x又希望将微服务注册到Eureka Server上时,就可以使用上面的方式。