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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM