# Spring Cloud(Finchley版本)系列教程(一) 服务注册与发现(eureka)

为了更好的浏览体验,欢迎光顾勤奋的凯尔森同学个人博客http://www.huerpu.cc:7000 (opens new window)

如有错误恳请大家批评指正,与大家共同学习、一起成长,万分感谢。

# 一、构建环境

Spring Cloud的构建工具可以使用MavenGradle,但Maven任然是主流。本文档所使用的开发环境如下:

环境参数 版本
JDK 8
Maven 3.9.4
Spring Cloud Finchley
IDE idea2023.1.1 U
OS Windows11专业版

Spring Cloud相关模块

模块 说明
Eureka 服务注册中心,用于服务管理
Ribbon 基于客户端的负载均衡组件
Hystrix 容错框架,能够防止服务的雪崩效应
Feign Web服务客户端,能够简化HTTP接口的调用
Zuul API网关,提供路由转发、请求过滤等功能
Config 分布式配置管理
Sleuth 服务跟踪
Stream 构建消息驱动的微服务应用程序的框架
Bus 消息代理的集群消息总线

Spring Cloud主要有5大组件,分别为服务发现组件EurekaFeignRibbonZuulHystrix。但很多都弃用了,比如Ribbon等。

注:SpringCloud版本说明

英文 中文 boot大版本 boot代表
Angel 安吉尔 1.2.X 1.2.8
Brixton 布里克斯顿 1.3.X 1.3.8
Camden 卡梅登 1.4.X 1.4.2
Dalston 达斯顿 1.5.X 1.5.0
Edgware 艾奇韦尔 1.5.X 1.5.19
Finchley 芬奇利 2.0.X 2.0.8
Greenwich 格林威治 2.1.X 2.1.2
Hoxton 霍克斯顿 2.2.X 2.2.6
2020.0.6-aka Ilford 埃福的 2.5.7 2.5.7
2021.0.6 Jubilee 朱比利 2.6.x 2.6.1
2022.0.0 Kilburn 基尔伯恩 3.0.x 3.0.5

# 二、微服务注册与发现

Spring Cloud提供了很多服务发现组件,比如:EurekaConsulZooKeeper等。而EurekaNetflix开源的服务发现组件,它包含Server和Client两部分。Eureka Server提供服务发现的能力,每个微服务启动时,都会向Eureka Server注册自己的信息(IP、端口、微服务名称等),Eureka Server存储记录每个微服务的这些信息。Eureka Client是用于简化与Eureka Server交互的Java客户端。微服务启动后,会周期性地(默认30s)向Eureka Server发送心跳以续约自己的可用时间。如果Eureka Server在规定的时间内没有接收到微服务实例的心跳,Eureka Server则会将该实例注销(默认90s)。

常见的注册中心

组件名 语言 CAP 一致性算法 服务健康检查 对外暴露接口
Eureka Java AP 可配支持 HTTP
Consul Go CP Raft 支持 HTTP/DNS
Zookeeper Java CP Paxos 支持 客户端
Nacos Java AP Raft 支持 HTTP

# 2.1 创建EurekaServer

在idea中,创建一个名称为eurekaServerMaven工程。

image-20230906120456178

image-20230906121408500

image-20230906131449947

image-20230906121903248

pom.xml文件增加Eureka依赖,修改SpringCloud版本为Finchley.SR2,修改SpringBoot版本为2.0.6.RELEASE

<?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>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cc.huerpu</groupId>
    <artifactId>eurekaServer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eurekaServer</name>
    <description>eurekaServer</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.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-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

修改EurekaServerApplication启动类,增加@EnableEurekaServer注解。

package cc.huerpu.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

创建application.yml文件

server:
  port: 8761 # 端口号

spring:
  application:
    name: eurekaServer # Eureka名称

