序言
Eureka 是 Netflix 開發的,一個基於 REST 服務的,服務注冊與發現的組件
它主要包括兩個組件:Eureka Server 和 Eureka Client
- Eureka Client:一個Java客戶端,用於簡化與 Eureka Server 的交互(通常就是微服務中的客戶端和服務端)
- Eureka Server:提供服務注冊和發現的能力(通常就是微服務中的注冊中心)
各個微服務啟動時,會通過 Eureka Client 向 Eureka Server 注冊自己,Eureka Server 會存儲該服務的信息
也就是說,每個微服務的客戶端和服務端,都會注冊到 Eureka Server,這就衍生出了微服務相互識別的話題
- 同步:每個 Eureka Server 同時也是 Eureka Client(邏輯上的)
多個 Eureka Server 之間通過復制的方式完成服務注冊表的同步,形成 Eureka 的高可用 - 識別:Eureka Client 會緩存 Eureka Server 中的信息
即使所有 Eureka Server 節點都宕掉,服務消費者仍可使用緩存中的信息找到服務提供者(筆者已親測) - 續約:微服務會周期性(默認30s)地向 Eureka Server 發送心跳以Renew(續約)信息(類似於heartbeat)
- 續期:Eureka Server 會定期(默認60s)執行一次失效服務檢測功能
它會檢查超過一定時間(默認90s)沒有Renew的微服務,發現則會注銷該微服務節點
Spring Cloud 已經把 Eureka 集成在其子項目 Spring Cloud Netflix 里面
關於 Eureka 配置的最佳實踐,可參考:https://github.com/spring-cloud/spring-cloud-netflix/issues/203
更多介紹,可參考:http://cloud.spring.io/spring-cloud-static/Camden.SR4/#spring-cloud-eureka-server
單個Eureka Server配置部署實例
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
注冊中心,啟動類。
@SpringBootApplication //創建服務注冊中心 @EnableEurekaServer public class StartMain { public static void main(String[] args) { SpringApplication.run(StartMain.class, args); } }
注冊中心配置文件
## server
server.port=8081
##eureka
#指定環境
eureka.environment=work
# 設置是否將自己作為客戶端注冊到注冊中心(缺省true)
# 這里為不需要(查看@EnableEurekaServer注解的源碼,會發現它間接用到了@EnableDiscoveryClient)
eureka.client.register-with-eureka=false
# 設置是否從注冊中心獲取注冊信息(缺省true)
# 因為這是一個單點的EurekaServer,不需要同步其它EurekaServer節點的數據,故設為false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
#是否開啟自我保護模式,默認為true。
eureka.server.enable-self-preservation=true
#續期時間,即掃描失效服務的間隔時間(缺省為60*1000ms)
eureka.server.eviction-interval-timer-in-ms=10000
zone
上面提到 serviceUrl,那就順便說下 defaultZone
Eureka 有一個 Region 和 Zone 的概念,你可以理解為現實中的大區(Region)和機房(Zone)
Eureka Client 在啟動時需要指定 Zone,它會優先請求自己 Zone 的 Eureka Server 獲取注冊列表
同樣的,Eureka Server 在啟動時也需要指定 Zone,如果沒有指定的話,其會默認使用 defaultZone
詳見源碼中的 getEurekaServerServiceUrls() 方法:https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfigBean.java
note:
現在啟動Eureka Server,沒有Eureka Client,過一段時間會出現
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE
UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND
HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
這說明Eureka進入保護模式,可通過上述配置去掉,Eureka的保護模式講解詳見:https://github.com/Netflix/eureka/wiki/Understanding-Eureka-Peer-to-Peer-Communication
Eureka Client配置部署實現
pom文件
<dependencies> <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> <version>2.0.0.RELEASE</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
微服務client,啟動類。
@SpringBootApplication @EnableEurekaClient public class StartMain { public static void main(String[] args) { SpringApplication.run(StartMain.class, args); } }
微服務client,配置文件
##eureka
eureka.client.serviceUrl.defaultZone=http://localhost:8081/eureka/
eureka.instance.instance-id=${spring.application.name}:${server.port}
# 設置微服務調用地址為IP優先(缺省為false)
eureka.instance.prefer-ip-address=true
# 心跳時間,即服務續約間隔時間(缺省為30s)
eureka.instance.lease-renewal-interval-in-seconds=30
# 發呆時間,即服務續約到期時間(缺省為90s)
eureka.instance.lease-expiration-duration-in-seconds=90
note:
關於續約序言中有講解,instance-id,是再注冊中心頁面顯示的微服務名。
Eureka 首頁顯示的微服務名默認為:機器主機名:應用名稱:應用端口,
也就是:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}
eureka.client.serviceUrl.defaultZone這個配置可以配置單個注冊中心的地址,也可配置多個,逗號隔開
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/,http://127.0.0.1:8081/eureka/
好啦,這樣一個注冊中心與微服務就完成啦。啟動看看吧。
Eureka Server注冊中心(高可用)集群部署
Eureka Server 支持運行多實例,並以互相注冊的方式(即伙伴機制),來實現高可用的部署
即每一台 Eureka 都在配置中指定另一個 Eureka 或多個 地址作為伙伴,它在啟動時會向伙伴節點獲取注冊列表
詳見:http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_peer_awareness
配置demo
與單Server配置稍作改動,如下三個注冊中心ABC
A:127.0.0.1:9001
B:127.0.0.1:9002
C:127.0.0.1:9003
A配置: eureka.client.serviceUrl.defaultZone : http://B/eureka/,http://C/eureka/
B配置: eureka.client.serviceUrl.defaultZone : http://A/eureka/,http://C/eureka/
C配置: eureka.client.serviceUrl.defaultZone : http://B/eureka/,http://A/eureka/
運行不同環境
java -jar .\trade-0.0.1-SNAPSHOT.jar --spring.profiles.active=local
ok啦,試試吧。
配置
服務端
server:
# 項目端口號
port: 8761
# SSL 配置
ssl:
# 開啟 SSL 認證
enabled: true
# 證書別名
key-alias: eurekaserver
# 證書存放路徑
key-store: classpath:EurekaServer.p12
# 證書密碼
key-store-password: 123456
# 存儲類型
key-store-type: PKCS12
spring:
application:
name: demo-eureka-server
# 開啟安全控制
security:
user:
# 用戶名
name: eureka-server
# 密碼
password: 8e9lx7LuP3436gfsg
eureka:
instance:
# 主機名
hostname: localhost
# 使用 ip 注冊到注冊中心實例化
prefer-ip-address: true
# 安全端口
secure-port: ${server.port}
# 指示是否應為流量啟用安全端口
secure-port-enabled: true
# 關閉非安全端口
non-secure-port-enabled: false
home-page-url: https://${eureka.instance.hostname}:${server.port}/
status-page-url: https://${eureka.instance.hostname}:${server.port}/actuator/info
health-check-url: https://${eureka.instance.hostname}:${server.port}/actuator/health
client:
# 此實例是否從注冊中心獲取注冊信息
fetch-registry: false
# 是否將此實例注冊到注冊中心
register-with-eureka: false
# 注冊地址
service-url:
# 默認注冊分區地址
defaultZone: https://${eureka.instance.hostname}:${server.port}/eureka/
server:
# 同步為空時,等待時間
wait-time-in-ms-when-sync-empty: 0
# 是否開啟自我保護機制
## 在分布式系統設計里頭,通常需要對應用實例的存活進行健康檢查,這里比較關鍵的問題就是要處理好網絡偶爾抖動或短暫不可用時造成的誤判。另外Eureka Server端與Client端之間如果出現網絡分區問題,在極端情況下可能會使得Eureka Server清空部分服務的實例列表,這個將嚴重影響到Eureka server的 availibility屬性。因此Eureka server引入了SELF PRESERVATION機制。
## Eureka client端與Server端之間有個租約,Client要定時發送心跳來維持這個租約,表示自己還存活着。 Eureka通過當前注冊的實例數,去計算每分鍾應該從應用實例接收到的心跳數,如果最近一分鍾接收到的續約的次數小於指定閾值的話,則關閉租約失效剔除,禁止定時任務剔除失效的實例,從而保護注冊信息。
# 此處關閉可以防止問題(測試環境可以設置為false):Eureka server由於開啟並引入了SELF PRESERVATION模式,導致registry的信息不會因為過期而被剔除掉,直到退出SELF PRESERVATION模式才能剔除。
enable-self-preservation: false
# 指定 Eviction Task 定時任務的調度頻率,用於剔除過期的實例,此處未使用默認頻率,頻率為:5/秒,默認為:60/秒
# 有效防止的問題是:應用實例異常掛掉,沒能在掛掉之前告知Eureka server要下線掉該服務實例信息。這個就需要依賴Eureka server的EvictionTask去剔除。
eviction-interval-timer-in-ms: 5000
# 設置read Write CacheMap的expire After Write參數,指定寫入多長時間后過期
# 有效防止的問題是:應用實例下線時有告知Eureka server下線,但是由於Eureka server的REST API有response cache,因此需要等待緩存過期才能更新
response-cache-auto-expiration-in-seconds: 60
# 此處不開啟緩存,上方配置開啟一個即可
# use-read-only-response-cache: false
# 指定每分鍾需要收到的續約次數的閾值,默認值就是:0.85
renewal-percent-threshold: 0.85
# 續約頻率提高,默認:30
leaseRenewalIntervalInseconds: 10
客戶端
server:
# \u9879\u76EE\u7AEF\u53E3\u53F7
port: 11200
spring:
application:
# Spring Boot \u9879\u76EE\u5B9E\u4F8B\u540D\u79F0
name: demo-goods
### \u6CE8\u518C\u4E2D\u5FC3\u914D\u7F6E
eureka:
instance:
# \u4E3B\u673A\u540D
hostname: localhost
# \u4F7F\u7528 ip \u6CE8\u518C\u5230\u6CE8\u518C\u4E2D\u5FC3\u5B9E\u4F8B\u5316
prefer-ip-address: true
client:
secure-port-enabled: true
ssl:
key-store: EurekaClient.p12
key-store-password: 123456
security:
user:
name: eureka-server
password: 8e9lx7LuP3436gfsg
# Spring Cloud Eureka \u6CE8\u518C\u4E2D\u5FC3\u5730\u5740
service-url:
defaultZone: https://${eureka.client.security.user.name}:${eureka.client.security.user.password}@${eureka.instance.hostname}:8761/eureka/
# \u9488\u5BF9\u65B0\u670D\u52A1\u4E0A\u7EBF, Eureka client\u83B7\u53D6\u4E0D\u53CA\u65F6\u7684\u95EE\u9898\uFF0C\u5728\u6D4B\u8BD5\u73AF\u5883\uFF0C\u53EF\u4EE5\u9002\u5F53\u63D0\u9AD8Client\u7AEF\u62C9\u53D6Server\u6CE8\u518C\u4FE1\u606F\u7684\u9891\u7387\uFF0C\u9ED8\u8BA4\uFF1A30\u79D2
registry-fetch-interval-seconds: 30
總結
多看文檔,很容易理解的。