spring cloud組件之Eureka注冊中心:通過自動注冊、發現、狀態監控來管理服務地址


Eureka:解決服務地址的管理。自身不提供服務(不注冊自己到Eureka中,如果是集群則要注冊,因為其他Eureka服務器也要發現這台Eureka)也不消費服務(不來取服務)。默認情況下要注冊和拉取的

在剛才的案例中,user-service對外提供服務,需要對外暴露自己的地址consumer-demo(調用者)需要記錄服務提供者的地址。將來地址出現變更,還需要及時更新。這在服務較少的時候並不覺得有什么,但是在現在日益復雜的互聯網環境,一個項目可能會拆分出十幾,甚至幾十個微服務。此時如果還人為管理地址,不僅開發困難,將來測試、發布上線都會非常麻煩,這與DevOps的思想是背道而馳的。

Eureka負責管理、記錄服務提供者的信息。服務調用者無需自己尋找服務,而是把自己的需求告訴Eureka,然后Eureka會把符合你需求的服務告訴你。(即發現是通過服務提供方的名字獲取實例集合,然后從實例集合中取出一個實例,再從實例中獲取IP和端口)

同時,服務提供方Eureka之間通過 “心跳” 機制進行監控,當某個服務提供方出現問題,Eureka自然會把它從服務列表中剔除。

這就實現了服務的自動注冊、發現、狀態監控。

Eureka:就是服務注冊中心(Eureka Server可以是一個集群),對外(服務提供方和服務消費方)暴露自己的地址

提供者:啟動向Eureka注冊自己信息(地址,提供什么服務)

消費者:向Eureka訂閱服務,Eureka會將對應服務的所有提供者地址列表發送給消費者,並且定期更新

心跳(續約):提供者定期通過http方式向Eureka刷新自己的狀態

Eureka詳解

基礎架構

Eureka架構中的三個核心角色:

1、服務注冊中心(沒有集群時,不需注冊和發現)

Eureka的服務端應用,提供服務注冊和發現功能,就是剛剛我們建立的eureka-server

2、服務提供者(只需注冊,不需要發現)

提供服務的應用,可以是SpringBoot應用,也可以是其它任意技術實現,只要對外提供的是Rest風格服務即可。本例中就是我們實現的user-service

3、服務消費者(不僅要注冊還要發現)

消費應用從注冊中心獲取服務集合,從而得知每個服務方的信息(ip和port),知道去哪里調用服務方。本例中就是我們實現的consumer-demo

搭建eureka-server工程

1、創建一個Maven的java工程 eureka-server

zwh-springcloud右鍵→new→Module→maven→ArtifactId: eureka-server →next→Module name: eureka-server,Content root: C:\Users\miracle\IdeaProjects\springcloud_2020\zwh-springcloud\eureka-server→finish

2、導入依賴坐標:spring-cloud-starter-netflix-eureka-server

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

3、編寫啟動類,添加@EnableEurekaServer

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

4、編寫配置文件application.yml,配置eureka的地址,這個地址是其他服務注冊的地址,也是獲取服務名的地址

server:
  port: 10086
spring:
  application:
    name: eureka-server
eureka: client:
  #Eureka服務地址,如果是集群的話,需要制定集群其他Eureka地址 service
-url: defaultZone: http://127.0.0.1:10086/eureka fetch-registry: false #默認為true register-with-eureka: false #默認為true

如果是eureka-server集群的話,則fetch-registry和register-with-eureka均為true

5、啟動服務,訪問:http://127.0.0.1:10086

搭建服務提供方工程,服務注冊

注冊服務,就是在服務(提供者)添加Eureka的客戶端依賴eureka-client,服務在啟動時,如果eureka.client.register-with-eureka=true,則客戶端代碼會自動把服務注冊到EurekaServer中

1、添加依賴,我們在user-service中添加Eureka客戶端依賴:spring-cloud-starter-netflix-eureka-client

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