eureka:
  instance:
    prefer-ip-address: false
    hostname: eurekaServer
  client:
    fetch-registry: false # 表示是否从EurekaServer获取注册信息,默认为true。因为本应用是一个单点的EurekaServer,不需要同步其他的EurekaServer节点的数据,因此设为false。
    register-with-eureka: false # 是否将自己注册到EurekaServer,默认为true。由于当前应用就是EurekaServer,因此设为false。
    service-url:
      defaultZone: http://eurekaServer:8761/eureka/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

修改系统的hostsWindows11hosts文件路径为:C:\Windows\System32\drivers\etc\hostsLinuxmacOS的文件路径为/etc/hosts。增加一行:127.0.0.1 eurekaServer

启动项目,并测试访问

点击idea的项目启动按钮,并访问http://eurekaserver:8761/查看Eureka首页。

image-20230906134611417

# 2.2 创建EurekaClient,并让它注册到EurekaServer上。

复制eurekaServer项目,修改artifactIdEurekaClient。修改application.yml文件,端口号为8000,应用名称为eurekaClient

server:
  port: 8000 # 端口号

spring:
  application:
    name: eurekaClient # Eureka名称

management:
  info:
    env:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "*"
    enabled-by-default: true

eureka:
  instance:
    prefer-ip-address: false
    hostname: eurekaClient
  client:
    healthcheck:
      enabled: true
    fetch-registry: true 
    register-with-eureka: true 
    service-url:
      defaultZone: http://eurekaServer:8761/eureka/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

修改启动类,增加@EnableDiscoveryClient注解。

package cc.huerpu.eurekaclient;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class EurekaClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApplication.class, args);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

编写一个测试接口,最简单的那种就好。

@RestController
public class UserController {

    @RequestMapping("/getUserById")
    public String getUserById(){

        return "{id:1,name:jason,age:23}";
    }

}
1
2
3
4
5
6
7
8
9
10

修改pom.xml文件,把几处地方改为eurekaClient,另外增加了一个actuator包。

<?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>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cc.huerpu</groupId>
    <artifactId>eurekaClient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eurekaClient</name>
    <description>eurekaClient</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.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-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

启动项目,刷新http://eurekaClient:8761/会看到EurekaClient注册上来了。

image-20230906140215041

# 2.3 添加EurekaServer用户认证

在实际应用中,资源的访问都是需要认证的,接下来我们把EurekaServer 改造为需要认证的服务。

EurekaServer 添加security依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
1
2
3
4

修改EurekaServerapplication.yml文件,增加security认证,增加spring.security.user.namespring.security.user.password。并修改defaultZonehttp://eurekaha:eurekapwd@eurekaServer:8761/eureka/

server:
  port: 8761 # 端口号

spring:
  security:
    user:
      name: eureka
      password: eurekapwd
  application:
    name: eurekaServer # Eureka名称

eureka:
  instance:
    prefer-ip-address: false
    hostname: eurekaServer
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka:eurekapwd@eurekaServer:8761/eureka/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

EurekaServercc.huerpu.eurekaserver.security包路径下创建WebSecurityConfig类,关闭csrf,并开启httpBasic认证。

package cc.huerpu.eurekaserver.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

重新启动项目,访问时需要认证登录。

image-20230906144643762

输入配置文件里的账号/密码:eureka/eurekapwd进行登录。

image-20230906144720577

如果你的没有注册上来,耐心等一分钟就可以了。

对于创建Eureka的注册中心集群,请参考文章:http://www.huerpu.cc:7000/?p=607。这里就不做过多的介绍了。

# 三、创建一个eurekaClientConsumer调用eurekaClient服务

复制eurekaClient项目,修改artifactIdeurekaClientConsumer。修改application.yml文件,端口号为8001,应用名称为eurekaClientConsumer(本机host中也增加这一个)。

127.0.0.1   localhost
127.0.0.1   eurekaServer
127.0.0.1   eurekaClient
127.0.0.1   eurekaclientconsumer
1
2
3
4
<?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>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cc.huerpu</groupId>
    <artifactId>eurekaClientConsumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eurekaClientConsumer</name>
    <description>eurekaClientConsumer</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.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-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

application.yml

server:
  port: 8001 # 端口号

spring:
  application:
    name: eurekaClientConsumer # Eureka名称


management:
  info:
    env:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "*"
    enabled-by-default: true

eureka:
  instance:
    prefer-ip-address: false
    hostname: eurekaClientConsumer
  client:
    healthcheck:
      enabled: true
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka:eurekapwd@eurekaServer:8761/eureka/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

修改启动类名称为EurekaClientConsumerApplication,并增加注入一个restTemplate

package cc.huerpu.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class EurekaClientConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaClientConsumerApplication.class, args);
    }
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

controller包下创建一个ConsumerController类,注入restTemplateeurekaClientdiscoveryClient

package cc.huerpu.eurekaclient.controller;

import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;

@RestController
public class ConsumerController {
    @Autowired
    private RestTemplate  restTemplate;
    @Autowired
    private EurekaClient eurekaClient;

    @Autowired
    private DiscoveryClient discoveryClient;

    //获得eurekaClient的url
    @RequestMapping("/eurekaClientServiceUrl")
    private String eurekaClientServiceUrl() {
        InstanceInfo instance = eurekaClient.getNextServerFromEureka("eurekaClient", false);
        return instance.getHomePageUrl();
    }

    @RequestMapping("/consumerEurekaClient")
    public String consumerEurekaClient(){
        String eurekaClientURL = eurekaClientServiceUrl();
        String res = restTemplate.getForObject(eurekaClientURL + "/getUserById",String.class);
        return "consumerEurekaClient:" + res;
    }

