Spring Cloud 升级之路 - 2020.0.x - 4. 使用 Eureka 做为注册中心

Eureka 目前的状态:Eureka 目前 1.x 版本还在更新,可是应该不会更新新的功能了,只是对现有功能进行维护,升级并兼容所需的依赖。 Eureka 2.x 已经胎死腹中了。可是,这也不表明 Eureka 就是不能用了。若是你须要一个简便易于部署的注册中心,Eureka 仍是一个很好的选择。云服务环境中,基本上全部实例地址和微服务名称都在不断变化,也并不太须要 Eureka 所缺乏的持久化特性。当你的集群属于中小规模的时候(节点小于 1000 个), Eureka 依然是一个不错的选择。当你的集群很大的时候,Eureka 的同步机制可能就限制了他的表现。java

Eureka 的设计

Eureka 的设计比较小巧,没有复杂的同步机制,也没有复杂的持久化机制,集群关系只是简单的将收到的客户端请求转发到集群内的其余 Eureka 实例。Eureka 自己也只有注册中心的功能,不像其余种类的注册中心那样,将注册中心和配置中心合在一块儿,例如 Consul 和 nacos。node

Eureka 的交互流程以下git

image

首先,Service A 经过 Eureka Client 发送注册请求(Register)到同一可用区的 Eureka Server 1。以后经过发送心跳请求(Renew)到这个 Eureka Server 1. Eureka Server 1 收到这些请求的时候,会处理这些请求并将这些请求转发到其余的集群内的 Eureka Server 2 和 Eureka Server 3. Eureka Server 2 和 Eureka Server 3 不会再转发收到的 Eureka Server 1 转发过来的请求。而后,Service B 还有 Service C 经过 Eureka 获取到了 Service A 的位置,最后调用了 Service A。github

对于本地没有查询到的微服务,Eureka Server 还会从远程 Region 的 Eureka Server 去获取,例如这里对于 Service D,本地没有查到,Eureka Server 会返回远程 Region 的 Service D 的实例。因为本地有 Service A,因此确定不会返回远程 Region 的 Service A 的实例。而且,本地是定时拉取的远程 Region 的 Service 列表,并非每次查询的时候现查询的。spring

通常的,微服务之间的互相调用,并不通过 Eureka,也不会涉及到 Eureka 客户端了,而是经过负载均衡器调用,这个咱们后面就会提到。apache

Eureka 相关概念

这里咱们忽略全部的 AWS 相关的术语以及配置还有相关逻辑处理。缓存

Eureka 中的术语:服务器

  1. Eureka 实例:每一个注册到 Eureka 上面的实例就是 Eureka 实例
  2. Eureka 实例状态:包括 UP(能够处理请求),DOWN(健康检查失败,不能正常处理请求),STARTING(启动中,不能处理请求),OUT_OF_SERVICE(人为下线,暂时不处理请求),UNKNOWN(未知状态)。
  3. Eureka 服务器:做为注册中心运行,主要提供实例管理功能(处理实例注册(register)请求、处理实例注销(cancel)请求、处理实例心跳(renew)请求、内部处理实例过时(evict))、实例查询功能(各类查询实例信息的接口,例如经过 AppName 获取实例列表,经过实例 id 获取实例信息等等)
  4. Eureka 服务器集群:Eureka 服务器的集群,每一个 Eureka 服务器都配置了区域以及可用区,Eureka 服务器收到的客户端请求会转发到同一区域内的其余 Eureka 服务器,能够配置优先发到同一可用区的 Eureka 服务器。非同一区域内 Eureka 服务器,经过定时拉取的方式进行同步。
  5. Eureka 客户端:请求 Eureka 服务器的客户端。封装发送实例注册(register)请求、实例注销(cancel)请求和实例心跳(renew)请求。
  6. VIP(或者是 Virtual Hostname): Eureka 中能够经过两种方式获取实例,一个是经过服务名称,另外一种是经过 VIP。每一个实例都有服务名称,以及 VIP。Eureka 服务器中的索引方式是以服务名称为 key 的索引,咱们也能够经过遍历全部实例信息的方式经过 VIP 字符串匹配获取相关的实例。在 Spring Cloud 体系中,一个实例的 VIP、SVIP(其实就是 Secure VIP,即 https 的地址)以及服务名称都是 spring.application.name 指定的服务名称。

Eureka 相关配置

  1. Eureka 实例配置:Eureka 实例,每一个注册到 Eureka 上面的实例就是 Eureka 实例。Eureka 实例包含如下元素,以及相关配置:
    1. 基本信息:包括 IP,端口等访问这个 Eureka 实例所需的信息:
      eureka:
      instance:
      #通常不用咱们本身设置,EurekaInstanceConfigBean 的构造器会经过 InetUtils 获取 ip 地址
      #ip-address:
      #通常不用咱们本身设置,EurekaInstanceConfigBean 的构造器会经过 InetUtils 获取 hostname
      #hostname:
      #注册到 eureka 上面供其余实例访问的地址使用 ip 进行注册,其余实例会经过 ip 进行访问
      prefer-ip-address: true
      #不用设置 non-secure-port,自动使用 server.port 做为 non-secure-port
      #non-secure-port:
      #若是 secure-port-enabled 是 true,则会自动使用 server.port 做为 secure-port;咱们通常内部调用不用 ssl,因此不须要配置 secure-port
      #secure-port:
      #默认是启用 non-secure-port 的
      non-secure-port-enabled: true
      #默认是不启用 secure-port 的,咱们通常内部调用不用 ssl
      secure-port-enabled: false
      #个性化的实例id,包括 ip:微服务名称:端口
      instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      # app名称,不填写在 Spring-cloud-netflix 体系下默认就是 spring.application.name
      appname: ${spring.application.name}
      #app组名称归类用的,目前也没什么用
      app-group-name: common
      #实例命名空间,目前也没什么用
      namespace: public
    2. 基本连接信息:包括首页路径地址以及健康检查路径地址:
      eureka:
      instance:
      # 健康检查地址,默认是 /actuator/health
      health-check-url-path: /actuator/health
      # 实例状态地址,默认是 /actuator/info
      status-page-url-path: /actuator/info
      # 首页地址,默认是 /
      home-page-url-path: /
    3. 实例注册行为,即实例注册后的行为,以及心跳间隔等配置:
      eureka:
      instance:
      # 服务过时时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除
      # 注意,EurekaServer必定要设置eureka.server.eviction-interval-timer-in-ms不然这个配置无效
      # 这个配置通常为服务刷新时间配置的三倍
      # 默认90s
      lease-expiration-duration-in-seconds: 15
      #服务刷新时间配置,每隔这个时间会主动心跳一次
      #默认30s
      lease-renewal-interval-in-seconds: 5
      registry:
      #请参考 wait-time-in-ms-when-sync-empty 配置说明
      default-open-for-traffic-count: 1
      #初始指望发送心跳请求的实例个数,默认为1,在有新实例注册的时候,会 +1,有注销的时候会 -1,初始默认为 1 通常由于本身也注册到 eureka 上
      expected-number-of-clients-sending-renews: 1
      #实例注册后是否马上开始服务,默认为 false,通常注册后还须要作一些操做,因此注册实例的状态是 STARTING。后面改变状态后会更新为 UP
      instance-enabled-onit: false
    4. 实例元数据
      eureka:
      instance:
      #元数据map,咱们能够本身使用,放一些个性化的元数据,目前只有 configPath 和 zone 比较有用。 configPath 是使用 spring-cloud-config 的时候会设置 
      metadata-map:
      # spring cloud 体系中,可用区的配置放入元数据中,key 为 zone
      zone: zone1
  2. Eureka 客户端配置网络

    1. Eureka 服务器地址配置,能够直接指定连接,也能够经过 region 和 zone 进行配置,也能够经过 DNS 配置:
      eureka:
      instance:
      # 可用区列表,key 为 region,value 为 zone
      availability-zones:
      region1: zone1, zone2
      region2: zone3
      # 所在区域,经过这个读取 availability-zones 获取 zone,而后经过 zone 读取 service-url 获取对应的 eureka url
      # 这里的逻辑对应的类是 ConfigClusterResolver 和 ZoneAffinityClusterResolver
      region: region1
      # key 为 zone,value 为 eureka 连接,以逗号分隔
      service-url:
      # 默认eureka集群,这里必须是defaultZone,不能用-替换大写,与其余的配置不同,由于实在EurekaClientConfigBean里面写死的
      defaultZone: http://127.0.0.1:8211/eureka/
      zone1: http://127.0.0.1:8212/eureka/
      zone2: http://127.0.0.1:8213/eureka/
      zone3: http://127.0.0.1:8214/eureka/
      # 若是上面 eureka server 地址相关配置更新了,多久以后会从新读取感知到
      eureka-service-url-poll-interval-seconds: 300
      # 是否使用 dns 获取,若是指定了则经过下面的 dns 配置获取,而不是上面的 service-url
      use-dns-for-fetching-service-urls: false
      # dns 配置
      # eureka-server-d-n-s-name:
      # dns 配置的 eureka server 的 port
      # eureka-server-port:
      # dns 配置的 eureka server 的 port 后面的 uri 前缀 context
      # eureka-server-u-r-l-context:
      # 若是设置为 true,则同一个 zone 下的 eureka 会跑到前面优先访问。默认为 true
      prefer-same-zone-eureka: true
    2. 拉取服务实例信息相关配置app

      eureka:
      instance:
      # 是否从 eureka 上面拉取实例
      fetch-registry: true
      # 若是只想获取一个特定 virtual host name 的实例列表,就配置 registry-refresh-single-vip-address
      #registry-refresh-single-vip-address:
      # 客户端请求头指定服务端返回的实例信息是压缩的信息仍是完整信息,默认是完整信息
      # full, compact
      client-data-accept: full
      # eureka client 刷新本地缓存时间
      # 默认30s
      registry-fetch-interval-seconds: 5
      # eureka client 刷新本地缓存(定时拉取 eureka 实例列表)线程池大小,默认为 2
      cache-refresh-executor-thread-pool-size: 2
      # eureka client 刷新本地缓存(定时拉取 eureka 实例列表)线程池任务最大延迟时间,这个配置是定时拉取任务延迟(registry-fetch-interval-seconds)的倍数,默认 10 倍
      cache-refresh-executor-exponential-back-off-bound: 10
      # 是否禁用增量拉取,若是网络条件很差,能够禁用,每次都会拉取全量
      disable-delta: false
      # 只保留状态为 UP 的实例,默认为 true
      filter-only-up-instances: true
      #能够指定也从某些 region 拉取服务实例
      #fetch-remote-regions-registry:
      # 是否打日志记录每次拉取实例信息与当前缓存内的实例信息变化
      log-delta-diff: true
      
      #在spring cloud 环境中,DiscoveryClient 用的其实都是 CompositeDiscoveryClient,这个 CompositeDiscoveryClient 逻辑其实就是多个 DiscoveryClient 共存,先访问一个,没找到就经过下一个寻找
      #这个order决定了顺序,默认为 0
      order: 0
    3. 当前实例注册相关配置
      eureka:
      instance:
      # 是否将本身注册到 eureka 上面
      register-with-eureka: true
      # 是否在初始化的时候就注册到 eureka,通常设置为 false,由于实例还不能正常提供服务
      should-enforce-registration-at-init: false
      # 是否在关闭的时候注销实例,默认为 true
      should-unregister-on-shutdown: true
      # 是否对于实例状态改变动新进行限流,默认为 true
      on-demand-update-status-change: true
      # 实例信息同定时同步到 Eureka Server 的间隔时间。每隔这么长时间,检查实例信息(即eureka.instance配置信息)是否发生变化,若是发生变化,则同步到 Eureka Server,默认 30s
      # 主要检查两类信息,分别是服务地址相关信息,以及服务过时时间与刷新时间配置信息
      instance-info-replication-interval-seconds: 30
      # 实例信息同定时同步到 Eureka Server 的初始延迟时间,默认 40s
      initial-instance-info-replication-interval-seconds: 40
    4. http链接相关配置
      eureka:
      instance:
      # 代理相关配置
      # proxy-host:
      # proxy-port:
      # proxy-user-name:
      # proxy-password:
      # 是否对于发往 Eureka Server 的 http 请求启用 gzip,目前已通过期了,只要 Eureka Server 启用了 gzip,请求就是 gzip 压缩的
      g-zip-content: true
      # httpclient 的连接超时,默认 5s
      eureka-server-connect-timeout-seconds: 5
      # httpclient 的读取超时,默认 5s
      eureka-server-read-timeout-seconds: 8
      # httpclient 的空闲链接超时,默认 30s
      eureka-connection-idle-timeout-seconds: 30
      # httpclient 的总链接数量,默认 200
      eureka-server-total-connections: 200
      # httpclient 的每一个 host 的链接数量
      eureka-server-total-connections-per-host: 50
      # tls 相关配置,默认没有启用
      #      tls:
      #        enabled: false
      #        key-password:
      #        key-store:
      #        key-store-password:
      #        key-store-type:
      #        trust-store:
      #        trust-store-password:
      #        trust-store-type:
  3. Eureka 服务器配置
    1. 定时检查实例过时相关配置:实例注册后须要发送心跳证实这个实例是活着的, Eureka 服务器中也有定时任务检查实例是否已通过期:
      eureka:
      server:
      #主动检查服务实例是否失效的任务执行间隔,默认是 60s
      eviction-interval-timer-in-ms: 3000
      #这个配置在两个地方被使用:
      #若是启用用了自我保护,则会 renewal-threshold-update-interval-ms 指定的时间内,收到的心跳请求个数是否小于实例个数乘以这个 renewal-percent-threshold
      #定时任务检查过时实例,每次最多过时 1 - renewal-percent-threshold 这么多比例的实例
      renewal-percent-threshold: 0.85
    2. 自我保护相关配置:Eureka 服务器中有定时过时的任务,检查迟迟没有心跳的实例,并注销他们。自我保护主要针对集群中网络出现问题,致使有不少实例没法发送心跳致使不少实例状态异常,可是实际实例还在正常工做的状况,不要让这些实例不参与负载均衡:
      eureka:
      server: 
      #注意,最好全部的客户端实例配置的心跳时间相关的配置,是相同的。这样使用自我保护的特性最准确。
      #关闭自我保护
      #咱们这里不使用自我保护,由于:
      #自我保护主要针对集群中网络出现问题,致使有不少实例没法发送心跳致使不少实例状态异常,可是实际实例还在正常工做的状况,不要让这些实例不参与负载均衡
      #启用自我保护的状况下,就会中止对于实例的过时
      #可是,若是出现这种状况,其实也表明不少实例没法读取注册中心了。
      #而且还有一种状况就是,Eureka 重启。虽然不常见,可是对于镜像中其余的组件更新咱们仍是很频繁的
      #我倾向于从客户端对于实例缓存机制来解决这个问题,若是返回实例列表为空,则使用上次的实例列表进行负载均衡,这样既能解决 Eureka 重启的状况,又能处理一些 Eureka 网络隔离的状况
      #自我保护模式基于每分钟须要收到 renew (实例心跳)请求个数,若是启用了自我保护模式,只有上一分钟接收到的 renew 个数,大于这个值,实例过时才会被注销
      enable-self-preservation: false
      # 每分钟须要收到 renew (实例心跳)请求个数是须要动态刷新的,这个刷新间隔就是 renewal-threshold-update-interval-ms
      #更新流程大概是:计算当前一共有多少实例,若是大于以前指望的实例量 * renewal-percent-threshold(或者没开启自我保护模式),则更新指望的实例数量为当前一共有多少实例
      #以后根据指望的实例数量,计算指望须要收到的实例心跳请求个数 = 指望的实例数量 * (60 / expected-client-renewal-interval-seconds) * renewal-percent-threshold
      #公式中 60 表明一分钟,由于公式用到了 expected-client-renewal-interval-seconds,也就是实例平均心跳间隔,为了使这个公式准确,最好每一个实例配置同样的心跳时间
      #默认 900000ms = 900s = 15min
      renewal-threshold-update-interval-ms: 900000
      #上面提到的实例平均心跳间隔,或者说是指望的心跳间隔,为了使这个公式准确,最好每一个实例配置同样的心跳时间
      #默认 30s
      expected-client-renewal-interval-seconds: 30
      #这个配置在两个地方被使用:
      #若是启用用了自我保护,则会 renewal-threshold-update-interval-ms 指定的时间内,收到的心跳请求个数是否小于实例个数乘以这个 renewal-percent-threshold
      #定时任务检查过时实例,每次最多过时 1 - renewal-percent-threshold 这么多比例的实例
      renewal-percent-threshold: 0.85
    3. 同一区域内集群配置相关:上面咱们提到了,同一区域内的 Eureka 服务器实例,收到的客户端请求,会转发到同一区域内的的其余 Eureka 服务器实例。同时,在某一 Eureka 服务器实例启动的时候,会从同一区域内其余 Eureka 服务器同步实例列表。而且,转发到其余 Eureka 服务器实例是异步转发的,这就有专门的线程池进行转发。同时,转发的也是 HTTP 请求,这就须要 HTTP 链接池:
      eureka:
      server: 
      #Eureka Server 从配置中更新同一区域内的其余 Eureka Server 实例列表间隔,默认10分钟
      peer-eureka-nodes-update-interval-ms: 600000
      #启动时从其余 Eureka Server 同步服务实例信息的最大重试次数,直到实例个数不为 0,默认为 0,这样其实就是不一样步
      registry-sync-retries: 0
      #启动时从其余 Eureka Server 同步服务实例信息重试间隔
      registry-sync-retry-wait-ms: 30000
      #集群内至少有多少个 UP 的 Eureka Server 实例数量,当前 Eureka Server 状态为 UP。默认 -1,也就是 Eureka Server 状态不考虑 UP 的集群内其余 Eureka Server 数量。
      min-available-instances-for-peer-replication: -1
      #请求其余实例任务的最大超时时间,默认 30 秒
      max-time-for-replication: 30000
      #用来处理同步任务的线程数量,有两个线程池,一个处理批量同步任务,默认大小为20
      max-threads-for-peer-replication: 20
      #另外一个处理非批量任务(若是没用 AWS Autoscaling 对接相关特性则没有啥用),默认大小为20
      max-threads-for-status-replication: 20
      #处理批量任务的线程池队列长度,默认为 10000
      max-elements-in-peer-replication-pool: 10000
      #处理非批量任务的线程池队列长度,默认为 10000
      max-elements-in-status-replication-pool: 10000
      #Eureka Server 经过 httpclient 访问其余 Eureka Server 同步实例,httpclient 的链接超时,默认 200ms
      peer-node-connect-timeout-ms: 200
      #httpclient 的读取超时,默认 200ms,通常不用太长
      peer-node-read-timeout-ms: 200
      #httpclient 的最大总链接数量,默认 1000
      peer-node-total-connections: 1000
      #httpclient 的对于某一 host 最大总链接数量,默认 500
      peer-node-total-connections-per-host: 500
      #httpclient 的链接空闲保持时间,默认 30s
      peer-node-connection-idle-timeout-seconds: 30
    4. 跨区域相关配置。Eureka 服务器会定时拉取其余区域的服务实例列表缓存在本地。在查询本地查询不到某个微服务的时候,就会查询这个远程区域服务实例的缓存。相关配置以下:
      eureka:
      server: 
      #请求其余 Region 的 httpclient 的链接超时,默认 1000ms
      remote-region-connect-timeout-ms: 1000
      #请求其余 Region 的 httpclient 的读取超时,默认 1000ms
      remote-region-read-timeout-ms: 1000
      #请求其余 Region 的 httpclient 的最大总链接数量,默认 1000
      remote-region-total-connections: 1000
      #请求其余 Region 的 httpclient 的对于某一 host 最大总链接数量,默认 500
      remote-region-total-connections-per-host: 500
      #请求其余 Region 的 httpclient 的链接空闲保持时间,默认 30s
      remote-region-connection-idle-timeout-seconds: 30
      #请求其余 Region 的 http 请求是否开启 gzip,对于其余 Region 咱们认为网络链接是比较慢的,因此默认开启压缩
      g-zip-content-from-remote-region: true
      #    remote-region-urls-with-name:
      #      region2eureka1: http://127:0:0:1:8212/eureka/
      #      region2eureka2: http://127:0:0:1:8213/eureka/
      #    remote-region-app-whitelist:
      #若是须要从其余 Region 获取实例信息,这个获取间隔,默认为 30s
      remote-region-registry-fetch-interval: 30
      #若是须要从其余 Region 获取实例信息,这个任务的线程池,默认为 20个
      remote-region-fetch-thread-pool-size: 20

启动一个 Eureka Server

启动一个 Eureka 注册中心服务器很是简单,咱们这里使用的是 Spring Cloud 封装好的启动包。Eureka 1.x 的 Eureka Server 是纯基于 servlet 的应用。为了与 Spring Cloud 结合使用,须要粘合模块,这就是 spring-cloud-netflix-eureka-server。在 spring-cloud-netflix-eureka-server 中,也有一个和 com.netflix.eureka.EurekaBootStrap 代码很相似的启动类,即 org.springframework.cloud.netflix.eureka.server.EurekaServerBootstrap。在咱们启动 EurekaServer 实例的时候,只用加入对于 spring-cloud-starter-eureka-server 的依赖便可。以后经过 @EnableEurekaServer 注解便可启动一个 Eureka 服务器实例。

Eureka Server 的依赖:

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-iiford</artifactId>
        <groupId>com.github.hashjang</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-cloud-iiford-eureka-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.github.hashjang</groupId>
            <artifactId>spring-cloud-iiford-service-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
</project>

Eureka Server 的配置:
参考咱们上面的配置便可:
application.yml

Eureka Server 的启动类:
EurekaServerApplication.java

package com.github.hashjang.iiford.eureka.server;

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);
    }
}
相关文章
相关标签/搜索