Spring Cloud 学习(3) --- Eureka(二) REST API、核心类、调优

在上一篇已经了解到了服务注册与发现EurekaEureka 简单示例Eureka Server 中查看 Client 状态等。接下来需要了解 Eureka 的 REST API核心类调优等组件。

REST API

在 Eureka Server 的可视化页面中,我们可以看到每个微服务的注册信息。在 Server、Client 的配置文件中,都指定了一个 defaultZone: ip:port/eureka/,那么这个配置的作用是什么?为什么在 ip、端口 后面要加上一个 /eureka ?

/eureka 就是 Eureka 的 REST API 的端点地址。

/eureka/ 端点

启动 Eureka Server、Client,在浏览器中输入: http://localhost:8761/eureka/apps ,可以看到如下信息:

<!-- 所有工程 -->
<applications> 
    <versions__delta>1</versions__delta>   
    <apps__hashcode>UP_1_</apps__hashcode>    
    <application> 
        <!-- 单个实例的名称 -->
        <name>SPRING-CLOUD-EUREKA-CLIENT-SIMPLE</name>    
         <instance> 
            <!-- 单个实例的 instance-id -->
            <instanceId>spring-cloud-eureka-client-simple:8081</instanceId>    
            <!-- 实例的 hostname,没有指定时用 ip -->
            <hostName>10.10.10.141</hostName>    
            <app>SPRING-CLOUD-EUREKA-CLIENT-SIMPLE</app>    
            <!-- 实例的ip -->
            <ipAddr>10.10.10.141</ipAddr>    
            <!-- 实例状态 -->
            <status>UP</status>    
            <overriddenstatus>UNKNOWN</overriddenstatus>    
            <!-- 端口 -->
            <port enabled="true">8081</port>    
            <!-- https -->
            <securePort enabled="false">443</securePort>    
            <countryId>1</countryId>    
            <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo"> 
                <name>MyOwn</name> 
            </dataCenterInfo>    
            <leaseInfo> 
                <!-- 每多长时间续约一次,单位 秒 -->
                <renewalIntervalInSecs>30</renewalIntervalInSecs>    
                <!-- 续约过期时间,单位秒。规定时间内没有续约会剔除 Eureka Server -->
                <durationInSecs>90</durationInSecs>    
                <!-- 注册时间 -->
                <registrationTimestamp>1547800471059</registrationTimestamp>    
                <!-- 上一次续约时间 -->
                <lastRenewalTimestamp>1547800471059</lastRenewalTimestamp>    
                <evictionTimestamp>0</evictionTimestamp>    
                <serviceUpTimestamp>1547800471059</serviceUpTimestamp> 
            </leaseInfo>    
            <metadata> 
                <management.port>8081</management.port>    
                <jmx.port>10235</jmx.port> 
            </metadata>    
            <!-- 主页面 -->
            <homePageUrl>http://10.10.10.141:8081/</homePageUrl>    
            <!-- 实例信息 -->
            <statusPageUrl>http://10.10.10.141:8081/actuator/info</statusPageUrl>    
            <!-- 实例健康检查 -->
            <healthCheckUrl>http://10.10.10.141:8081/actuator/health</healthCheckUrl>    
            <vipAddress>spring-cloud-eureka-client-simple</vipAddress>    
            <secureVipAddress>spring-cloud-eureka-client-simple</secureVipAddress>    
            <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>    
            <lastUpdatedTimestamp>1547800471059</lastUpdatedTimestamp>    
            <lastDirtyTimestamp>1547800470997</lastDirtyTimestamp>    
            <actionType>ADDED</actionType> 
        </instance> 
    </application> 
</applications>

此时看到的信息,是在 Eureka Server 中注册的所有Client 的信息。如果想要查询单个 Client 的信息,可以访问 http://localhost:8761/eureka/apps/{application.name} ,如:http://localhost:8761/eureka/apps/SPRING-CLOUD-EUREKA-CLIENT-SIMPLE

常用的 REST API

常用的 Eureka REST API 除了 /eureka/apps 之外,还有如下接口

