Eureka使用介绍

Eureka采用的是Server/Client的模式进行设计。Server扮演了服务注册中心的角色,为Client提供服务注册和发现的功能,维护着注册到自身的Client的相关信息,同时提供接口给Client获取到注册表中其他服务的信息。Client将有关自己的服务的信息通过一定的方式登记到Server上,并在正常范围内维护自己信息的一致性,方便其他服务发现自己,同时可以通过Server获取到自己的依赖的其他服务信息,从而完成服务调用。

Eureka功能主要包括:服务注册、服务续约、服务剔除、服务下线、获取注册表信息、远程调用等。

以下是Eureka几个角色的解释:

Eureka服务端:负责服务注册、发现并管理每项服务的中心。

Eureka实例:服务(如订单系统)部署多个服务器,每个服务器上提供的服务都是实例。

Eureka服务:指提供特定服务功能的服务,例如:订单系统,同一服务可以提供多个实例;

Eureka客户端:主要向服务中心注册自己成为服务。但它既可以是服务提供者,也可以是消费者。它与Eureka实例感觉相似,但实际上意义不同。

Eureka Client和Eureka Server的依赖:

Eureka Client(服务提供方和服务调用方)

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

Eureka Server(注册中心)

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

一、可配置项

Eureka Client

从META-INF/spring-configuration-metadata.json总可以看出客户端可以配置哪些前缀

  • name:就是配置文件可配置的前缀
  • type:就是具体的配置类
  • sourceType和sourceMethod就是实例化对象的配置,可能是直接在类上加注解托管到Spring容器,也可能是使用new一个对象,使用@Bean托管到Spring。
  • properties就是每个前缀可配置的属性说明

从上面我们可以知道Eureka Client可配置的前缀有:

eureka.client
eureka.client.tls
eureka.client.transport
eureka.instance
spring.cloud.loadbalancer.eureka

eureka.client配置项

eureka:
  client:
    #服务器是否能够重定向客户端请求到备份服务器。
    #如果设置为false,服务器将直接处理请求,
    #如果设置为true,它可能发送HTTP重定向到客户端。默认为false
    allow-redirects: false
    #获取实例所在的地区下可用性的区域列表,用逗号隔开。
    availability-zones: zone1,zone2
    #获取实现了eureka客户端在第一次启动时读取注册表的信息作为回退选项的实现名称
    backup-registry-impl: ""
    #执行程序指数回退刷新的相关属性,是重试延迟的最大倍数值,默认为10
    cache-refresh-executor-exponential-back-off-bound: 10
    #执行程序缓存刷新线程池的大小,默认为5
    cache-refresh-executor-thread-pool-size: 2
    #客户端数据接收的名称????
    client-data-accept: full
    #这是一个短暂的解码器的配置,如果最新的解码器是稳定的,则可以去除,默认为null
    decoder-name: null
    #指示eureka客户端是否禁用增量提取
    disable-delta: false
    #eureka服务器序列化/反序列化的信息中获取“$”符号的替换字符串。默认为“_-”
    dollar-replacement:
    #该客户端是否可用
    enabled: true
    #编码器名称
    encoder-name: ""
    #eureka服务器序列化/反序列化的信息中获取“_”符号的的替换字符串。默认为“__“
    escape-char-replacement:
    #连接到 Eureka Server 空闲连接的超时时间(s),默认30
    eureka-connection-idle-timeout-seconds: 30
    #连接Eureka Server 超时时间(s),默认5秒
    eureka-server-connect-timeout-seconds: 5
 
    #***********DNS***************
    #获取要查询的DNS名称来获得eureka服务器,此配置只有在eureka服务器ip地址列表是在DNS中才会用到。默认为null
    eureka-server-d-n-s-name:
    #获取eureka服务器的端口,此配置只有在eureka服务器ip地址列表是在DNS中才会用到。默认为null
    eureka-server-port:
    #表示eureka注册中心的路径,
    #如果配置为eureka,则为http://ip:port/eureka/,
    #在eureka的配置文件中加入此配置表示eureka作为客户端向注册中心注册,从而构成eureka集群。此配置只有在eureka服务器ip地址列表是在DNS中才会用到,默认为null
    eureka-server-u-r-l-context: "eureka"
    #指示eureka客户端是否应使用DNS机制来获取要与之通信的eureka服务器列表。
    #当DNS名称更新为具有其他服务器时,eureka客户端轮询eurekaServiceUrlPollIntervalSeconds中指定的信息后立即使用该信息。
    use-dns-for-fetching-service-urls: false
 
 
    #读取Eureka Server 超时时间(s),默认8秒
    eureka-server-read-timeout-seconds: 8
    #获取从eureka客户端到所有eureka服务器的连接总数,默认200个
    eureka-server-total-connections: 200
    #获取从eureka客户端到eureka服务器主机允许的连接总数,默认50个
    eureka-server-total-connections-per-host: 50
    #询问Eureka Server信息变化的时间间隔(s),默认为300秒
    eureka-service-url-poll-interval-seconds: 300
    #客户端是否获取eureka服务器注册表上的注册信息,默认为true
    fetch-registry: true
    #eureka服务注册表信息里的以逗号隔开的地区名单,如果不这样返回这些地区名单,则客户端启动将会出错。默认为null
    fetch-remote-regions-registry:
    #是否过滤掉,非UP的实例。默认为true
    filter-only-up-instances: true
    #当服务端支持压缩的情况下,是否支持从服务端获取的信息进行压缩。默认为true
    g-zip-content: true
    #心跳执行程序回退相关的属性,是重试延迟的最大倍数值,默认为10
    heartbeat-executor-exponential-back-off-bound: 10
    #心跳保持线程池初始化线程数,默认2个
    heartbeat-executor-thread-pool-size: 2
    #是否开启健康检查
    healthcheck:
      enabled: true
    #是否记录eureka服务器和客户端之间在注册表的信息方面的差异,默认为false
    log-delta-diff: false
    #客户端的状态更新到远程服务器上,默认为true
    on-demand-update-status-change: true
    #客户端优先级
    order: 0
    #实例是否使用同一zone里的eureka服务器,默认为true,理想状态下,eureka客户端与服务端是在同一zone下
    prefer-same-zone-eureka: true
    #获取此实例所在的区域
    region: "us-east-1"
    #自动刷新开启
    refresh:
      enable: true
    #是否注册到eureka
    register-with-eureka: true
    #从eureka服务器获取注册表信息的频率,默认30秒
    registry-fetch-interval-seconds: 30
    #此客户端只对单一的VIP注册表的信息感兴趣。默认为null
    registry-refresh-single-vip-address:
    #与Eureka注册服务中心的通信zone和url地址,分区时使用,一般默认使用defaultZone
    service-url:
      defaultZone: http://ip:port/eureka/,http://ip:port/eureka/
      Zone1: http://ip:port/eureka/,http://ip:port/eureka/
    #client是否在初始化阶段强行注册到服务中心,默认为false
    should-enforce-registration-at-init: false
    #client在shutdown情况下,是否显示从注册中心注销,默认为true
    should-unregister-on-shutdown: true
    #更新实例信息的变化到Eureka服务端的间隔时间,(s)
    instance-info-replication-interval-seconds: 30
    #初始化实例信息到Eureka服务端的间隔时间,(s)
    initial-instance-info-replication-interval-seconds: 40
 
    #**********codec-解析器*************
    property-resolver:
 
    #**********proxy-代理*************
    #获取eureka server 的代理主机名
    proxy-host:
    #获取eureka server 的代理主机密码
    proxy-password:
    #获取eureka server 的代理主机端口
    proxy-port:
    #获取eureka server 的代理用户名
    proxy-user-name:

eureka.instance配置项

eureka:
  instance:
    #***********instance-属性*****************
    #注册到注册中心的应用所属分组名称
    app-group-name:
    #*注册到注册中心的应用名称
    appname: unknown
    #指定服务实例所属数据中心
    data-center-info:
    #默认地址解析顺序
    default-address-resolution-order:
    #该服务实例环境配置,默认test
    environment: test
    #*该服务实例所在主机名
    hostname:
    #*该服务实例在注册中心的唯一实例ID
    instance-id:
    #*该服务实例的IP地址
    ip-address:
    #该服务实例注册到Eureka Server 的初始状态
    initial-status: up
    #指示是否应在eureka注册后立即启用实例以获取流量
    instance-enabled-onit: false
    #表示eureka client发送心跳给server端的频率,默认30秒
    #如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。
    #除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
    lease-renewal-interval-in-seconds: 30
    #表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,默认90秒
    #在这个时间内若没收到下一次心跳,则将移除该instance。
    #如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。
    #如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。该值至少应该大于
    lease-expiration-duration-in-seconds: 90
    #自定义的元数据,key/value都可以随便写。
    metadata-map:
      myKey: myvalue
    #获取用于查找属性的命名空间。 在Spring Cloud中被忽略。
    namespace: eureka
    #http通信端口
    non-secure-port: 80
    #是否启用HTTP通信端口
    non-secure-port-enabled: true
    #*是否优先使用服务实例的IP地址,相较于hostname
    prefer-ip-address: false
    registry:
      #默认与eureka server开启通信的数量
      default-open-for-traffic-count: 1
      #每分钟向eureka server的续约次数
      expected-number-of-clients-sending-renews: 1
      
    #*********check-健康检查*************
    #该服务实例的健康检查地址(url),绝对地址
    health-check-url:
    #该服务实例的健康检查地址,相对地址
    health-check-url-path: /actuator/health
    #该服务实例的主页地址(url),绝对地址
    home-page-url:
    #该服务实例的主页地址,相对地址
    home-page-url-path: /
    #该服务实例的状态检查地址(url),绝对地址
    status-page-url:
    #该服务实例的状态检查地址,相对地址
    status-page-url-path: /actuator/info
 
    #**************https****************
    #该服务实例安全健康检查地址(URL),绝对地址
    secure-health-check-url:
    #HTTPS通信端口
    secure-port: 443
    #是否启用HTTPS通信端口
    secure-port-enabled: false
    #服务实例安全主机名称(HTTPS)
    secure-virtual-host-name: unknown
    #该服务实例非安全注解名称(HTTP)
    virtual-host-name: unknown
 
    #***********AWS***************
    #注册到注册中心的应用所属分组名称(AWS服务器)
    a-s-g-name: ""
Eureka Server
eureka:
  server:
    #************node-节点**************
    #服务端开启自我保护模式,前面章节有介绍
    enable-self-preservation: true
    #清除无效服务实例的时间间隔,默认1分钟
    eviction-interval-timer-in-ms: 60000
    #客户端续约间隔,用于计算每分钟续约数Renews threshold
    expected-client-renewal-interval-seconds: 30
    #请求频率限制器
    rate-limiter-burst-size: 1
    #是否开启请求频率限制器
    rate-limiter-enabled: false
    #请求频率的平均值
    rate-limiter-full-fetch-average-rate: 100
    #设置信任的client list
    rate-limiter-privileged-clients:
    #注册服务、拉去服务列表数据的请求频率的平均值
    rate-limiter-registry-fetch-average-rate: 500
    #是否对标准的client进行频率请求限制。如果是false,则只对非标准client进行限制
    rate-limiter-throttle-standard-clients: false
    #在服务节点启动时,eureka尝试获取注册信息的次数
    registry-sync-retries: 0
    #在服务节点启动时,eureka多次尝试获取注册信息的间隔时间
    registry-sync-retry-wait-ms: 30000
    #Eureka服务器是否应该登录clientAuthHeaders,默认为true
    log-identity-headers: true
    #允许备份到备份池的最大复制事件数量。而这个备份池负责除状态更新的其他事件。可以根据内存大小,超时和复制流量,来设置此值得大小
    max-elements-in-peer-replication-pool: 10000
    #允许备份到状态备份池的最大复制事件数量
    max-elements-in-status-replication-pool: 10000
    #在设置的时间范围类,期望与client续约的百分比。
    renewal-percent-threshold: 0.85
    #多长时间更新续约的阈值,默认15分钟
    renewal-threshold-update-interval-ms: 900000
    #对于缓存的注册数据,多长时间过期,3分钟
    response-cache-auto-expiration-in-seconds: 180
    #多长时间更新一次缓存中的服务注册数据,30秒
    response-cache-update-interval-ms: 30000
    #缓存增量数据的时间,以便在检索的时候不丢失信息,默认3分钟
    retention-time-in-m-s-in-delta-queue: 180000
    #当时间戳不一致的时候,是否进行同步
    sync-when-timestamp-differs: false
    #*是否采用只读缓存策略,只读策略对于缓存的数据不会过期。
    use-read-only-response-cache: true
    #当eureka server启动的时候,不能从对等节点获取instance注册信息的情况,应等待多长时间。5分钟
    wait-time-in-ms-when-sync-empty: 300000
    my-url:
 
    #************peer-集群**************
    #指示群集节点之间的复制是否应批处理以提高网络效率。
    batch-replication: false
    #间隔多长时间,清除过期的 delta 数据
    delta-retention-timer-interval-in-ms: 30000
    #是否开启禁用增量功能,默认为false
    disable-delta: false
    #增量信息是否可以提供给客户端或一些远程地区,默认为false
    disable-delta-for-remote-regions: false
    #如果在远程区域本地没有实例运行,对于应用程序回退的旧行为是否被禁用, 默认为false
    disable-transparent-fallback-to-other-region: false
    #复制的数据在发送请求时是否被压缩
    enable-replicated-request-compression: false
    #eureka服务器中获取的内容是否在远程地区被压缩
    g-zip-content-from-remote-region: false
    #用于定义二级响应缓存的容量大小,默认1000
    initial-capacity-of-response-cache: 1000
    #复制线程可以保持存活的空闲时间,默认为15分钟
    max-idle-thread-age-in-minutes-for-peer-replication: 15
    #状态复制线程可以保持存活的空闲时间,默认为10分钟
    max-idle-thread-in-minutes-age-for-status-replication: 10
    #获取将被用于复制线程的最大数目,默认为20
    max-threads-for-peer-replication: 20
    #被用于状态复制的线程的最大数目,默认为1
    max-threads-for-status-replication: 1
    #尝试在丢弃复制事件之前进行复制的时间,默认为30000毫秒
    max-time-for-replication: 30000
    #正常的对等服务instance最小数量。-1表示服务中心为单节点。
    min-available-instances-for-peer-replication: -1
    #获取将被用于复制线程的最小数目,默认为5
    min-threads-for-peer-replication: 5
    #被用于状态复制的线程的最小数目,默认为1
    min-threads-for-status-replication: 1
    #获取集群里服务器尝试复制数据的次数,默认为5
    number-of-replication-retries: 5
    #eureka server更新集群节点间隔时间,默认10分钟,集群节点发送变化时使用。
    peer-eureka-nodes-update-interval-ms: 60000
    #eureka服务状态的相互更新的时间间隔。
    peer-eureka-status-refresh-time-interval-ms: 30000
    #eureka对等节点间连接超时时间
    peer-node-connect-timeout-ms: 200
    #eureka对等节点连接后的空闲时间
    peer-node-connection-idle-timeout-seconds: 30
    #eureka服务节点间的读数据连接超时时间,会一致进行重试,如果过小容易造成占用cpu过高
    peer-node-read-timeout-ms: 200
    #eureka server 节点间连接的总共最大数量
    peer-node-total-connections: 1000
    #eureka server 节点间连接的单机最大数量
    peer-node-total-connections-per-host: 500
 
    #**************remote-远程******************
    #必须通过远程区域中检索的应用程序的列表
    remote-region-app-whitelist:
    #连接到对等远程地eureka节点的超时时间,默认为1000毫秒
    remote-region-connect-timeout-ms: 1000
    #http连接被清理之后远程地区服务器的空闲时间,默认为30秒
    remote-region-connection-idle-timeout-seconds: 30
    #用于执行远程区域注册表请求的线程池的大小,默认为20
    remote-region-fetch-thread-pool-size: 20
    #获取从远程地区eureka节点读取信息的超时时间,默认为1000毫秒
    remote-region-read-timeout-ms: 1000
    #从远程区域取出该注册表的信息的时间间隔,默认为30秒
    remote-region-registry-fetch-interval: 30
    #获取远程地区对等节点上http连接的总数,默认为1000
    remote-region-total-connections: 1000
    #获取远程地区特定的对等节点上http连接的总数,默认为500
    remote-region-total-connections-per-host: 500
    #用来合格请求远程区域注册表的信任存储文件,默认为空
    remote-region-trust-store: ""
    #获取偏远地区信任存储文件的密码,默认为“changeit”
    remote-region-trust-store-password: changeit
    #远程地区的URL列表
    remote-region-urls: 11
    #针对远程地区发现的网址域名的map
    remote-region-urls-with-name:
 
    #**************codec-解析器******************
    #如果没有设置默认的编解码器将使用xml编解码器,获取的是编码器的类名称
    xml-codec-name:
    #如果没有设置默认的编解码器将使用全JSON编解码器,获取的是编码器的类名称
    json-codec-name:
    #属性解析器
    property-resolver:
 
    #************AWS-节点**************
    #AWS缓存时间
    a-s-g-cache-expiry-timeout-ms: 60000
    #从AWS上更新ASG信息的时间间隔,单位为毫秒
    a-s-g-update-interval-ms: 300000
    #查询AWS上ASG(自动缩放组)信息的超时值,单位为毫秒,默认为300
    a-s-g-query-timeout-ms: 300
    #获取aws访问的id,主要用于弹性ip绑定,此配置是用于aws上的,默认为null
    a-w-s-access-id:
    #获取aws私有秘钥,主要用于弹性ip绑定,此配置是用于aws上的,默认为null
    a-w-s-secret-key:
    #aws获取配置绑定EIP或Route53的策略。
    binding-strategy: eip
    #获取服务器尝试绑定到候选的EIP的次数,默认为3
    e-i-p-bind-rebind-retries: 3
    #与上面的是同一作用,仅仅是稳定状态检查,默认为5 * 60 * 1000
    e-i-p-binding-retry-interval-ms: 300000
    #服务器检查ip绑定的时间间隔,单位为毫秒,
    e-i-p-binding-retry-interval-ms-when-unbound: 60000
    #用来描述从AWS第三账户的自动缩放组中的角色名称,默认为“ListAutoScalingGroups”
    list-auto-scaling-groups-role-name: ListAutoScalingGroups
    #对AWS集群中服务器节点的准备连接,默认为true
    prime-aws-replica-connections: true
    #AmazonRoute 53是一项高可用性及高可扩展性域名服务
    #服务器尝试绑定到候选Route53域的次数,默认为3
    route53-bind-rebind-retries: 3
    #服务器应该检查是否和Route53域绑定的时间间隔,默认为5分钟
    route53-binding-retry-interval-ms: 300000
    #用于建立route53域的ttl,默认为30
    route53-domain-t-t-l: 30

二、工作原理

Eureka工作流程
  • Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息。
  • Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务。
  • Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常。
  • 当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例。
  • 单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端。
  • 当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式。
  • Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地。
  • 服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存。
  • Eureka Client 获取到目标服务器信息,发起服务调用。
  • Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除。
Eureka的自我保护

默认情况下,如果 Eureka Server 在一定的 90s 内没有接收到某个微服务实例的心跳,会注销该实例。但是在微服务架构下服务之间通常都是跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,网络分区故障,导致此实例被注销。

固定时间内大量实例被注销,可能会严重威胁整个微服务架构的可用性。为了解决这个问题,Eureka 开发了自我保护机制,那么什么是自我保护机制呢?

Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 即会进入自我保护机制。

Eureka Server 进入自我保护机制,会出现以下几种情况:

  • Eureka 不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
  • Eureka 仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)。
  • 当网络稳定时,当前实例新的注册信息会被同步到其它节点中。

Eureka 自我保护机制是为了防止误杀服务而提供的一个机制。当个别客户端出现心跳失联时,则认为是客户端的问题,剔除掉客户端;当 Eureka 捕获到大量的心跳失败时,则认为可能是网络问题,进入自我保护机制;当客户端心跳恢复时,Eureka 会自动退出自我保护机制。

如果在保护期内刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,即会调用失败。对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等。

通过在 Eureka Server 配置如下参数,开启或者关闭保护机制,生产环境建议打开:

eureka.server.enable-self-preservation=true
Eureka的缓存机制

Eureka Server 在运行期间就是一个普通的 Java 项目,并没有使用数据库之类的存储软件,那么在运行期间是如何存储数据的呢?

Eureka Server 的数据存储分了两层:数据存储层和缓存层。数据存储层记录注册到 Eureka Server 上的服务信息,缓存层是经过包装后的数据,可以直接在 Eureka Client 调用时返回。

数据存储层的数据结构

Eureka Server 的数据存储层是双层的 ConcurrentHashMap,我们知道 ConcurrentHashMap 是线程安全高效的 Map 集合。

private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();

第一层的 ConcurrentHashMap 的 key=spring.application.name 也就是客户端实例注册的应用名;value 为嵌套的 ConcurrentHashMap。

第二层嵌套的 ConcurrentHashMap 的 key=instanceId 也就是服务的唯一实例 ID,value 为 Lease 对象,Lease 对象存储着这个实例的所有注册信息,包括 ip 、端口、属性等。

根据这个存储结构我们可以发现,Eureka Server 第一层都是存储着所有的服务名,以及服务名对应的实例信息,最终的数据结构如下:

缓存层的结构

Eureka Server 为了提供响应效率,提供了两层的缓存结构,将 Eureka Client 所需要的注册信息,直接存储在缓存结构中。

第一层缓存:readOnlyCacheMap,本质上是 ConcurrentHashMap,依赖定时从 readWriteCacheMap 同步数据,默认时间为 30 秒。

readOnlyCacheMap : 是一个只读缓存,这个主要是为了供客户端获取注册信息时使用,其缓存更新,依赖于定时器的更新,通过和 readWriteCacheMap 的值做对比,如果数据不一致,则以 readWriteCacheMap 的数据为准。

第二层缓存:readWriteCacheMap,本质上是 Guava 缓存。

readWriteCacheMap:readWriteCacheMap 的数据主要同步于存储层。当获取缓存时判断缓存中是否没有数据,如果不存在此数据,则通过 CacheLoader 的 load 方法去加载,加载成功之后将数据放入缓存,同时返回数据。

readWriteCacheMap 缓存过期时间,默认为 180 秒,当服务下线、过期、注册、状态变更,都会来清除此缓存中的数据。

Eureka Client 获取全量或者增量的数据时,会先从一级缓存中获取;如果一级缓存中不存在,再从二级缓存中获取;如果二级缓存也不存在,这时候先将存储层的数据同步到缓存中,再从缓存中获取。

通过 Eureka Server 的二层缓存机制,可以非常有效地提升 Eureka Server 的响应时间,通过数据存储层和缓存层的数据切割,根据使用场景来提供不同的数据支持。