2、在啟動類上通過添加 @EnableDiscoveryClient開啟Eureka客戶端發現功能。可以不用添加該注解,因為服務提供方不需要發現。

@SpringBootApplication
@MapperScan("com.zwhxpp.user.mapper")
@EnableDiscoveryClient #開啟Eureka客戶端發現功能 public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

3、在配置文件中添加了spring.application.name屬性來指定應用名稱,將來會作為服務的id使用。

spring:
  application:
      name: user-service
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka  #告訴服務器Eureka在哪里,才能將服務注冊到Eureka中

搭建服務消費方工程,服務發現

在服務消費方添加Eureka客戶端依賴eureka-client,開啟發現功能且eureka.client.fetch-registry=true,則會從EurekaServer服務的列表拉取只讀備份,然后緩存在本地

我們可以使用DiscoveryClient的方法根據服務名稱獲取對應的服務地址列表來模擬。

1、添加依賴:spring-cloud-starter-netflix-eureka-client

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

2、在啟動類上通過添加 @EnableDiscoveryClient開啟Eureka客戶端發現功能

@SpringBootApplication
@EnableDiscoveryClient #開啟Eureka客戶端發現功能 public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

3、新增配置文件

server:
  port: 8080
spring:
  application:
    name: consumer-demo
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

4、修改Controller,用工具類DiscoveryClient類的方法,根據服務名稱,獲取服務實例。

import org.springframework.cloud.client.discovery.DiscoveryClient;

當注冊服務有多個的時候,我們會用負載均衡的方式從ServerInstance的集合中取出一個(Eureka-client中已經集成了Ribbon),而現在是取第一個

5、重啟 consumer-demo 項目;然后再瀏覽器中再次訪問 http://localhost:8080/consumer/8 ;在代碼中debug跟進查看最終拼接要訪問的URL:

服務提供方)服務注冊

服務注冊的條件:eureka.client.register-with-eureka=true

服務注冊的方式:主機名注冊或ip注冊

服務提供者在啟動時,會檢測配置屬性中的: eureka.client.register-with-eureka=true 參數是否正確,事實上默認就是true。如果值確實為true,則會EurekaServer發起一個Rest請求,並攜帶自己的元數據信息EurekaServer會把這些信息保存到一個雙層Map結構中

1、第一層Map的Key就是服務id,一般是配置中的 spring.application.name 屬性

2、第二層Map的key是服務的實例id。一般host+ serviceId + port,例如: localhost:user-service:8081

3、值則是服務的實例對象,也就是說一個服務,可以同時啟動多個不同實例,形成集群。

默認注冊時使用的是主機名或者localhost,如果想用ip進行注冊,可以在服務提供方 user-service 中添加prefer-ip-address配置如下:(服務地址使用ip方式)

eureka:
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

修改完后先后重啟 user-service 和 consumer-demo ;默認注冊時使用的是主機名,將從eureka獲取的實例的主機名改成ip地址,這樣,在調用服務的時候就已經變成ip地址;

需要注意的是:不是在eureka中的控制台服務實例狀態顯示。即在控制台顯示的仍然是主機名,只是在調用服務的時候將主機名改為了ip地址,如下所示:

 

 

服務提供方)服務續約(30s,90s)

在注冊服務完成以后,服務提供者會維持一個心跳(定時向EurekaServer發起Rest請求),告訴EurekaServer:“我還活着”。這個我們稱為服務的續約(renew);

有兩個重要參數可以修改服務續約的行為;可以在 user-service (服務提供方)中添加如下配置項:

eureka:
  instance:
    lease-expiration-duration-in-seconds: 90 #默認90秒
    lease-renewal-interval-in-seconds: 30 #默認30秒

lease-renewal-interval-in-seconds:服務續約(renew)的間隔,默認為30秒

lease-expiration-duration-in-seconds:服務失效時間,默認值90秒

lease:租約租約過期時間90秒,90秒之內沒有續約就過期。租約續約時間30

也就是說,默認情況下每隔30秒服務會向注冊中心發送一次心跳,證明自己還活着。如果超過90秒沒有發送心跳(續約)EurekaServer就會認為該服務宕機,會定時(eureka.server.eviction-interval-timer-in-ms設定的時間)從服務列表中移除,這兩個值在生產環境不要修改,默認即可

修改這兩個參數的值如下進行測試:

設置好了之后,重啟user-service,然后關閉user-service,按照配置,每隔5秒鍾會去續約,如果不續約,再等15秒,如果還沒有續約,則會允許剔除,即是可以剔除而不是一定會剔除。但是剔除是在eureka上面剔除的,eureka默認每隔一段時間(默認為60秒)將當前清單中超時(默認為90秒)沒有續約的服務剔除而現在沒有剔除,因為它認為有可能是網絡故障造成的,會觸發了Eureka的自我保護機制,只有設置了eureka.server.eviction-interval-timer-in-ms(失效剔除)才會真正剔除。

服務消費方)獲取服務列表(30s)

獲取服務列表的條件:eureka.client.fetch-registry=true

獲取服務列表的頻率:默認30s

當服務消費者啟動時,會檢測 eureka.client.fetch-registry=true 參數的值,如果為true,則會從EurekaServer服務的列表拉取只讀備份,然后緩存在本地。並且 每隔30秒 會重新拉取並更新數據。可以在 consumer-demo項目中通過下面的參數來修改:(獲取服務地址的頻率)

eureka:
  client:
    registry-fetch-interval-seconds: 30

服務下線

當服務(提供方)進行正常關閉操作時,它會觸發一個服務下線的REST請求給Eureka Server,告訴服務注冊中心:“我要下線”。服務中心接受到請求之后,將該服務置為下線狀態

Eureka Server)失效剔除(60s)

先判斷心跳是否續約,如果未續約,則可能失效剔除。

有時我們的服務(提供方)可能由於內存溢出或網絡故障等(非正常原因)使得服務不能正常的工作,而服務注冊中心並未收到“服務下線”的請求。相對於服務提供者的“服務續約”操作,服務注冊中心在啟動時會創建一個定時任務,默認每隔一段時間(默認為60秒)將當前清單中超時(默認為90秒)沒有續約的服務剔除,這個操作被稱為失效剔除。

可以通過 eureka.server.eviction-interval-timer-in-ms 參數對其進行修改,單位是毫秒

eureka:
  server:
    eviction-interval-timer-in-ms: 60000

Eureka Server)自我保護

先判斷心跳是否續約,如果未續約,則可能自我保護。

我們關停一個服務,很可能會在Eureka面板看到一條警告:

 

這是觸發了Eureka的自我保護機制。當服務未按時進行心跳續約時,Eureka會統計服務實例最近15分鍾心跳續約的比例是否低於了85%。在生產環境下,因為網絡延遲等原因,心跳失敗實例的比例很有可能超標,但是此時就把服務剔除列表並不妥當,因為服務可能沒有宕機。Eureka在這段時間內不會剔除任何服務實例,直到網絡恢復正常。產環境下這很有效,保證了大多數服務依然可用,不過也有可能獲取到失敗的服務實例,因此服務調用者必須做好服務的失敗容錯。

開發階段,啟動自我保護模式是沒有意義的,服務停止了就是停止了,不是因為網絡的原因,因為在我們自己的機器上基本不可能出現網絡的原因,建議開發是關閉自我保護模式

自我保護模式是默認打開的。

可以通過下面的配置來關停自我保護:

eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 60000

上述配置,先判斷心跳是否續約,如果未續約,則會失效剔除,而不會自我保護,因為自我保護已關閉。

在生產環境,打開自我保護,而不是失效剔除。

 


免責聲明!

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



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