    @RequestMapping("/eurekaClient-instance")
    public List<ServiceInstance> showInfo() {
        return this.discoveryClient.getInstances("eurekaClient");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

在没有服务注册中心的时候,eurekaClientConsumer服务调用eurekaClient服务,需要在eurekaClientConsumer服务代码里显式通过硬编码IP地址和端口号进行调用,也可以通过@Value注入配置的方式进行配置,但被调用方方的IP和端口号变化之后,调用方就必须进行修改,针对千千万万的接口来说,维护这些信息简直是场噩梦。

@RestController
public class ConsumerController {

    @RequestMapping("/consumerEurekaClient")
    public String consumerEurekaClient(){
        String res = restTemplate.getForObject("http://localhost:8000/getUserById", String.class);
        return "consumerEurekaClient:" + res;
    }
  
}
1
2
3
4
5
6
7
8
9
10
@RestController
public class ConsumerController {
		//通过配置文件中的hep.eurekaclient.userservice.url值进行配置
    @Value("${hep.eurekaclient.userservice.url}")
    private String eurekaClient;
    @RequestMapping("/consumerEurekaClient")
    public String consumerEurekaClient(){
        String res = restTemplate.getForObject("http://localhost:8000/getUserById", String.class);
        return "consumerEurekaClient:" + res;
    }
}
1
2
3
4
5
6
7
8
9
10
11

但现在我们通过eureka就没有这个烦恼啦,只需要eurekaClient.getNextServerFromEureka("eurekaClient", false),就可以获得服务的调用地址,其中"eurekaClient"是由spring.application.name指定的,即使被调用方的IP和端口号变化,对我们来说都是无感的,调用方这边完全不用做任何修改,是不是很开心?

访问http://eurekaclientconsumer:8001/consumerEurekaClient,就可以得到consumerEurekaClient:{id:1,name:jason,age:23},证明我们的消费方consumerEurekaClient调用被消费方eurekaClient成功了。

image-20230420150333493

# 四、Eureka 的元数据

Eureka 的元数据有两种,标准元数据和自定义元数据。标准元数据有主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。自定义元数据可以使用eureka.instance.metadata-map配置。

可以通过http://eurekaserver:8761/eureka/apps来查看eureka中有哪些应用。

<applications>
	<versions__delta>1</versions__delta>
	<apps__hashcode>UP_3_</apps__hashcode>
	<application>
		<name>EUREKASERVER</name>
		<instance>
			<instanceId>localhost:eurekaServer:8761</instanceId>
			<hostName>eurekaServer</hostName>
			<app>EUREKASERVER</app>
			<ipAddr>192.168.75.1</ipAddr>
			<status>UP</status>
			<overriddenstatus>UNKNOWN</overriddenstatus>
			<port enabled="true">8761</port>
			<securePort enabled="false">443</securePort>
			<countryId>1</countryId>
			<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
				<name>MyOwn</name>
			</dataCenterInfo>
			<leaseInfo>
				<renewalIntervalInSecs>30</renewalIntervalInSecs>
				<durationInSecs>90</durationInSecs>
				<registrationTimestamp>1693982763311</registrationTimestamp>
				<lastRenewalTimestamp>1693984895889</lastRenewalTimestamp>
				<evictionTimestamp>0</evictionTimestamp>
				<serviceUpTimestamp>1693982734094</serviceUpTimestamp>
			</leaseInfo>
			<metadata>
				<management.port>8761</management.port>
			</metadata>
			<homePageUrl>http://eurekaServer:8761/</homePageUrl>
			<statusPageUrl>http://eurekaServer:8761/actuator/info</statusPageUrl>
			<healthCheckUrl>http://eurekaServer:8761/actuator/health</healthCheckUrl>
			<vipAddress>eurekaServer</vipAddress>
			<secureVipAddress>eurekaServer</secureVipAddress>
			<isCoordinatingDiscoveryServer>true</isCoordinatingDiscoveryServer>
			<lastUpdatedTimestamp>1693982763311</lastUpdatedTimestamp>
			<lastDirtyTimestamp>1693982733236</lastDirtyTimestamp>
			<actionType>ADDED</actionType>
		</instance>
	</application>
	<application>
		<name>EUREKACLIENT</name>
		<instance>
			<instanceId>localhost:eurekaClient:8000</instanceId>
			<hostName>eurekaClient</hostName>
			<app>EUREKACLIENT</app>
			<ipAddr>192.168.75.1</ipAddr>
			<status>UP</status>
			<overriddenstatus>UNKNOWN</overriddenstatus>
			<port enabled="true">8000</port>
			<securePort enabled="false">443</securePort>
			<countryId>1</countryId>
			<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
				<name>MyOwn</name>
			</dataCenterInfo>
			<leaseInfo>
				<renewalIntervalInSecs>30</renewalIntervalInSecs>
				<durationInSecs>90</durationInSecs>
				<registrationTimestamp>1693982763312</registrationTimestamp>
				<lastRenewalTimestamp>1693984884241</lastRenewalTimestamp>
				<evictionTimestamp>0</evictionTimestamp>
				<serviceUpTimestamp>1693982751862</serviceUpTimestamp>
			</leaseInfo>
			<metadata>
				<management.port>8000</management.port>
			</metadata>
			<homePageUrl>http://eurekaClient:8000/</homePageUrl>
			<statusPageUrl>http://eurekaClient:8000/actuator/info</statusPageUrl>
			<healthCheckUrl>http://eurekaClient:8000/actuator/health</healthCheckUrl>
			<vipAddress>eurekaClient</vipAddress>
			<secureVipAddress>eurekaClient</secureVipAddress>
			<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
			<lastUpdatedTimestamp>1693982763312</lastUpdatedTimestamp>
			<lastDirtyTimestamp>1693982751816</lastDirtyTimestamp>
			<actionType>ADDED</actionType>
		</instance>
	</application>
	<application>
		<name>EUREKACLIENTCONSUMER</name>
		<instance>
			<instanceId>localhost:eurekaClientConsumer:8001</instanceId>
			<hostName>eurekaClientConsumer</hostName>
			<app>EUREKACLIENTCONSUMER</app>
			<ipAddr>192.168.75.1</ipAddr>
			<status>UP</status>
			<overriddenstatus>UNKNOWN</overriddenstatus>
			<port enabled="true">8001</port>
			<securePort enabled="false">443</securePort>
			<countryId>1</countryId>
			<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
				<name>MyOwn</name>
			</dataCenterInfo>
			<leaseInfo>
				<renewalIntervalInSecs>30</renewalIntervalInSecs>
				<durationInSecs>90</durationInSecs>
				<registrationTimestamp>1693984674119</registrationTimestamp>
				<lastRenewalTimestamp>1693984884145</lastRenewalTimestamp>
				<evictionTimestamp>0</evictionTimestamp>
				<serviceUpTimestamp>1693984674119</serviceUpTimestamp>
			</leaseInfo>
			<metadata>
				<management.port>8001</management.port>
			</metadata>
			<homePageUrl>http://eurekaClientConsumer:8001/</homePageUrl>
			<statusPageUrl>http://eurekaClientConsumer:8001/actuator/info</statusPageUrl>
			<healthCheckUrl>http://eurekaClientConsumer:8001/actuator/health</healthCheckUrl>
			<vipAddress>eurekaClientConsumer</vipAddress>
			<secureVipAddress>eurekaClientConsumer</secureVipAddress>
			<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
			<lastUpdatedTimestamp>1693984674119</lastUpdatedTimestamp>
			<lastDirtyTimestamp>1693984674059</lastDirtyTimestamp>
			<actionType>ADDED</actionType>
		</instance>
	</application>
</applications>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

我们在上面也有写了一个接口,用来获得eurekaClient服务的相关实例。

@Autowired
private DiscoveryClient discoveryClient;

@RequestMapping("/eurekaClient-instance")
public List<ServiceInstance> showInfo() {
    return this.discoveryClient.getInstances("eurekaClient");
}
1
2
3
4
5
6
7
<List>
	<item>
		<host>eurekaClient</host>
		<port>8000</port>
		<metadata>
			<management.port>8000</management.port>
		</metadata>
		<secure>false</secure>
		<uri>http://eurekaClient:8000</uri>
		<serviceId>EUREKACLIENT</serviceId>
		<instanceInfo>
			<instanceId>localhost:eurekaClient:8000</instanceId>
			<app>EUREKACLIENT</app>
			<appGroupName />
			<ipAddr>192.168.75.1</ipAddr>
			<sid>na</sid>
			<homePageUrl>http://eurekaClient:8000/</homePageUrl>
			<statusPageUrl>http://eurekaClient:8000/actuator/info</statusPageUrl>
			<healthCheckUrl>http://eurekaClient:8000/actuator/health</healthCheckUrl>
			<secureHealthCheckUrl />
			<vipAddress>eurekaClient</vipAddress>
			<secureVipAddress>eurekaClient</secureVipAddress>
			<countryId>1</countryId>
			<dataCenterInfo _class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
				<name>MyOwn</name>
			</dataCenterInfo>
			<hostName>eurekaClient</hostName>
			<status>UP</status>
			<overriddenStatus>UNKNOWN</overriddenStatus>
			<leaseInfo>
				<renewalIntervalInSecs>30</renewalIntervalInSecs>
				<durationInSecs>90</durationInSecs>
				<registrationTimestamp>1693982763312</registrationTimestamp>
				<lastRenewalTimestamp>1693984674011</lastRenewalTimestamp>
				<evictionTimestamp>0</evictionTimestamp>
				<serviceUpTimestamp>1693982751862</serviceUpTimestamp>
			</leaseInfo>
			<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
			<metadata>
				<management.port>8000</management.port>
			</metadata>
			<lastUpdatedTimestamp>1693982763312</lastUpdatedTimestamp>
			<lastDirtyTimestamp>1693982751816</lastDirtyTimestamp>
			<actionType>ADDED</actionType>
			<asgName />
		</instanceInfo>
		<scheme />
	</item>
</List>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 五、Eureka的健康检查

在pom文件中引入Spring Boot Actuator,它提供了/health端点,该端点可展示应用程序的健康信息。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
1
2
3
4

引入Actuator后,在Eureka中开启健康检查。

eureka:
  client:
    healthcheck:
      enabled: true 	 #开启健康检查(依赖spring-boot-actuator)
1
2
3
4

访问http://localhost:8761/actuator/health可以查看Eureka的状态。

若出现下面红色警告,其实是Eureka进入自我保护模式。如果最近一分钟实际接收到的心跳值Renews除以期望的心跳阈值Renews threshold小于等于0.85,即 Renews/Renews threshold≤0.85

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED  JUST TO BE SAFE 

可以把renewal-percent-threshold调的小一些

eureka:
  server:
    renewal-percent-threshold: 0.49
1
2
3

或者暴力一点关闭自我保护模式

# 默认值是true
eureka:
  server:
  	enable-self-preservation: false
1
2
3
4

默认情况下,服务注册到Eureka Server的过程较慢。在开发或测试时,常常希望能够加速这一过程,从而提升工作效率。

##默认是30,单位秒。设成一个更小的值,该配置用于设置Eureka Client向Eureka Server发送心跳的时间间隔
eureka:
  instance:
    lease-renewal-interval-in-seconds: 5
1
2
3
4

本文参考SpringCloud官方文档:https://docs.spring.io/spring-cloud-netflix/docs/4.0.1/reference/html/

# 六、部署eurekaserver到ubuntu22.04服务器

每次都启动eureka的项目,太繁琐了,我们把eureka部署到Ubuntu,就可以愉快的玩耍了。最好部署到一台可以远程访问的服务器,这样在任何地方都可以注册服务和消费服务了。

# 6.1 配置文件设置

这里为了演示,我们准备好了一台 ubuntu22.04,IP地址为192.168.169.128

eurekaserver项目,创建application-text.yml文件,内容如下

server:
  port: 8761 # 端口号

spring:
  security:
    user:
      name: eureka
      password: eurekapwd
  application:
    name: eurekaServer # Eureka名称

eureka:
  server:
    enable-self-preservation: true
  instance:
    prefer-ip-address: false
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka:eurekapwd@192.168.169.128:8761/eureka/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

application.properties中增加让test生效配置。

spring.profiles.active=test
1

# 6.2 生成eurekaserver的jar包

生成eurekaserver的jar包:

image-20230906154343842

# 6.3 ubuntu安装jdk1.8

sudo su -

apt update

apt upgrade -y

apt install openjdk-8-jre-headless

java -version
1
2
3
4
5
6
7
8
9

# 6.4 运行eurekaServer-0.0.1-SNAPSHOT.jar包

我们把eurekaServer-0.0.1-SNAPSHOT.jar包 放在/usr/software目录下,根据个人喜好目录存放即可。使用MobaXterm等SSH工具上传即可。

cd /usr
#创建software文件夹,在此文件夹下有我们的eurekaServer-0.0.1-SNAPSHOT.jar包,可以通过上传工具上传过来
mkdir software
#赋予权限
chmod -R 777 software
#进入到software目录
cd software

#运行jar包
nohup java -jar eurekaServer-0.0.1-SNAPSHOT.jar > log.txt &

#开放8761端口
ufw allow 8761
ufw enable
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 6.5 验证eurekaserver服务

打开http://192.168.169.128:8761/查看,Eureka已经启动了。

image-20230906154948081

eurekaClient项目修改defaultZonehttp://eureka:eurekapwd@192.168.169.128:8761/eureka/

defaultZone: http://eureka:eurekapwd@192.168.169.128:8761/eureka/
1

重启eurekaClient项目和eurekaClientConsumer项目,并刷新eurekaserver,查看服务是否注册上来。

image-20230906171825726

这样我们就可以使用这个Eureka注册中心,而没必要每次都用idea启动一下,这样会方便一点点。

# 七、eureka相关说明

# 7.1 EurekaServer REST API接口

POST    /eureka/apps/{appId}                                            注册新的实例

DELETE  /eureka/apps/{appId}/{instanceId}                               注销应用实例

PUT     /eureka/apps/{appId}/{instanceId}                               应用实例发送心跳

GET     /eureka/apps                                                    查询所有的实例

GET     /eureka/apps/{appId}                                            查询指定appId的实例

GET     /eureka/apps/{appId}/{instanceId}                               查询指定appId和instanceId的实例

GET     /eureka/instances/{instanceId}                                  查询指定的instanceId的实例

PUT     /eureka/apps/{appId}/{instanceId}/status?value=OUT_OF_SERVICE   暂停应用实例

PUT     /eureka/apps/{appId}/{instanceId}/status?value=UP               恢复应用实例

PUT     /eureka/apps/{appId}/{instanceId}/metadata?key=value            更新元数据信息

GET     /eureka/vips/{vipAddress}                                       根据vip地址查询

GET     /eureka/svips/{svipAddress}                                     根据svip地址查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 7.2 Client端参数

eureka.client.register-with-eureka: true                     是否注册自己到Eureka Server上面
eureka.client.fetch-registry: true                           是否从Eureka Server上面拉取服务信息
eureka.client.enable: true                                   是否启用Eureka客户端,不启用则不注册到Eureka Server
eureka.client.healthcheck.enable: true                       是否启用Eureka健康检查
eureka.client.availability-zones: new HashMap<>()            告诉client有哪些可用的region和zone
eureka.client.filter-only-up-instances: true                 是否过滤出InstanceStatus为UP的实例
eureka.client.region: us-east-1                              指定该应用实例所在的region,AWS datacenters适用
eureka.client.prefer-same-zone-eureka: true                  是否优先使用与该应用相同Zone的Eureka Server
eureka.client.cache-refresh-executor-thread-pool-size: 2     缓存刷新线程池CacheRefreshThread的初始化线程数
eureka.client.registry-fetch-interval-seconds: 30            Eureka client拉取服务注册信息间隔时间(s)
eureka.client.instance-info-replication-interval-seconds: 30 复制实例变化信息到Eureka服务器所需要的时间间隔(s)
eureka.client.eureka-service-url-poll-interval-seconds:  300 轮询Eureka服务端地址更改的间隔时间(s)
eureka.client.eureka-server-read-timeout-seconds: 8          读取Eureka Server信息的超时时间(s)
eureka.client.eureka-server-connect-timeout-seconds: 5       连接Eureka Server的超时时间(s)
eureka.client.eureka-server-total-connections: 200           从Eureka客户端到所有Eureka服务端的连接总数
eureka.client.eureka-server-total-connections-per-host: 50   从Eureka客户端到每个Eureka服务端主机的连接总数
eureka.client.eureka-connection-idle-timeout-seconds: 30     Eureka服务端连接的空闲关闭时间(s)
eureka.instance.metadata-map: new HashMap<>()                指定应用实例的元数据信息
eureka.instance.prefer-ip-address: false                     是否优先使用ip地址来替代hostname作为实例hostname字段值 
eureka.instance.lease-expiration-duration-in-seconds: 90     Eureka clent最后一次心跳后,Eureka Server剔除需要等待时间(s)
eureka.instance.lease-renewal-interval-in-seconds: 30        客户端向Eureka Server发送心跳周期(s)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 7.3 Server端参数

eureka.server.enable-self-preservation: true                 Eureka Server是否开启自我保护模式
eureka.server.renewal-percent-threshold: 0.85                指定每分钟需要收到的续约次数的阙值,如果阈值比最小值大,则自我保护模式开启
eureka.server.eviction-interval-timer-in-ms: 60*1000         指定EvictionTask定时任务的调度频率,用于剔除过期的实例
eureka.server.wait-time-in-ms-when-sync-empty: 1000*60*5     在Eureka服务器获取不到集群里对等服务器上的实例时,需要等待的时间
1
2
3
4

# 八、代码地址

代码共享地址:http://www.huerpu.cc:2080/root/springcloud-finchley

最近更新: 12/3/2024
勤奋的凯尔森同学   |