缓存设计带来的一些思考

除了 Eureka Server 端存在缓存外,Eureka Client 也同样存在着缓存机制,Eureka Client 启动时会全量拉取服务列表,启动后每隔 30 秒从 Eureka Server 量获取服务列表信息,并保持在本地缓存中。

Eureka Client 增量拉取失败,或者增量拉取之后对比 hashcode 发现不一致,就会执行全量拉取,这样避免了网络某时段分片带来的问题,同样会更新到本地缓存。

同时对于服务调用,如果涉及到 ribbon 负载均衡,那么 ribbon 对于这个实例列表也有自己的缓存,这个缓存定时(默认30秒)从 Eureka Client 的缓存更新。

这么多的缓存机制可能就会造成一些问题,一个服务启动后可能最长需要 90s 才能被其它服务感知到:

  • 首先,Eureka Server 维护每 30s 更新的响应缓存。
  • Eureka Client 对已经获取到的注册信息也做了 30s 缓存。
  • 负载均衡组件 Ribbon 也有 30s 缓存。

这三个缓存加起来,就有可能导致服务注册最长延迟 90s ,这个需要我们在特殊业务场景中注意其产生的影响。

三、单点模式

Eureka Server

1、引入依赖

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

2、application.properties配置

server.port=9090

server.servlet.context-path=/os

# eureka服务端的实例名
eureka.instance.hostname=localhost

# 不在注册中心注册自己
eureka.client.register-with-eureka=false
# 表示自己是注册中心,不需要检索服务
eureka.client.fetch-registry=false
# 服务地址,在这里标识注册中心的url
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/${server.servlet.context-path}/eureka


#是否开启自我保护机制
eureka.server.enable-self-preservation=true

3、在启动类上添加@EnableEurekaServer注解

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

}
Eureka Client

1、 添加依赖

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

注意:仅加eureka-client依赖并不一个web应用,所以需要再加一个依赖spring-boot-starter-web。

2、application.properties配置

server.port=8090
spring.application.name=eureka-client

eureka.instance.hostname=localhost eureka.instance.instance-id=ins_client

#要注册 eureka.client.register-with-eureka=true #要检索服务 eureka.client.fetch-registry=true #读取Eureka Server 超时时间(s) eureka.client.eureka-server-read-timeout-seconds=30 #连接 Eureka Server的超时时间,单位为秒。 eureka.client.eureka-server-connect-timeout-seconds=30 #从 Eureka 服务端获取注册信息的间隔时间,单位为秒。 eureka.client.registry-fetch-interval-seconds=120 #更新实例信息的变化到 Eureka 服务端的间隔时间,单位为秒。 eureka.client.instance-info-replication-interval-seconds=120 #注册地址 eureka.client.service-url.defaultZone=http://localhost:9090/os/eureka

3、 在启动类上添加@EnableDiscoveryClient或@EnableEurekaClient注解

@EnableDiscoveryClient
//@EnableEurekaClient
@SpringBootApplication
public class EurekaClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApplication.class, args);
    }
}

四、集群模式

集群的实现方式就是Eureka Server相互注册

Eureka Server

我们在单点模式的基础上再加一个EurekaServer。

为了模拟不同服务器之间的集群,先在windows/system32/drivers/etc中修改hosts文件:

第一个eureka server 配置如下:

server.port=9090

server.servlet.context-path=/os

# eureka服务端的实例名
eureka.instance.hostname=localhost

# 不在注册中心注册自己
eureka.client.register-with-eureka=false
# 表示自己是注册中心,不需要检索服务
eureka.client.fetch-registry=false
# 服务地址,在这里标识注册中心的url
eureka.client.service-url.defaultZone=http://eureka9091.com:9091/os/eureka


#是否开启自我保护机制
eureka.server.enable-self-preservation=true
#eureka服务节点间的读数据连接超时时间,会一直进行重试,如果过小容易造成占用cpu过高
eureka.server.peer-node-read-timeout-ms=1000

