Eureka 客户端服务实战

441 阅读7分钟

Eureka 核心功能就是服务注册与发现,Eureka 官方架构

image.png

上面的架构描述了 Eureka 的部署方式,这也是常用的运行方式。该架构中需要知道的几个核心概念:

  • Register(服务注册)
    任何想参与服务注册发现的实例,首先需要向Eureka服务器注册自己信息,注册在第一次心跳发生时提交

  • Renew(服务续租) Eureka客户端服务需要每30秒发送一次心跳来续租,通知Eureka服务当前客户端服务仍然是活动的。如果Eureka服务在90秒内没有看到更新信息,便会将客户端服务从其注册表中删除。注册信息和续订信息被复制到集群中的所有Eureka节点

  • Cancel(服务下线) Eureka客户端服务在关闭时向Eureka服务发送取消请求。Eureka服务将会把实例从注册表中删除

  • Get Registry(拉取服务列表) Eureka客户端服务从Eureka服务获取注册表信息并将其缓存在本地。然后客户端服务使用这些信息来查找其他服务以便于发起远程调用。

一、如何向Eureka集群注册服务

上一篇笔记 Eureka高可用服务集群搭建 中记录了集群搭建方法。在此基础上来说明如何向集群中注册一个服务提供者 provider

1. 项目结构

image.png

  • pom.xml 配置
<?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.3.10.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>user-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>8</java.version>
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        
        <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>
        </dependency>
    </dependencies>

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

</project>

2. 服务配置

application.properties 配置

server.port=8081
#
# 注册中心
eureka.client.service-url.defaultZone=http://ek1.com:7901/eureka/
#
# 指定当前客户端服务在注册中心的名称
eureka.instance.instance-id=user-provider-8081
#
# 服务名称
spring.application.name=user-provider
#
# eureka 服务名,默认值 unknown;如果没有配置,则取 spring.application.name
#eureka.instance.appname=user-provider
#
# 实例的虚拟主机名称,默认值 unknown;如果没有配置,则取 spring.application.name
#eureka.instance.virtual-host-name=user-provider

# 是否将自己注册到其他Eureka Server,默认为true
eureka.client.register-with-eureka=true
#
# 表示将自己的ip注册到Eureka Server上。不配置,表示将操作系统的hostname注册到server
eureka.instance.prefer-ip-address=true

如果要配置 eureka.instance.appnameeureka.instance.virtual-host-name 属性值,一定要和 spring.application.name 值配置成一样,避免奇奇怪怪的问题。

3. 启动服务

服务启动后,可到Eureka注册中心(ek1.com:7901/) 中查看服务是否注册上了

image.png

二、Eureka服务信息API

这里重点说明几个常用的API接口,需要更多详细接口可参考官方文档:Eureka REST operations

1. 查看注册的所有服务信息

get请求: ek1.com:7901/eureka/apps

image.png

2. 查看注册的的具体的服务信息

get请求: {ip:port}/eureka/apps/{spring.application.name}/{instanceId} 例如:ek1.com:7901/eureka/apps…

image.png

(1)元数据

Eureka的元数据有两种:标准元数据自定义元数据

  • 标准元数据:主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。
  • 自定义元数据:可以使用eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,但是一般不改变客户端行为,除非客户端知道该元数据的含义。可以在配置文件中对当前服务设置自定义元数据,可后期用户个性化使用。元数据可以配置Eureka服务器或者Eureka客户端上
eureka.instance.metadata-map.myKey=这是Eureka客户端

3. 服务续约

put请求:{ip:port}/eureka/apps/{spring.application.name}/{instanceId}?lastDirtyTimestamp={}&status=up

4. 更改服务状态

put请求:{ip:port}/eureka/apps/{spring.application.name}/{instanceId}/status?lastDirtyTimestamp={}&value={UP/DOWN}

5. 删除状态更新

delete请求:{ip:port}/eureka/apps/{spring.application.name}/{instanceId}/status?lastDirtyTimestamp={}&value={UP/DOWN}

6. 删除服务

delete请求:{ip:port}/eureka/apps/{spring.application.name}/{instanceId}

三、 Spring Boot Actuator 监控

Spring Boot ActuatorSpring Boot 的子项目。它使用 HTTP 端点来公开有关任何正在运行的应用程序的操作信息。使用该库的主要好处是我们可以从生产就绪的应用程序中获取运行状况和监控指标。当然,我们也需要对这些公开的信息进行鉴权,避免暴露重要信息,可参考 Spring Boot Actuator如何进行安全鉴权 这篇博文。

1. pom.xml 中引入

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>

2. Actuator监控

加人配置后启动应用程序,然后通过 http://localhost:8081/actuator访问,可返回如下结果:

{
   "_links": {
       "self": {
           "href": "http://localhost:8081/actuator",
           "templated": false
       },
       "health": {
           "href": "http://localhost:8081/actuator/health",
           "templated": false
       },
       "health-path": {
           "href": "http://localhost:8081/actuator/health/{*path}",
           "templated": true
       }
   }
}

可以看出,默认情况下只开放了 health 端点,如果要开发更多端点,需要进行配置

#开启所有端点
management.endpoints.web.exposure.include=*

这样能够看到更多的监控指标,实际开发中不建议这么做,除非你做了安全鉴权

image.png

3. 常用的几个端点

  • /actuator/health 显示系统监控状态,UP状态表示存活
    { "status": "UP" }

  • /actuator/beans:获取应用上下文中创建的所有bean

  • /actuator/configprops:获取应用中配置的属性信息报告,比如应用的环境变量和系统变量等信息

  • /actuator/metrics:返回应用的各类重要度量指标信息

image.png metrics节点并没有返回全量信息,我们可以通过不同的key去加载我们想要的值,比如访问: /actuator/metrics/system.cpu.count可以得到如下信息

{
    "name": "system.cpu.count",
    "description": "The number of processors available to the Java virtual machine",
    "baseUnit": null,
    "measurements": [
        {
            "statistic": "VALUE",
            "value": 8
        }
    ],
    "availableTags": []
}

四、 Eureka 的自我保护机制

  默认情况下,Eureka Server 在 90 秒内没有检测到服务列表中的某微服务,则会自动将该微服务从服务列表中删除。但很多情况下并不是该微服务节点(主机)出了问题,而是由于网络抖动等原因使该微服务无法被 Eureka Server 发现,即无法检测到该微服务主机的心跳。如果在短暂时间内网络恢复正常,但由于 Eureka Server 的服务列表中已经没有该微服务,该微服务就无法提供服务了,因为已经从Eureka Server服务列表中移除了,这种情况对服务稳定性来说是非常危险的。

  在短时间内若 Eureka Server 丢失较多微服务,即 Eureka Server 收到的心跳数量小于阈值,为了保证系统的可用性(AP),给那些由于网络抖动而被认为宕机的客户端重新复活的机会,Eureka Server 会自动进入自我保护模式,此时服务列表只可读取、写入,不可执行删除操作。Eureka Server 收到的心跳数量恢复到阈值以上时,会自动退出自我保护机制。

image.png

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.

【翻译】紧急情况!当微服务主机联系不上时,Eureka 不能够正确判断它们是否处于 up 状态。当更新(指收到的微服务主机的心跳)小于阈值时,为了安全,微服务主机将不再失效。

1. 自我保护机制触发条件

当 每分钟心跳次数 renewsLastMin 小于 numberOfRenewsPerMinThreshold 时,并且开启自动保护模式开关 eureka.server.enable-self-preservation = true 时,触发自我保护机制,不再自动过期租约。

  • numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 续租百分比( eureka.server.renewalPercentThreshold, 默认0.85 )
  • expectedNumberOfRenewsPerMin = 当前注册的应用实例数 x 2 (默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x 2 )
  • 举个例子,比如
    服务实例数:10个,期望每分钟续约数:10 * 2=20,期望阈值:20*0.85=17,自我保护少于17时 触发。

五、 Eureka 客户端服务下线

1.强制停止服务

# 开启所有端点 
management.endpoints.web.exposure.include=*
# 开启远程关闭服务功能,开启后可通过请求开闭服务
management.endpoint.shutdown.enabled=true

Eureka Server 发送 POST 请求:/actuator/shutdown

{
    "message": "Shutting down, bye..."
}

表示当前客户端节点应用程序已停止服务,该方式的不足之处是:如果需要该服务时,必须再次启动服务jar

2.不停止服务,改变服务状态

通过修改服务的状态为 UPDOWN 来设置提供者是否可用,而无需重启应用;怎么实现呢?

  • 我们只需将客户端微服务的健康状态也同步到 Eureka Server,启动Eureka Server的健康检查就行。这样微服务就会将自己的健康状态同步到Eureka Server。在客户端服务中做如下配置:
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# 客户端启动健康检查
eureka.client.healthcheck.enabled=true

提供改变健康状态的方法

@Service
public class HealthStatusService implements HealthIndicator{

	private Boolean status = true;

	public void setStatus(Boolean status) {
		this.status  = status;
	}

	@Override
	public Health health() {
		if(status) {
                 return new Health.Builder().up().build();
           }
		return new Health.Builder().down().build();
	}

	public String getStatus() {
		return this.status.toString();
	}
}