(二).SpringCloud 从入门到放弃-Eureka注册中心深入

深入了解Eureka

Eureka Server的REST API简介

前面介绍了一个最基本的Eureka Server 和Eureka Client,它是整个springcloud生态服务注册于发现的一个缩影
这里举的shi是使用java语言的client例子,但是Eureka Server提供了REST API,允许其他语言的应用通过HTTP REST的方式接入到Eureka的服务注册发现中

REST API 列表
操作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格式
查询指定appId应用实例GET /eureka/apps/{appId}
根据指定appId和instanceId查询应用实例GET /eureka/apps/{appId}/{instanceId}
根据指定instanceId查询应用实例GET /eureka/instances/{instanceId}
暂停应用实例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}/status?mametadata?key=value成功返回200,失败返回500
根据vip地址查询GET /eureka/vips/{vipAddress}成功返回200,输出json或者xml格式
根据svip地址查询GET /eureka/svips/{svipAddress}成功返回200,输出json或者xml格式
REST API 实例
  • 查询所有应用实例 curl -i http://localhost:10086/eureka/apps
HTTP/1.1 200
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Wed, 24 Apr 2019 07:23:38 GMT

<applications>
  <versions__delta>1</versions__delta>
  <apps__hashcode>UP_1_</apps__hashcode>
  <application>
    <name>SERVICE-ONE</name>
    <instance>
      <instanceId>DESKTOP-2Q068VO:service-one</instanceId>
      <hostName>DESKTOP-2Q068VO</hostName>
      <app>SERVICE-ONE</app>
      <ipAddr>192.168.50.208</ipAddr>
      <status>UP</status>
      <overriddenstatus>UNKNOWN</overriddenstatus>
      <port enabled="true">8080</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>1556089288403</registrationTimestamp>
        <lastRenewalTimestamp>1556090696963</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1556089288403</serviceUpTimestamp>
      </leaseInfo>
      <metadata>
        <management.port>8080</management.port>
      </metadata>
      <homePageUrl>http://DESKTOP-2Q068VO:8080/</homePageUrl>
      <statusPageUrl>http://DESKTOP-2Q068VO:8080/actuator/info</statusPageUrl>
      <healthCheckUrl>http://DESKTOP-2Q068VO:8080/actuator/health</healthCheckUrl>
      <vipAddress>service-one</vipAddress>
      <secureVipAddress>service-one</secureVipAddress>
      <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
      <lastUpdatedTimestamp>1556089288403</lastUpdatedTimestamp>
      <lastDirtyTimestamp>1556089286739</lastDirtyTimestamp>
      <actionType>ADDED</actionType>
    </instance>
  </application>
</applications>
  • 根据appId查询 curl -i http://localhost:10086/eureka/apps/service-one
HTTP/1.1 200
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Wed, 24 Apr 2019 07:25:32 GMT

<application>
  <name>SERVICE-ONE</name>
  <instance>
    <instanceId>DESKTOP-2Q068VO:service-one</instanceId>
    <hostName>DESKTOP-2Q068VO</hostName>
    <app>SERVICE-ONE</app>
    <ipAddr>192.168.50.208</ipAddr>
    <status>UP</status>
    <overriddenstatus>UNKNOWN</overriddenstatus>
    <port enabled="true">8080</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>1556089288403</registrationTimestamp>
      <lastRenewalTimestamp>1556090696963</lastRenewalTimestamp>
      <evictionTimestamp>0</evictionTimestamp>
      <serviceUpTimestamp>1556089288403</serviceUpTimestamp>
    </leaseInfo>
    <metadata>
      <management.port>8080</management.port>
    </metadata>
    <homePageUrl>http://DESKTOP-2Q068VO:8080/</homePageUrl>
    <statusPageUrl>http://DESKTOP-2Q068VO:8080/actuator/info</statusPageUrl>
    <healthCheckUrl>http://DESKTOP-2Q068VO:8080/actuator/health</healthCheckUrl>
    <vipAddress>service-one</vipAddress>
    <secureVipAddress>service-one</secureVipAddress>
    <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
    <lastUpdatedTimestamp>1556089288403</lastUpdatedTimestamp>
    <lastDirtyTimestamp>1556089286739</lastDirtyTimestamp>
    <actionType>ADDED</actionType>
  </instance>
</application>

其他的就不一一尝试了,大家可以自己创建eureka client 来测试相关的API,
需要注意的是 eureka client 必须是web工程

Eureka的核心类
作用
InstanceInfo代表注册的服务实例
LeaseInfo标识应用实例的租约信息
ServiceInstance包含一些通用的方法,包括优雅的关闭Eureka Client
InstanceStatus服务的状态
Eureka 的设计理念
服务实例如何注册到注册中心

本质上就是在服务启动的时候,需要调用Eureka Server的 REST API的register方法,去注册该应用实例的信息
对于java应用,可以使用Netflix的 Eureka Client封装的API去调用
对应springcloud应用,可以使用spring-cloud-starter-netflix-eureka-client,基于springboot的自动配置,帮你自动实现服务的注册

服务实例如何从注册中心剔除

正常情况在服务实例关闭应用时,应该通过钩子函数或者其他生命周期回调方法去调用Eureka Server 的REST API的de-register方法,来删除自身服务实例的信息
Eureka Server要求client定时续约,也就是发送心跳,如果超过一定时间没有进行续约操作,Server就会主动剔除,这一点Eureka Server使用的是心跳检测

分布式系统的CAP特性
  • Consistency : 数据一致性,可能由于网络故障等导致分布式系统中,数据多副本要保持数据不冲突
  • Availability : 在任何时候对集群进行操作,都能正常响应(可以再一定的延时内完成)
  • Partition Tolerance : 分区容忍性 ,发生通信故障的时候,整个集群被划分多个无法通信的分区时,集群仍然可用

对于分布式系统来说,由于网络的不可控,出现分区是不可避免的,所以分布式系统设计一般在AP或者CP中选择
Eureka是部署在AWS的背景下设计的,网络问题不可避免,所以选择AP
在实际生产中,服务注册中心保留可用及过期的数据总比丢失掉可用的数据要好,这样的话,集群的信息就不是强一致性的,这就需要客户端能够支持负载均衡和失败重试,在Netflix的生态中,由ribbon提供此功能

Peer to Peer架构

一般来说,分布式应用中多个副本的复制方式,可分为主从复制和对等复制

  • 主从复制

也就是最为常见的 master-slave模式
有一个主副本,其他都是从副本,对所有的写操作都提交到主副本,再由主副本同步到其他的从副本
写操作的压力都在主副本上,是整个系统的瓶颈,从副本可以分担读请求压力

  • 对等复制

副本之间不分主从,任何副本都可以进行读写操作,然后每个副本之间进行数据同步,不存在某一块陷入瓶颈
Eureka Server 采用的就是Peer to Peer模式
各个副本之间的数据同步和冲突解决是个大问题
peer节点之间的数据相互复制并不能一定成功,因此Eureka还通过实例于Server之间的心跳检测来进行数据的最终修复,即如果发现不一致,应用实例重新进行register操作

Eureka参数调优及监控
核心参数
  • client端基本参数
参数默认值说明
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.instance.prefer-ip-addressfalse是否优先使用ip地址来代替host name作为实例 hostname
eureka.instance.lease-expiration-duration-in-seconds90指定 Eureka Client间隔多久向Eureka Server发送心跳来告知Client是否存活
eureka.instance.metadata-map指定应用实例的元数据信息
eureka.client.on-demand-update-status-changetrue是否将本地实例状态的更新通过ApplicationInfoManager实时同步到Eureka Server
  • Client端 定时任务参数
参数默认值说明
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心跳线程HeartBeatThread线程池的大小
eureka.client.heartbeat-executor-thread-pool-size10调度任务执行超时下次调度延时时间
eureka.client.register-fetch-interval-seconds30CaCacheRefresh线程的调度频率
eureka.client.eureka-service-url-poll-interval-seconds5*60AsyncResolver.updateTask刷新Eureka Server地址的时间间隔
eureka.client.initial-instance-info-replication-interval-seconds40InstanceInfoReplication将实例信息变更同步到Eureka Server的初始延时时间
eureka.client.instance-info-replication-interval-seconds30InstanceInfoReplication将实例信息变更同步到Eureka Server的时间间隔
eureka.instance.lease-renewal-interval-in-seconds30Eureka Client向Eureka Server发送心跳的时间间隔
  • ** Client端 http参数**
参数默认值说明
eureka.client.eureka-server-connect-timeout5连接超时时间
eureka.client.eureka-server-read-timeout8读超时时间
eureka.client.eureka-server-total-connections200连接池最大活动数
eureka.client.eureka-server-total-connections-per-host50每个host能使用的最大连接数
eureka.client.eureka-connections-idle-timeout-seconds30连接池中连接的空闲时间
  • Server端基本参数
参数默认值说明
eureka.server.enable-self-preservationtrue是否开启自我保护模式
eureka.server.renewal-percent-threshold-timeout0.85指定每分钟需要收到的续约次数的阈值
eureka.instance.registry.expected-number-of-renews-per-min1指定每分钟需要收到的续约次数,实际数值被写死为count*2,另外也会被更新
eureka.server.renewal-threshold-update-interval-ms15分钟指定updateRenewalThreshold定时任务的调度频率来动态更新
eureka.server.evicition-interval-timer-in-ms60*1000指定Eviction Task定时任务的频率,用于剔除过期的实例
  • Server端 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的频率,只在response-cache设置为true才生效
eureka.server.response-cache-auto-expiration-in-seconds180设置readWriteCacheMap的expireAfterWrite参数,指定写入多久后过期
  • Server端 Peer参数
参数默认值说明
eureka.server.peer-eureka-nodes-update-interval-ms10分钟指定peerupdateTask的调度时间间隔,用于配置文件刷新peerEurekaNodes节点的配置信息
eureka.server.peer-eureka-status-refresh-time-interval-ms30*1000指定更新peer nodes状态更新的时间间隔
  • Server端 http参数

Eureka Server 需要和其他的peer节点进行通信,底层使用的是HTTPClient

参数默认值说明
eureka.server.peer-node-connect-timeout-ms200连接超时时间
eureka.server.peer-node-read-timeout-ms200读超时时间
eureka.server.peer-node-total-connections1000连接池最大活动数
eureka.server.peer-node-total-connections-per-host500每个host能使用的最大连接数
eureka.server.peer-node-connections-idle-timeout-seconds30连接池中连接的空闲时间
参数调优
  • 常见问题

为什么服务下线了,Eureka Server接口返回的信息还在
为什么服务上线了,Eureka Client不能及时收取
为什么有时候会出现

  • 解决办法
    • Eureka Server不是强一致性的,注册中心残留过期的实例信息是正常的

    应用实例会异常挂掉,没能在挂掉之前告诉Eureka Server要下线掉该服务实例信息,这个就需要依赖Eureka Server 的Eviction Task去剔除
    应用实例有告知Eureka Server下线,但是由于Eureka Server的REST API有response cache,所有需要等待缓存失效才能更新
    Eureka Server由于开启病引入了 SELF PRESERVATION 模式,导致registry信息不回因为过期而被清除,直到退出该模式

    • 针对Client下线没有通知Server的问题,可以调整Evictio Task的调度频率,比如将默认的60秒调整为5秒
    eureka.server.eviction-interval-timer-in-ms: 5000
    
    或者调整readWriteCacheMap的过期时间
    eureka.server.response.cache-auto-expiration-in-seconds:60
    
    或者关闭readOnlyCacheMap
    eureka.server.use-read-only-response-cache:false
    
    针对 SELF PRESERVATION 的问题,在测试环境可以将enable-self-preservation设置为false
    eureka.server.enable-self-preservation:false
    
    如果这样设置会提示
    在这里插入图片描述
    或者
    在这里插入图片描述

    这个地方有个很严重的问题
    在实际生产中,网络波动在所难免,经常会存在实例与Server之间的心跳检测未能如期,但是实例本身并没有问题,如果关闭了自我保护,会造成误判,甚至大面积的误判,导致服务列表的大部分注册信息被删除,无服务可用
    这也是Eureka 为什么引入SELF PRESERVATION,就是为了解决这一问题,当最近一分钟收到的续约次数小于指定阈值,就会关闭租约失效剔除,禁止定时任务剔除失效实例,从而保护注册信息,在生产环境可以把renewal-percent-threshold和lease-renewal-interval-in-seconds参数调小一些,从而提高触发SELF PRESERVATION的门槛

    eureka.instance.lease-renewal-interval-in-seconds:10    # 默认是30
    eureka.server.renewal-percent-threshold-timeout:0.49    # 默认是0.85
    
    • 针对新服务上线,Eureka Client获取不及时的问题,在测试环境可以提高Client端拉取注册信息的频率,比如将默认的30s改为5s
    eureka.clinet.registry-fetch-interval-seconds:5
    

    总结

    本章并无实际代码,主要对Eureka注册中心的介绍和相关参数的简介,欢迎补充和指错

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值