注意:eureka.client.service-url.defaultZone是其他Eureka server的地址,如果有多个用逗号分隔。

第二个eureka server配置如下

server.port=9091

server.servlet.context-path=/os

# eureka服务端的实例名
eureka.instance.hostname=localhost

# 不在注册中心注册自己
eureka.client.register-with-eureka=false
# 表示自己是注册中心,不需要检索服务
eureka.client.fetch-registry=false
# 服务地址,在这里标识注册中心的url
eureka.client.service-url.defaultZone=http://eureka9090.com:9090/os/eureka


#是否开启自我保护机制
eureka.server.enable-self-preservation=true
#eureka服务节点间的读数据连接超时时间,会一直进行重试,如果过小容易造成占用cpu过高
eureka.server.peer-node-read-timeout-ms=1000

注意:eureka.client.service-url.defaultZone是其他Eureka server的地址,如果有多个用逗号分隔。

进入端口为9091的eureka server,可以看到如下内容:

Eureka Client

因为现在有多个Eureka server,所以客户端要注册的就有多个,用逗号隔开。

修改application.properties,改为如下内容:

eureka.client.service-url.defaultZone=http://eureka9090.com:9090/os/eureka,http://eureka9091.com:9091/os/eureka

启动后,再进入到eureka server的管理界面,可以看到如下内容。已经注册上了:

五、添加用户验证

当我们配置完 Spring Cloud Eureka  注册中心的时候,默认访问首页直接进入注册中心。

这样不管是谁,都可以直接进入太不安全,如果是在内网还好一点,如在外网,则把你的所有服务都暴露在外,非常不安全。

在Eureka Server 和Eureka Client 的pom文件添加以下依赖:

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

注意:springboot引入spring-boot-starter-security做安全校验后,自动开启CSRF安全认证。

Eureka server

1、在application.properties中设置用户名和密码

spring.security.user.name=test
spring.security.user.password=123456

2、注册中心地址也要进行修改,如下:

eureka.client.service-url.defaultZone=http://${spring.security.user.name}:${spring.security.user.password}@${eureka.instance.hostname}:9090/os/eureka

3、启动后,直接访问会提示输入用户名和密码。

 

4、默认情况下,当Spring Security在classpath中,它将要求向应用程序的每个请求都发送一个有效的CSRF令牌。Eureka客户端通常不会拥有有效的跨站点请求伪造(CSRF)令牌,所以需要手动关闭CSRF。

在Eureka Server项目创建一个类,内容如下:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()// 关闭CSRF
                .authorizeRequests()
                .antMatchers("/actuator/**").permitAll()
                .anyRequest()
                .authenticated().and().httpBasic();
        //super.configure(http); // 上面设置了请求路径就不能使用默认的了,这里不能打开
    }
}
Eureka Client

上面eureka server中的eureka.instance.hostname=localhost,所以需要修改Eureka Client的配置文件:

eureka.client.service-url.defaultZone=http://test:123456@localhost:9090/os/eureka

启动后,发现注册上了。

六、Eureka的一些重要注解或类

@EnableEurekaServer

在项目启动类上使用@EnableEurekaServer,可以将项目作为SpringCloud中的注册中心。

@EnableDiscoveryClient和@EnableEurekaClient注解

@EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现; 

@EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用。

EnableEurekaClient有@EnableDiscoveryClient的功能。

其实@EnableEurekaClient注解就是一种方便使用eureka的注解而已,可以说使用其他的注册中心后,都可以使用@EnableDiscoveryClient注解,
但是使用@EnableEurekaClient的情景,就是在服务采用eureka作为注册中心的时候,使用场景较为单一。

推荐使用@EnableDiscoveryClient。

 

posted @ 2020-12-05 10:02  codedot  阅读(2495)  评论(0编辑  收藏  举报