操作 http 动作 接口 描述
注册新的应用实例 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 格式的 body
查询单个实例 GET /eureka/apps/{appId} 成功返回 200,输出json 或 xml 格式的 body
根据 appId、instanceId 查询 GET /eureka/apps/{appId}/{instanceId} 成功返回 200,输出 json 或 xml 格式的 body
暂停某个实例 PUT /eureka/apps/{appId}/{instanceId}/status?value=OUT_OF_SERVICE 成功返回 200,失败返回 500
恢复某个实例 DELETE /eureka/apps/{appId}/{instanceId}/status?vlaue=UP(value 可不传) 成功返回 200,失败返回 500
更新元数据 PUT /euerka/apps/{appId}/{instanceId}/metadata?key=value 成功返回 200,失败返回 500
根据虚拟 ip 查询 GET /eureka/vip/{vipAddr} 成功返回 200,输出 json 或 xml 格式的 body
根据基于 htpps 的虚拟 ip 查询 GET /eureka/svip/{svipAddr} 成功返回 200,输出 json 或 xml 格式的 body

在进行新实例的注册时,传入的 json、xml 的格式需要与调用获取单个实例所返回的数据格式一致。具体的数据需要自己指定,需要注意的是,如果要注册的实例的ip、端口已经存在的话,不会再次注册,需要修改 instanceId。


Eureka 核心类

Eureka 提供了一些核心的类,这些类中保存了 Eureka Server、Client 的注册信息、运行时的信息等。

InstanceInfo

InstanceInfo 代表了注册的服务实例(位置: com/netflix/appinfo/InstanceInfo.java)

