SpringCloud-Eureka基础篇

1. Eureka 简介

本博客来自阅读《重新定义Spring Cloud实战》

Eureka是 Netflix 的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。
服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。
功能类似于dubbo的注册中心,比如Zookeeper

2. Spring Cloud Eureka 简单案例

2.1 创建Maven父级 Pom 工程

在父工程里面配置好工程需要的父级依赖,目的是为了方便管理与简化配置。

<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.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>

2.2 创建Eureka Server工程

在 pom 文件中引入相关依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

在主启动类添加EnableEurekaServer注解

@SpringBootApplication
@EnableEurakeServer
public class DemoEurekaServer{

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

Eurake Server需要的 application.yml 配置

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    fetch-registry: false
  server:
    wait-time-in-ms-when-sync-empty: 0
    enable-self-preservation: false

2.3 创建Eureka Client组件工程

在 pom 文件中引入相关依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

在主启动类添加EnableDiscoveryClient注解

@SpringBootApplication
@EnableDiscoveryClient
public class DemoEurekaClient{

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

Eurake Client需要的 application.yml 配置

server:
  port: 8081
eureka:
  client:
    service-url: 
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: demo-client1

如果不配置 spring.application.name,会在 Eureka Server中显示 UNKNOWN.

分别启动Eureka ServerEureka Client,然后在浏览器中访问 http://localhost:8761

eureka-server-home

通过访问Eureka Server的 rest api 接口,比如http://localhost:8761/eureka/apps返回的结果如下:

<applications>
    <versions__delta>1</versions__delta>
    <apps__hashcode>UP_1_</apps__hashcode>
    <application>
        <name>DEMO-CLIENT1</name>
        <instance>
            <instanceId>172.21.0.222:demo-client1:8081</instanceId>
            <hostName>172.21.0.222</hostName>
            <app>DEMO-CLIENT1</app>
            <ipAddr>172.21.0.222</ipAddr>
            <status>UP</status>
            <overriddenstatus>UNKNOWN</overriddenstatus>
            <port enabled="true">8081</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>1570849865198</registrationTimestamp>
                <lastRenewalTimestamp>1570851155489</lastRenewalTimestamp>
                <evictionTimestamp>0</evictionTimestamp>
                <serviceUpTimestamp>1570849865199</serviceUpTimestamp>
            </leaseInfo>
            <metadata>
                <management.port>8081</management.port>
            </metadata>
            <homePageUrl>http://172.21.0.222:8081/</homePageUrl>
            <statusPageUrl>http://172.21.0.222:8081/actuator/info</statusPageUrl>
            <healthCheckUrl>http://172.21.0.222:8081/actuator/health</healthCheckUrl>
            <vipAddress>demo-client1</vipAddress>
            <secureVipAddress>demo-client1</secureVipAddress>
            <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
            <lastUpdatedTimestamp>1570849865199</lastUpdatedTimestamp>
            <lastDirtyTimestamp>1570849865140</lastDirtyTimestamp>
            <actionType>ADDED</actionType>
        </instance>
    </application>
</applications>

2. Rest Api 列表

operationhttp actiondescription
组册新的应用实例POST/eureka/apps/{appId}可以输入 json/xml 格式的 body,成功返回204
注销应用实例DELETE/eureka/apps/{appId}/{instanceId}成功返回200
应用实例发送心跳PUT/eureka/apps/{appId}/{instanceId}成功返回200,如果 instanceId 不存在返回404
查询所有实例GET/eureka/apps成功返回200,输出 json/xml 格式
查询指定 appId 实例GET/eureka/apps/{appId}成功返回200,输出 json/xml 格式
根据指定 appId 和 instanceId 查询GET/eureka/apps/{appId}/{instanceId}成功返回200,输出 json/xml 格式
暂停应用实例PUT/eureka/apps/{appId}/{instanceId}/status?value=OUT_OF_SERVICE成功返回200,失败返回500
恢复应用实例DELETE/eureka/apps/{appId}/{instanceId}/status?value=UP(value 参数可不传)成功返回200,失败返回500
更新元数据PUT/eureka/apps/{appId}/{instanceId}/metadata?key=value成功返回200,失败返回500
根据 vip 地址查询GET/eureka/vips/{vipAddress}成功返回200,输出 json/xml 格式
根据 svip 地址查询GET/eureka/svips/{svipAddress}成功返回200,输出 json/xml 格式

3. Eureka 核心类

3.1. InstanceInfo

Eureka使用InstanceInfo来代表注册的服务实例.

字段说明
instanceId实例 Id
appName应用名称
appGroupName应用所属组名
ipAddrip 地址
sid被废弃的属性,默认为 na
port端口号
securePorthttps 端口号
homePageUrl应用实例的首页 url
statusPageUrl应用实例的状态页 url
healthCheckUrl应用实例的健康检查 url
secureHealthCheckUrl应用实例的健康检查 https 的 url
vipAddress虚拟 ip 地址
countryId被废弃的属性,默认为 1,代表 US
dataCenterInfodataCenter 信息,Netflix/Amazon/MyOwn
hostName主机名称
status实例状态 UP/DOWN/STARTING/OUT_OF_SERVICE/UNKNOWN
overriddenStatus外界需要强制覆盖的状态值,默认为 UNKNOWN
leaseInfo租约信息
isCoordinatingDiscoveryServer首先标识是否是 discoveryService,其次标识该 discoveryService 是否是响应你请求的实例
metadata应用实例的元数据信息
lastUpdatedTimestamp状态信息最后更新时间
lastDirtyTimestamp实例信息最新的过期时间,在 Client 端用于标识该实例信息是否与 Eureka Server 一致,在 Server 端则与多个 Eureka Server 之间的信息同步处理
actionType标识 Eureka Server 对该实例执行的操作,包括 ADDED、MODIFIED、DELETED 这三类
asgName在 AWS 的 autoscaling group 名称
version实例版本,默认为 unknown

可以看到InstanceInfo中既有 metadata,也有 dataCenterInfo,还有一个比较重要的leaseInfo,用来标识该应用实例的租约信息。

3.2. LeaseInfo

Eureka使用LeaseInfo来标识应用实例的租约信息.

字段说明
renewalIntervalInSecsClient 续约的间隔周期
durationInSecsClient 需要设定的租约有效时长
registrationTimestampServer 端设置的该租约的第一次注册时间
lastRenewalTimestampServer 端设置的该租约的最后一次续约时间
evictionTimestampServer 端设置的该租约被剔除的时间
serviceUpTimestampServer 端设置的该服务实例标记为 UP 的时间

这些参数主要用于标识应用实例的心跳情况,比如约定的心跳周期,租约有效期,最近一次续约的时间等。

3.3. ServiceInstance

ServicdeInstance是 Spring Cloud 对 service discovery 的实例信息的抽象接口,约定了服务发现的实例应用有哪些通用的信息。

public interface ServiceInstance {

