目录
3、在项目启动类添加@EnableEurekaServer注解
3、在项目启动类添加@EnableEurekaClient注解
3、在项目启动类添加@EnableEurekaClient或@EnableDiscoveryClient 注解
自定义Eureka Server刷新服务列表,将无效服务剔除的时间间隔:
1.Eureka工作机制
Eureka工作原理
Eureka包含哪两个组件?
Spring Cloud框架下的服务发现Eureka包含两个组件,分别是:Eureka Server与Eureka Client。
Eureka Server:
Eureka Server,也称为服务注册中心。各个服务启动后,会在Eureka Server中进行注册,这样Eureka Server的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client:
Eureka Client也称为服务(服务实例)。作为一个Java客户端,用于简化与Eureka Server的交互。Eureka Client内置一个使用轮询负载算法的负载均衡器。服务启动后,Eureka Client将会向Eureka Server发送心跳更新服务,如果Eureka Server在多个心跳周期内没有接收到某个服务的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
为了更好地理解Eureka 组件的工作原理,接下来通过一张图来描述。如下图所示。
Eureka Client注册在Eureka Server,Eureka Client中的服务Service是通过REST调用的。Eureka Client还具有缓存功能,它能够从Eureka Server查询当前注册的服务信息并缓存到本地,这样即使Eureka Server宕机,Eureka Client依然可以利用缓存中的信息调用服务。
2.服务提供者与服务消费者
Eureka Client有哪两种角色?
Eureka Client存在两种角色,分别是服务提供者和服务消费者。
服务提供者:
服务提供者( Eureka Client )启动后,会通过REST请求将自己注册在Eureka Server,并维护一个心跳(默认30秒发送一次心跳)进行服务续约,告诉Eureka Server“我还活着”,防止Eureka Server将该服务从服务列表剔除。
服务消费者:
用于获取Eureka Server注册的服务清单,并且该服务清单默认每隔30秒更新一次。服务消费者获取到服务清单后,能够根据自己的需求决定调用哪个服务,默认采用轮询方式调用,从而实现Eureka Client的负载均衡。
接下来,通过一张图描述Eureka Server与服务提供者、服务消费者之间的关系,如下图所示。
服务消费者是如何调用服务提供者的?
服务提供者和服务消费者都属于Eureka Client,它们都会将自己的信息通过REST API形式提交给Eureka Server。服务消费者注册后,还会获取一份服务注册列表,该列表包含了所有向Eureka Server注册的服务信息。获取到服务注册信息后,服务消费者就会根据服务提供者的IP地址,通过HTTP远程调用服务提供者的服务。
3.第一个Eureka应用
①搭建Eureka-server
1、创建项目,引入依赖
使用Spring Initializr方式创建一个名称为eureka-server的Spring Boot项目,在pom.xml文件中添加Eureka Server依赖。
在pom文件中添加的Eureka Server依赖如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2、添加Eureka的相关配置
在全局配置文件application.yml中添加Eureka的相关配置信息。(注:项目自动生成的配置文件为application.properties,我们直接将后缀名改掉就行。这两个文件格式都可以,只是内部的内容格式不同。)
application.yml:
server:
port: 7000 # 服务器端口号7000
spring:
application: #端口号名称配置
name: eureka-server
eureka:
client:
fetch-registry: false # 表示是否向Eureka Server注册
register-with-eureka: false # 表示是否从Eureka Server获取注册信息
service-url:
defaultZone:
http://${eureka.instance.hostname}:${server.port}/eureka/ #设置服务注册中心地址
instance:
hostname: localhost
3、在项目启动类添加@EnableEurekaServer注解
在项目启动类EurekaServerApplication上添加@EnableEurekaServer注解开启Eureka Server功能。
@SpringBootApplication
@EnableEurekaServer
public class EurekeServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekeServerApplication.class, args);
}
}
启动eureka-server项目,在浏览器中访问http://localhost:7000/。效果如下图所示。
②搭建服务提供者
1、创建项目,引入依赖
使用Spring Initializr方式创建一个名称为eureka-provider的Spring Boot项目,添加Web、Eureka Client依赖。
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
2、添加Eureka的相关配置
在全局配置文件application.yml中添加Eureka的相关配置信息。
server:
port: 7006
spring:
application:
name: eureka-provider
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
instance:
hostname: localhost
3、在项目启动类添加@EnableEurekaClient注解
在项目启动类EurekaProviderApplication上添加@EnableEurekaClient注解开启Eureka Client功能。
@SpringBootApplication
@EnableEurekaClient
public class EurekaServerProvide01Application {
public static void main(String[] args) {
SpringApplication.run(EurekaServerProvide01Application.class, args);
}
}
保证Eureka Server启动的状态下,启动eureka-provider,在浏览器中访问Eureka Server的主界面http://localhost:7000/,效果如下图所示。
③搭建服务消费者
1、创建项目,引入依赖
使用Spring Initializr方式创建一个名称为eureka-consumer的Spring Boot项目,添加Web、Eureka Client依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
2、添加Eureka的相关配置
在全局配置文件application.yml中添加Eureka的相关配置信息。
server:
port: 7002
spring:
application:
name: eureka-consumer
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
instance:
hostname: localhost
3、在项目启动类添加@EnableEurekaClient或@EnableDiscoveryClient 注解
注:在启动类中,使用了@EnableDiscoveryClient 注解来修改启动类,该注解使得服务调用者有能力去 Eureka 中发现服务,需要注意的是@EnableEurekaClient 注解已经包含了 @EnableDiscoveryClient 的功能,也就是说,一个 Eureka 客户端,本身就具有发现服务的能力。
@SpringBootApplication
@EnableDiscoveryClient
public class EurekaServerInvokeApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerInvokeApplication.class, args);
}
}
保证Eureka Server启动的状态下,启动eureka-consumer。在浏览器访问http://localhost:7000/,说明服务提供者和服务消费者已经成功注册到Eureka Server中。效果如下图所示。
4.Eureka 高可用配置
在微服务架构这样的分布式环境中,我们需要充分考虑发生故障的情况,所以在生产环境中必须对各个组件进行高可用部署,对于微服务如此,对于服务注册中心也一样。但是到本节为止,我们一直都在使用单节点的服务注册中心,这在生产环境中显然并不合适,我们需要构建高可用的服务注册中心以增强系统的可用性。 Eureka Server 的设计一开始就考虑了高可用问题,在 Eureka 的服务治理设计中,所有节点即是服务提供方,也是服务消费方,服务注册中心也不例外。
Eureka Server 的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。下面我们就来尝试搭建高可用服务注册中心的集群。可以在本章第1节中实现的服务注册中心的基础之上进行扩展,构建一个双节点的服务注册中心集群。
本例将会运行两个服务器实例、两个服务提供者实例,然后服务调用者请求服务,第一个 Eureka 应用,使用的是浏览器访问 Eureka 的服务调用者,而改造后,为了能看到负载均衡的效果,会编写一个 HttpClient 的 REST 客户端访问服务调用者发布的服务。
新建模块 eureka-cloud-server,并添加依赖
在 Eureka 项目中用 springboot 创建 eureka-cloud-server 模块,勾选 Spring Cloud Discovery->Eureka Server ,修改相应的版本和上面一致。
@SpringBootApplication
@EnableEurekaServer
public class EurekaCloudServerApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(EurekaCloudServerApplication.class).run(args);
}
}
配置文件如下
server:
port: 8761
spring:
application:
name: eureka-cloud-server
profiles: slave1
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/
--------------------------------------------------
server:
port: 8762
spring:
application:
name: eureka-cloud-server
profiles: slave2
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
配置了两个 profiles,名称分别为 slave1 和 slave2。
在 slave1 中,配置了应用端口为 8761,主机名为 slave1,当使用 salve1 这个 profiles 来启动服务器时,将会向http://slave2:8762/eureka/注册自己。
使用salve2来启动服务器,会向 http://slave1:8761/eureka/ 注册自己。
简单点说,就是两个服务器启动后,它们会互相注册
注意:第一个启动的服务器会抛出异常,异常原因我们前已经讲述,抛出的异常可不必理会。
当 Eureka 配置高可用后,服务提供者也需要进行相应的调整。eureka-service-provider 复制出来,并改名为 eureka-cloud-provider。修改配置文件,将服务提供者注册到两个服务器中
spring:
application:
name: eureka-cloud-provider
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
修改控制器,可以看到是请求的 url
@RestController
public class FirstController {
@RequestMapping(value = "/person/{personId}")
public Map<String, Object> findPerson(@PathVariable Integer personId, HttpServletRequest request) {
HashMap<String, Object> map = new HashMap<>();
map.put("id", personId);
map.put("name", "张三");
map.put("age", 18);
map.put("url", request.getRequestURL().toString());
return map;
}
}
分别在 8886 和 8888 端口启动两个服务提供者
调整服务调用者,将 eureka-service-invoker 复制并改名为 eureka-cloud-invoker。本例中的服务调用者只需启动一个实例,因此修改下配置文件即可使用
server:
port: 9000
spring:
application:
name: eureka-cloud-invoker
eureka:
client:
serviceUrl:
defaultZone: http://slave1:8761/eureka/,http://slave2:8761/eureka/
调用类修改一下服务名
@RestController
@Configuration
public class InvokerController {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@RequestMapping(value = "/router/{personId}")
public String router(@PathVariable Integer personId) {
RestTemplate restTpl = getRestTemplate();
// 根据应用名称调用服务
String json = restTpl.getForObject(
"http://eureka-cloud-provider/person/" + personId, String.class);
return json;
}
}
启动调用者服务后即可完成浏览器测试,但是建议使用 HttpClient 进行测试
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
</dependencies>
main方法如下
public static void main(String[] args) throws Exception {
// 创建默认的HttpClient
CloseableHttpClient httpclient = HttpClients.createDefault();
// 调用6次服务并输出结果
for(int i = 0; i < 6; i++) {
// 调用 GET 方法请求服务
HttpGet httpget = new HttpGet("http://localhost:9000/router/"+i);
// 获取响应
HttpResponse response = httpclient.execute(httpget);
// 根据 响应解析出字符串
System.out.println(EntityUtils.toString(response.getEntity()));
}
}
完成编写后,按以下顺序启动各个组件:
- 启动两个服务器端,控制台中分别输入“slave1”和“slave2”。
- 启动两个服务提供者,控制台分别输入 8888 与 8886。
- 启动服务调用者。
启动了整个集群后,运行TestHttpClient,可以看到输出如下
{"name":"张三","id":3,"age":18,"url":"http://localhost:8886/person/0"}
{"name":"张三","id":3,"age":18,"url":"http://localhost:8888/person/1"}
{"name":"张三","id":3,"age":18,"url":"http://localhost:8886/person/2"}
{"name":"张三","id":3,"age":18,"url":"http://localhost:8888/person/3"}
{"name":"张三","id":3,"age":18,"url":"http://localhost:8886/person/4"}
{"name":"张三","id":3,"age":18,"url":"http://localhost:8888/person/5"}
根据输出结果可知,8888 与 8886端口分别被请求了 3 次,可见已经达到负载均衡的目的
5.心跳机制
Eureka是通过心跳的方式实现对各个服务实例的健康检测的。在Eureka的服务续约与剔除机制下,客户端的健康状态从注册到注册中心开始都会处于UP状态,除非心跳中止一段时间后,服务注册中心将其剔除。心跳机制以有效检查客户端进程是否正常运作,接下来,我们将对Eureka心跳机制常用配置进行讲解
自定义心跳时间:
服务启动后,Eureka Client实例将会向Eureka Server发送周期性的心跳,默认是每30秒发送一次,可通过修改Eureka Client实例的eureka.instance. leaseRenwalIntervalInSeconds属性来改变发送周期性心跳的默认时间。如下所示。
eureka:
instance:
leaseRenewalIntervalInSeconds: 5 #设置心跳时间为5秒
自定义Eureka Server刷新服务列表,将无效服务剔除的时间间隔:
Eureka Server如果在一定期限内没有接收到Eureka Client实例的心跳,那么会将该实例从注册中心剔除掉,其他客户端将无法访问这个实例。这个期限默认值为90秒。可以通过eureka.instance.leaseExpriationDurationInSeconds属性修改默认值,示例代码如下:
eureka:
instance:
leaseRenewalIntervalInSeconds: 5
leaseExpirationDurationInSeconds: 10 #设置每隔10秒刷新服务列表,将 无效服务剔除
自我保护机制
Eureka的自我保护机制是为了防止误杀服务。如果Eureka Server注册中心发生故障,那么Eureka Client服务就有可能不能正常续约,虽然这时Eureka Client服务是正常的,但注册中心依然会将超过90秒未续约的服务剔除,造成误杀服务的情况。
Eureka Server如何判断是否开启自我保护?
Eureka Server通过判断是否存在大量续约失败的服务,从而确定是否开启自我保护。默认情况下,Eureka Server配置的自我保护阀值是0.85,如果Eureka Server运行期间根据心跳比例接收到的服务续约低于阀值,则Eureka Server开启自我保护,不再剔除注册列表的信息。
如何关闭自我保护机制?
如果在Eureka Server保护期间,可能会发生服务下线的情况,此时Eureka Server维护的服务清单就不那么准确了,此时可以关闭保护保护机制,确保服务中心不可用的服务实例被及时剔除。 默认情况下,Eureka Server自我保护是开启的,如果需要关闭,则可以在配置文件中添加如下代码:
eureka:
server:
enable-self-preservation: false
其他配置
参数名称 | 参数说明 |
enable | 启动Eureka客户端,默认值true |
registryFetchIntervalSeconds | 从Eureka服务端获取注册信息的间隔时间,单位为秒,默认值30 |
fetchRegistry | 是否从Eureka服务端获取注册信息,默认值false |
eurekaServerReadTimeoutSeconds | 读取Eureka Server信息的超时时间,单位为秒,默认值8 |
initialInstanceInfoReolicationInstervalSeconds | 初始化实例信息到Eureka服务端的间隔时间,单位为秒,默认值40 |
instanceInfoReolicationInstervalSeconds | 更新实例信息的变化到Eureka服务端的间隔时间,单位为秒,默认值30 |
preferIpAddress | 是否优先使用IP地址作为主机名的标识,默认值false |
leaseRenewalIntervalInSeconds | Eureka客户端向服务端发送心跳的时间间隔,单位为秒,默认值30 |
leaseExpirationDurationInSeconds | Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,如果超出时间后,服务端会将该服务实例从服务清单中剔除,从而禁止服务调用请求被发送到该实例上,默认值90 |
appname | 服务名,默认取spring.application.name的配置值,如果没有则为unknown |
hostname | 主机名,不配置时将根据操作系统的主机名来获取 |