字段 说明
app 应用名称
appGroupName 应用所属群组
ipAddr ip 地址
sid 已废弃,默认 na
port 端口号
securePort https 端口
homePageUrl 应用实例的首页 url
statusPageUrl 应用实例的状态页 url
healthPageUrl 应用实例的健康检查 url
secureHealthPageUrl 应用实例的健康检查 https url
vipAddress 虚拟 ip 地址
secureVipAddress https 的虚拟 ip 地址
countryId 已废弃,默认 1,代表 US
dataCenterI dataCenter 信息,Netflix、Amazon、MyOwen
hostName 主机名称(默认 ip
status 状态,如:UP、DOWN、STATING、OUT_OF_SERVICE、UNKNOWN
overrideenstatus 外界需要强制覆盖的状态,默认为 UNKNOWN
leaseInfo 租约信息
isCorrdinatindDiscoveryServer 首先标示是否是 DiscoveryServer,其次标示该 DiscoveryServer 是否是响应你请求的实例
metadata 应用实例的元数据信息
lastUpdateTimestamp 状态信息最后更新时间
lastDirtyTimestamp 实例信息的最新过期时间,在 Client 端用于标志该实例信息是否与 Eureka Server 一致,在 Server 端则与多个 Server 之间进行信息同步
actionType 标示 Server 对该实例进行的操作,包括:ADDED、MODIFIED、DELETED
args 在 AWS 的 autoscaling group 名称

可以看出,整个 InstanceInfo 的返回值信息,就是访问 /eureka/apps/{appId} 的返回值,也是通过 REST API 向 Eureka Server 注册时的 body。

LeaseInfo

LeaseInfo 标识应用实例的租约信息(位置: com/netflix/appinfo/LeaseInfo.java)

字段 说明
renewalIntervalInSecs Client 续约时间间隔(秒)
durationInSecs Client 的租约有效时间长(秒)
registreationTimestamp 第一次注册时间(毫秒时间戳)
laseRenewalTimestamp 最后一次续约时间(毫秒时间戳)
evicationTimestamp 租约被剔除时间(毫秒时间戳)
serviceUpTimestamp Client 被标记为 UP 状态的时间(毫秒时间戳)

ServiceInstanceInfo

ServiceInstanceInfo 是一个标识一个应用实例的接口,约定了服务的发现的实例应用有哪些通用信息(位置: org/springframework/cloud/client/ServiceInstanceInfo.java)

方法 说明
getSercieId() 获取服务 id
getHost() 获取实例的 HOST
getPort() 获取实例的端口
isSecure() 是否开启 https
getUri() 实例的 uri 地址
getMetadata() 实例的元数据信息
getScheme() 实例的 scheme

对于 ServiceInstanceInfo 接口的实现为:EurekaRegistration(位置:org/springframework/cloud/netflix/eureka/serviceregistry/EurekaRegistration.java),EurekaRegistration 同时还实现了 Closeable 接口,这个接口的作用之一是在 close 的时候调用 eurekaClient.shutdown() 方法,实现优雅关闭 Eureka Client。

InstanceStatus

InstanceStatus 是一个枚举类型,源码如下:

public static enum InstanceStatus {
    UP,
    DOWN,
    STARTING,
    OUT_OF_SERVICE,
    UNKNOWN;

    private InstanceStatus() {
    }

    public static InstanceInfo.InstanceStatus toEnum(String s) {
        if (s != null) {
            try {
                return valueOf(s.toUpperCase());
            } catch (IllegalArgumentException var2) {
                InstanceInfo.logger.debug("illegal argument supplied to InstanceStatus.valueOf: {}, defaulting to {}", s, UNKNOWN);
            }
        }

        return UNKNOWN;
    }
}

其中定义了 5 种状态,对应 Client 的 5 种状态。


服务的核心操作

对于服务发现来说,一般都是围绕几个核心的概念进行设计:

服务发现(register)
服务下线(cancel)
服务租约(renew)
服务剔除(evict)

围绕这几个概念,Eureka 设计了一些核心的操作类:

  • com/netflix/eureka/lease/LeaseManager.java
  • com/netflix/discovery/shared/LookupService.java
  • com/netflix/eureka/registry/InstanceRegistry.java
  • com/netflix/eureka/registry/AbstractInstanceRegistry.java
  • com/netflix/eureka/registry/PeerAwareInstanceRegistry.java

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

  • org/springframewor/cloud/netflix/eureka/server/InstanceRegistry.java
  • org/springframewor/cloud/client/serviceregistry/ServiceRegistry.kava
  • org/springframewor/cloud/netflix/eureka/serviceregistry/EurekaServiceRegistry.java
  • org/springframewor/cloud/netflix/eureka/serviceregistry/EurekaRegistration.java
  • org/springframewor/cloud/netflix/eureka/EurekaClientAutoConfiguration.java
  • org/springframewor/cloud/netflix/eureka/EurekaClientConfigBean.java
  • org/springframewor/cloud/netflix/eureka/EurekaInstanceConfigBean.java

其中:LeaseManagerLookupService 是 Eureka 关于服务发现相关操作操作定义的接口类,LeaseManager 定义了服务写操作相关方法,LookupService 定义查询操作的相关方法。

LeaseManager

public interface LeaseManager<T> {
    
    void register(T r, int leaseDuration, boolean isReplication);

    boolean cancel(String appName, String id, boolean isReplication);

    boolean renew(String appName, String id, boolean isReplication);

    void evict();
}、
  • register:用于注册服务实例信息
  • cancel:用于删除服务实例信息
  • renew:用于和 Eureka Server 进行心跳操作,维持租约
  • evict:Server 端的方法,用于剔除租约过期的服务实例。

LoopupService

public interface LookupService<T> {

    Application getApplication(String appName);

    Applications getApplications();

    List<InstanceInfo> getInstancesById(String id);

    InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
}
  • getApplication:根据 appName 获取服务信息
  • getApplications:获取所有注册的服务信息
  • getInstancesById:根据 appid,获取所有实例
  • getNextServerFromEureka:根据虚拟hostname、是否是 https,获取下一个服务实例方法(默认轮训获取)

Eureka 参数调优

Client 端

基本参数

参数 默认值 说明
eureka.client.avaliability-zones 告知 Client 有哪些 regin 和 zone,支持配置修改运行时生效
eureka.client.filter-only-up-instances true 是否滤出 InstanceStatus 为 UP 的实例
eureka.clint.region us-east-1 指定 region,当 datacenters 为 AWS 时适用
eureka.client.register-with-eureka true 是否将实例注册到 Eureka Server
eureka.client.prefer-same-zone-eureka true 是否优先使用和该应用实例处于相同 Zone 的 Eureka Server
eureka.client.on-demand-update-status-change trye 是否将本地实例状态的更新,通过 ApplicationInfoManager 实时同步到 Eureka Server(这个同步请求有流量限制)
eureka.instance.matadata-map 指定实例的元数据信息
eureka.instance.prefer-ip-address false 是否优先使用 ip 地址来代替 hostname 作为实例的 hostname 字段值
eureka.instance.lease-exporation-duration-in-seconds 90 指定 Eureka Client 间隔多久向 Server 发送心跳

定时任务参数

参数 默认值(时间单位:秒,非时间单位:个) 说明
eureka.client.cache-refresh-executor-thread-pool-size 2 刷新缓存的 CacheRefreshThread 线程池大小
eureka.client.cache-refresh-executor-exponential-back-off-bound 10 调度任务执行时,下次调度的延迟时间
eureka.client.heartbeat-executor-thread-pool-size 2 执行心跳 HeartbeatThread 的线程池大小
eureka.client.heartbeat-executor-exponential-back-off-bound 10 调度任务执行时,下次调度的延迟时间
eureka.client.registry-fetch-interval-seconds 30 CachaRefreshThread 线程调度频率
eureka.client.eureka-service-url-poll-interval-seconds 5*60 AsyncResolver.updateTask 刷新 Eureka Server 地址的时间间隔
eureka.client.initial-instance-info-replication-interval-seconds 40 InstanceInfoReplicator 将实例信息变更同步到 Eureka Server 的初始延时时间
eureka.client.instance-infi-replication-interval-seconds 30 InstanceInfiReplicator 将实例信息变更同步到 Eureka Server 的时间间隔
eureka.client.lease-renewal-interval-in-seconds 30 Eureka Client 向 Eureka Server 发送心跳的时间间隔

http 参数

Eureka Client 底层使用 HttpClient 与 Eureka Server 通信。

参数 默认值 说明
eureka.client.eureka-server-connect-timeout-seconds 5 连接超时时间
eureka.client.eureka-server-read-timeout-seconds 8 读超时时间
eureka.client.eureka-server-total-connections 200 连接池最大连接数
eureka.client.eureka-server-total-connections-per-host 50 每个 host 能使用的最大链接数
eureka.client.eureka-connection-idle-timeout-seconds 30 连接池空闲连接时间

Server 端

Server 端的参数调优分为:基本参数,Response Cache、Peer、Http 等

基本参数

参数 默认值 说明
eureka.server.enable-self-preservation true 是否开启自我保护模式
eureka.server.renewal-percent-threshold 0.85 每分钟需要收到的续约次数阈值(心跳数/client实例数)
eureka.instance.registry.expected-number-of-renews-per-min 1 指定每分钟需要收到的续约次数,实际上,在源码中被写死为 count * 2
eureka.server-renrewal-threshold-update-interval-ms 15 分钟 指定 updateRenewalThreshold 定时任务的调度频率,动态更新 expectedNumberOfRenewsMin 以及 numberOfNewsPerMinThreshold 的值
eureka.server.evication-interval-timer-in-ms 60*1000 指定 EvicationTask 定时任务调度频率,用于剔除过期的实例

Response Cache 参数

Eureka Server 为了提升自身 REST API 接口的性能,提供了两个缓存:一个是基于 ContioncurrentMapreadOnlyCacheMap,一个是基于 Guava ChahereadWriteCacheMap

参数 默认值 说明
eureka.server.use-read-only-response-cache true 是否使用只读的 Response Cache
eureka.server.response-cache-update-interval-ms 30 * 1000 设置 CacheUpdateTask 的调度时间间隔,用于从 readWriteCacheMap 更新数据到 readOnlyCacheMap。仅在 eureka.server.use-read-only-response-cache 为 true 时生效
eureka.server.response-cache-auto-expiration-in-seconds 180 设置 readWriteCacheMap 的过期时间

peer 参数

参数 默认值 说明
eureka.server.peer.eureka-nodes-update-interval-ms 10分钟 指定 peersUpdateTask 调度的时间间隔,用于配置文件刷新 peerEurekaNodes 节点的配置信息
eureka.server.peer-eureka-status-refresh-time-interval-ms 30*1000 指定更新 Peer nodes 状态的时间间隔

http 参数

参数 默认值 说明
eureka.server.peer-node-connect-timeout-ms 200 链接超时时间
eureka.server.peer-node-read-timeout-ms 200 读超时时间
eureka.server.peer-node-total-connections 1000 连接池最大连接数
eureka.server.peer-node-total-connections-per-host 500 每个 host 能使用的最大连接数
eureka.server.peer-node-connection-idle-timeout-seconds 30 连接池中链接的空闲时间
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容