    /**
     * @return 注册的唯一实例 instanceId.
     */
    default String getInstanceId() {
        return null;
    }

    /**
     * @return 注册的 serviceId.
     */
    String getServiceId();

    /**
     * @return 注册服务实例的的 hostname.
     */
    String getHost();

    /**
     * @return 注册服务实例的端口.
     */
    int getPort();

    /**
     * @return 注册实例是否使用 https.
     */
    boolean isSecure();

    /**
     * @return 服务实例的 uri 地址.
     */
    URI getUri();

    /**
     * @return 服务实例元数据信息.
     */
    Map<String, String> getMetadata();

    /**
     * @return 服务实例的 scheme.
     */
    default String getScheme() {
        return null;
    }

}

由于 Spring Cloud Discovery 适配了 ZookeeperConsulNetflix Eureka等注册中心,因此其ServicdeInstance定义更为抽象和通用,而且采用的是定义方法的方式。
Spring Cloud 对该接口的实现类为EurekaRegistration,EurekaRegistration实现了ServicdeInstance接口,同时还实现了Closeable接口,目的是在 close 的时候调用 eurekaClient.shutdown() 方法,实现优雅关闭 Eureka Client。

3.3. ServiceStatus

InstanceInfo内部枚举类,用于标识服务实例状态。

public enum InstanceStatus {
    UP, // Ready to receive traffic
    DOWN, // Do not send traffic- healthcheck callback failed
    STARTING, // Just about starting- initializations to be done - do not
    // send traffic
    OUT_OF_SERVICE, // Intentionally shutdown for traffic
    UNKNOWN;

    public static InstanceStatus toEnum(String s) {
        if (s != null) {
            try {
                return InstanceStatus.valueOf(s.toUpperCase());
            } catch (IllegalArgumentException e) {
                // ignore and fall through to unknown
                logger.debug("illegal argument supplied to InstanceStatus.valueOf: {}, defaulting to {}", s, UNKNOWN);
            }
        }
        return UNKNOWN;
    }
}

服务实例主要有 UP、DOWN、STARTING、OUT_OF_SERVICE 和 UNKNOWN 几个状态。其中 OUT_OF_SERVICE 标识停止服务,处于该状态的服务实例不会被路由到,经常用于升级部署的场景。

4. 服务的核心操作

4.1. 概述

对于服务发现来说,围绕服务实例主要有如下几个重要的操作:

  • 服务注册(Service Register)
  • 服务下线(Service Cancel)
  • 服务租约(Service Renew)
  • 服务剔除(Service Evict)

围绕这几个功能,Eureka设计了几个核心操作类:

  • com.netflix.eureka.lease.LeaseManager
  • com.netflix.discovery.shared.LookUpService
  • com.netflix.eureka.registry.InstanceRegistry
  • com.netflix.eureka.registry.AbstractInstanceRegistry
  • com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl

Spring Cloud Eureka 在 Netflix Eureka 的基础上,抽象或定义了如下几个核心类:

  • org.springframework.cloud.netflix.eureka.server.InstanceRegistry
  • org.springframework.cloud.client.serviceregistry.ServiceRegistry
  • org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry
  • org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration
  • org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
  • org.springframework.cloud.netflix.eureka.EurekaClientConfigBean
  • org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean

其中LeaseManager以及LookUpServiceEureka关于服务发现相关操作定义的操作类,前者定义了操作相关方法,后者定义了操作相关方法。

4.2. LeaseManager

LeaseManager接口定义了应用服务实例在服务中心的几个操作方法: register、cancel、renew、evict。

public interface LeaseManager<T> {

    /**
     * 为传入的 r(T) 分配一个新的 Lease
     *
     * @param r - T to register
     * @param leaseDuration 续约时长
     * @param isReplication 是否是来自其他 eureka 节点的重复 entry
     */
    void register(T r, int leaseDuration, boolean isReplication);

    /**
     * 根据传入的 appname 和 id 删除关联的服务实例信息
     *
     * @param appName 应用唯一 id
     * @param id appName 中的唯一 id
     * @param isReplication  是否是来自其他 eureka 节点的重复 entry
     * @return 操作是否成功
     */
    boolean cancel(String appName, String id, boolean isReplication);

    /**
     * 根据传入的 appname 和 id 续约关联的服务实例信息
     *
     * @param id appName 中的唯一 id
     * @param isReplication  是否是来自其他 eureka 节点的重复 entry
     * @return 操作是否成功
     */
    boolean renew(String appName, String id, boolean isReplication);

    /**
     * Server 端方法,用于剔除租约过期的服务实例信息
     */
    void evict();
}

4.3. LookUpService

LookUpService接口定义了 Eureka Client从服务中心获取服务实例的查询方法。

public interface LookupService<T> {

    /**
     * 根据 appName 返回对应的 Application 实例
     *
     * @param appName
     * @return application/null
     */
    Application getApplication(String appName);

    /**
     * 返回所有的 Application 实例
     *
     * @return {@link Applications}
     */
    Applications getApplications();

    /**
     * 根据 instanceId 返回对应的 InstanceInfo 实例
     *
     * @param id
     * @return List<InstanceInfo>/Collections.emptyList()
     */
    List<InstanceInfo> getInstancesById(String id);

    /**
     * Gets the next possible server to process the requests from the registry
     * information received from eureka.
     * 获取下一个可能的 server,以处理来自 eureka 的注册信息请求
     * <p>
     *
     * @param virtualHostname 与服务器关联的虚拟主机名
     * @param secure 是否使用 https
     * @return the {@link InstanceInfo} 下一个服务器的 InstanceInfo
     * @throws java.lang.RuntimeException 如果 virtualHostname 不存在
     */
    InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
}

该接口是给 Client 使用的,其定义了获取所有应用信息、根据应用 id 获取所有服务实例,以及根据 visualHostname 使用 round-robin 方法获取下一个服务实例的方法。

5. Eureka 参数调优及监控

要深入了解一个开源组件,从解读参数入手,不失为一种好的研读代码的方法。

5.1. 核心参数

5.1.1. Client 端

5.1.1.1. 基本参数
参数默认值说明
eureka.client.availability-zones-告知 Client 有哪些 region 及 availability-zones,支持配置修改运行时生效
eureka.client.filter-only-up-instancestrue是否过滤出 InstanceStatus 为 UP 的实例
eureka.client.regionus-east-1指定该应用实例所在的 region,AWS datacenters 适用
eureka.client.register-with-eurekatrue是否将该应用实例注册到Eureka Server
eureka.client.prefer-same-zone-eurekatrue是否优先使用与该应用实例相同 Zone 的Eureka Server
eureka.client.on-demand-update-status-changetrue是否将本实例状态的更新通过 ApplicationInfoManager 实时触发同步(有请求流控限制)到Eureka Server
eureka.instance.metadata-map-指定应用实例的元数据信息
eureka.instance.prefer-ip-addressfalse是否优先使用 IP 地址替代 hostname 作为实例的 hostName 字段
eureka.instance.lease-expiration-duration-in-seconds90指定Eureka Client需要间隔多久向Eureka Server发送心跳告知该实例还存活
5.1.1.2. 定时任务参数
参数默认值说明
eureka.client.cache-refresh-executor-thread-pool-size2刷新缓存的 CacheRefreshThread 线程池大小
eureka.client.cache-refresh-executor-exponential-back-off-bound10调度任务执行超时时下次执的调度延迟时间
eureka.client.heartbeat-executor-thread-pool-size2发送心跳的 CacheRefreshThread 线程池大小
eureka.client.heartbeat-executor-exponential-back-off-bound10调度任务执行超时时下次执的调度延迟时间
eureka.client.registry-fetch-interval-seconds30CacheRefreshThread 线程的调度频率
eureka.client.eureka-service-url-poll-interval-seconds5*60AsyncResolver.updateTask 刷新Eureka Server地址的时间间隔
eureka.client.initial-instance-info-replication-interval-seconds40InstanceInfoReplicator 将实例信息变更同步到Eureka Server的初始延迟时间
eureka.client.instance-info-replication-interval-seconds30InstanceInfoReplicator 将实例信息变更同步到Eureka Server的时间间隔
eureka.instance.lease-renewal-interval-in-seconds30Eureka ClientEureka Server发送心跳的时间间隔
5.1.1.2. http 相关参数
参数默认值说明
eureka.client.eureka-server-connect-timeout-seconds5连接超时时间
eureka.client.eureka-server-read-timeout-seconds8读超时时间
eureka.client.eureka-server-total-connections200连接池最大活动连接数(MaxTotal)
eureka.client.eureka-server-total-connections-per-host50每个 host 能使用的最大连接数(DefaultMaxPerRoute)

5.1.2. Server 端

5.1.2.1. 基本参数
参数默认值说明
eureka.server.enable-self-preservationtrue是否开启自我保护模式
eureka.server.renewal-percent-threshold0.85指定每分钟需要收到的续约次数的阀值
eureka.instance.registry.expected-number-of-clients-sending-renews1指定每分钟需要收到的续约次数值,实际该值在其中被写死为 count*2,另外也会被更新
eureka.server.renewal-threshold-update-interval-ms15*60指定 updateRenewalThreshold 定时任务的调度频率,来动态更新 exceptedNumber OfRenewsPerMin 及 numberOfRenewsPerMin Threshold 值
eureka.server.eviction-interval-timer-in-ms60*1000指定 EvictionTask 定时任务的调度频率,用于剔除过期的实例
5.1.2.2. response cache 参数

Eureka Server为了提升自身 Rest Api 接口性能,提供基于 ConcurrentMap 的 readOnlyCacheMap 和 基于 Guava Cache 的 readWriteCacheMap。

参数默认值说明
eureka.server.use-read-only-response-cachetrue是否使用只读的 response-cache
eureka.server.response-cache-update-interval-ms30*1000设置 CacheUpdateTask 的调度时间间隔,用于从 readWriteCacheMap 更新数据到 readOnlyCacheMap。仅仅在 eureka.server.use-read-only-response-cache=true 时有效
eureka.server.response-cache-auto-expiration-in-seconds180设置 readWriteCacheMap 的 expireAfterWrite 参数,指定写入多长时间后过期
5.1.2.3. peer 相关参数

Eureka Server需要与其他 peer 节点进行通信,复制实例信息,其底层使用 httpClient。

参数默认值说明
eureka.server.peer-node-connect-timeout-ms200连接超时时间
eureka.server.peer-node-read-timeout-ms200读超时时间
eureka.server.peer-node-total-connections1000连接池最大活动连接数(MaxTotal)
eureka.server.peer-node-total-connections-per-host500每个 host 能使用的最大连接数(DefaultMaxPerRoute)
eureka.server.peer-node-connection-idle-timeout-seconds30连接池中连接的空闲时间(connectionIdleTimeout)

5.1.3. 参数调优

5.1.3.1. 常见问题

对于新接触 Eureka 的开发人员来说,一般会有几个困惑:

  • 为什么服务下线了,Eureka Server接口返回的信息还会存在
  • 为什么服务上线了,Eureka Client不能及时获取到
  • 为什么有时会出现如下提示:

eureka-error

5.1.3.2. 解决办法

对于第一个问题,Eureka不是强一致性,因此 registry 中会存留过期的实例信息,可能导致的原因是:

  1. 应用实例异常挂掉,没能在挂掉之前告知Eureka Server要下线掉该服务实例信息。这需要依赖Eureka ServerEvictionTask去剔除。
  2. 应用实例有告知Eureka Server下线,但由于Eureka Server但 Rest Api 存在 response-cache,因此需要等待缓存过期才能更新。
  3. Eureka Server由于开启并引入了 SELF PRESERVATION 模式,导致 registry 的信息不会因为过期而被剔除掉,直接退出 SELF PRESERVATION 模式。

对于 Client 下线没有通知Eureka Server,可以调整 EvictionTask 的调度频率,将默认的30秒改为5秒:

eureka.eureka.server.eviction-interval-timer-in-ms=5000

针对 response-cache 的问题,可以考虑关闭 readOnlyCacheMap:

eureka.server.use-read-only-response-cache=false

或者调整 readWriteCacheMap 的过期时间

eureka.server.response-cache-auto-expiration-in-seconds=60

针对 SELF PRESERVATION 的问题,测试环境中将 enable-self-preservation 设置为 false:

eureka.server.enable-self-preservation=false

关闭的话,则会提示:

THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

或者

RENEWALS ARE LESSER THAN THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

针对新服务上线,Eureka Client获取不及时的问题,在测试环境,可以适当提高 Client 端拉取 Server 端注册信息的频率,例如将默认的30秒改为5秒:

eureka.client.registry-fetch-interval-seconds=5

针对 SELF PRESERVATION 的问题,SELF PRESERVATION 是为了解决因为网络抖动等问题造成服务实例与Eureka Server心跳未能如期保持,从而导致本身健康的服务为剔除。
对于开发测试环境,开启这个机制有时候反而会影响系统的持续集成,因此可以通过如下参数关闭:

eureka.server.enable-self-preservation=false

在生产环境中可以把 renewal-percent-threshold 及 lease-renewal-interval-in-seconds 参数调小,进而提高触发 SELF PRESERVATION 机制的门槛:

eureka.server.renewal-percent-threshold=0.49 ## 默认0.85
eureka.instance.lease-renewal-interval-in-seconds=10 ## 默认30

5.2. 指标监控

Eureka 内置基于 servo 的指标统计,详见 EurekaMonitors 类

指标名称说明
renewCounter自启动以来收到的总续约次数
cancelCounter自启动以来收到的总取消续约次数
getAllCacheMissCounter自启动以来查询 registry 的总次数
getAllCacheMissDeltaCounter自启动以来 delta 查询 registry 的总次数
getAllWithRemoteRegionCacheMissCounter自启动以来 remote region 查询 registry 的总次数
getAllWithRemoteRegionCacheMissDeltaCounter自启动以来remote region及delta查询registry的总次数
getAllDeltaCounter自启动以来查询 delta 的总次数(/{version}/apps/delta)
getAllDeltaWithRemoteRegionCounter自启动以来传递 regions 参数查询 delta 的总次数(/{version}/apps/delta)
getAllCounter自启动以来查询(/{version}/apps)的总次数
getAllWithRemoteRegionCounter自启动以来传递 regions 参数查询(/{version}/apps)的总次数
getApplicationCounter自启动以来请求 /{version}/apps/{appId} 的总次数
registerCounter自启动以来 registry 的总次数
expiredCounter自启动以来剔除过期实例的总次数
statusUpdateCounter自启动以来 statusUpdate 的总次数
statusOverrideDeleteCounter自启动以来 deleteStatusOverride 的总次数
cancelNotFoundCounter自启动以来收到 cancel 请求时对应实例找不到次数
renewNotFoundexpiredCounter自启动以来收到 renew 请求时对应实例找不到次数
numOfRejectedReplications
numOfFailedReplications
numOfRateLimitedRequests由于 rate limiter 被丢弃的请求数量
numOfRateLimitedRequestCandidates如果开启 rate limiter 的话,将被丢弃的请求数
numOfRateLimitedFullFetchRequests开启 rate limiter 时请求全量 registry 被丢弃的请求数
numOfRateLimitedFullFetchRequestCandidates如果开启 rate limiter 时请求全量 registry 将被丢弃的请求数

Spring Boot 2.X 版本改为使用 Micrometer,不再支持 Netflix Servo,转而支持了 Netflix Servo 替代者 Netflix Spectator。不过对于 Servo,可以通过 DefaultMonitorRegistry.getInstance().getRegisteredMonitors() 来获取所有注册了的 Monitor,进而获取其指标值。

6. Eureka 实战

6.1. Eureka Server 在线扩容

6.1.1 准备工作

在 pom.xml 中引入 config-server 工程

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

启动类 DemoEurekaServerApplication 代码

@SpringBootApplication
@EnableEurekaServer
public class DemoEurekaServerApplication {

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

}

添加 bootstrap.yml 配置文件

spring:
    application:
      name: config-server
    profile:
      active: native
server:
    port: 8888

使用 native 的 profile,即使用文件来存储配置,默认放在 resource/config 目录下。

由于要使用动态扩容,这里还需要建立一个 eureka-server 和 eureka-client 工程。并为两个工程都添加 QueryController 用于实验。

@RestController
@RequestMapping("/query")
public class QueryController {

    private final EurekaClientConfigBean eurekaClientConfigBean;

    public QueryController(EurekaClientConfigBean eurekaClientConfigBean) {
        this.eurekaClientConfigBean = eurekaClientConfigBean;
    }

    @GetMapping("/eureka-server")
    public Map<String, String> getEurekaServerUrl() {
        return eurekaClientConfigBean.getServiceUrl();
    }

}

eureka-client 配置文件清单 (${eureka-client-project}/src/main/resource/config/eureka-client.yml):

spring:
    application:
      name: config-client1
server:
    port: 8881
eureka:
    client:
      serverUrl:
        defaultZone: http://localhost:8761/eureka/

另外一个 eureka-server 工程配置文件清单 (${eureka-server-project}/src/main/resource/config/eureka-server-peer1.yml):

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/
  server:
    wait-time-in-ms-when-sync-empty: 0
    enable-self-preservation: false

然后分别启动 config-server、eureka-server(使用 peer1 的 profile)、eureka-client工程,打开 http://localhost:8761.可以观察到注册实例

然后我们开始扩充Eureka Server实例,在 eureka-server 中使用 peer2 的 profile 启动第二个Eureka Server

mvn spring-boot:run -DSpring.profile=active=peer2

eureka-server-peer2.yml 的配置文件如下:

server:
  port: 8762
eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/
  server:
    wait-time-in-ms-when-sync-empty: 0
    enable-self-preservation: false

当 eureka-server-peer2 工程启动之后,需要修改 eureka-client.yml 和 eureka-server-peer1.yml 配置文件

eureka-client.yml

spring:
    application:
      name: config-client1
server:
    port: 8881
eureka:
    client:
      serverUrl:
        defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/

eureka-server-peer1.yml

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8762/eureka/
  server:
    wait-time-in-ms-when-sync-empty: 0
    enable-self-preservation: false

之后重启 config-server,使配置生效。并使用命令刷新 eureka-client 和 eureka-server-peer1 工程的配置。

curl -i -X POST localhost:8761/actuator/refresh

curl -i -X POST localhost:8081/actuator/refresh

分别调用 queryController 的方法:

curl -i http://localhost:8761/query/eureka-server

curl -i http://localhost:8762/query/eureka-server


文章作者: Emil
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Emil !
评论
 上一篇
SpringBoot-Mail发送邮件 SpringBoot-Mail发送邮件
添加 maven 依赖在 pom.xml 中添加 mail 和 thymeleaf 对应的依赖<dependencies> <dependency> <groupId>org.springframe
2019-10-03
下一篇 
Mac终端工具iTerm2 Mac终端工具iTerm2
iTerm2Mac OS自带的终端,用起来虽然有些不太方便,界面也不够友好,iTerm2是一款相对比较好用的终端工具.iTerm2常用操作包括主题选择、声明高亮、自动填充建议、隐藏用户名和主机名、分屏效果等.下载地址: https://ww
2019-09-21
  目录