1. 程式人生 > 其它 >SpringCloud註冊中心Eureka

SpringCloud註冊中心Eureka

什麼是Eureka

原理理解

  • Netflix在涉及Eureka時,遵循的就是CAP原則.

  • Eureka是Netflix的一個子模組,也是核心模組之一。Eureka是基於REST的服務,用於定位服務,以實現雲端中介軟體層服務發現和故障轉移,服務註冊與發現對於微服務來說是非常重要的,有了服務註冊與發現,只需要使用服務的識別符號,就可以訪問到服務,而不需要修改服務呼叫的配置檔案了,功能類似於Dubbo的註冊中心,比如Zookeeper.

  • Eureka基本的架構

    • Springcloud 封裝了Netflix公司開發的Eureka模組來實現服務註冊與發現 (對比Zookeeper).
    • Eureka採用了C-S的架構設計,EurekaServer作為服務註冊功能的伺服器,他是服務註冊中心.
    • 而系統中的其他微服務,使用Eureka的客戶端連線到EurekaServer並維持心跳連線。這樣系統的維護人員就可以通過EurekaServer來監控系統中各個微服務是否正常執行,Springcloud 的一些其他模組 (比如Zuul) 就可以通過EurekaServer來發現系統中的其他微服務,並執行相關的邏輯.

​ 和Dubbo架構對比.

  • Eureka 包含兩個元件:Eureka ServerEureka Client.

  • Eureka Server 提供服務註冊,各個節點啟動後,回在EurekaServer中進行註冊,這樣Eureka Server中的服務登錄檔中將會儲存所有可用服務節點的資訊,服務節點的資訊可以在介面中直觀的看到.

  • Eureka Client 是一個Java客戶端,用於簡化EurekaServer的互動,客戶端同時也具備一個內建的,使用輪詢負載演算法的負載均衡器。在應用啟動後,將會向EurekaServer傳送心跳 (預設週期為30秒) 。如果Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將會從服務登錄檔中把這個服務節點移除掉 (預設週期為90s).

  • 三大角色

    • Eureka Server:提供服務的註冊與發現
    • Service Provider:服務生產方,將自身服務註冊到Eureka中,從而使服務消費方能夠找到
    • Service Consumer:服務消費方,從Eureka中獲取註冊服務列表,從而找到消費服務

springcloud-eureka-7001:構建eureka

1.構建eureka的server端

springcloud-eureka-7001 模組建立

這裡我採用maven來新建eureka的server端模組!

pom.xml 配置

<!--導包~-->
<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
    <!--匯入Eureka Server依賴-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--熱部署工具-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

application.yml編寫

server:
  port: 7001


#Eureka配置
eureka:
  instance:
    hostname: localhost #eureka服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registryr如果為false,則表示自己為註冊中心,客戶端的話為true
    service-url: #表示註冊中心的地址,其中http://${eureka.instance.hostname}:${server.port}是一個監控頁面
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

我們點開application.yml中的service-url可以看到eureka的預設埠8761和訪問路徑:

主啟動類編寫

由於我們是maven工程構建的模組,所以要加個主啟動類:

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer 表示是一個註冊中心服務端:可以接收別人註冊進來
public class EurekaServer_7001 {

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

訪問頁面

啟動成功後訪問 http://localhost:7001/ 得到以下頁面

2.構建eureka的client端

eureka的client端也就是服務提供者

調整之前建立的springlouc-provider-dept-8001

匯入Eureka依賴

<!--Eureka依賴-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

application中新增Eureka配置

# Eureka配置:配置服務註冊中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/

為主啟動類新增@EnableEurekaClient註解

//啟動類
@SpringBootApplication
@EnableEurekaClient //在服務啟動後自動註冊到eureka中
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

先啟動7001服務端後啟動8001客戶端進行測試,然後訪問監控頁http://localhost:7001/ 再看結果如圖,成功

修改Eureka上的預設描述資訊

#Eureka的配置,服務註冊到哪裡
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 #修改eureka監控介面對應此服務的實列id

結果如圖:

配置關於服務載入的監控資訊

pom.xml中新增依賴

<!--actuator是用來完善eureka介面對應服務的詳細監控資訊的:就介面status那裡每個服務有個連結點進去-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.yml中新增配置

#info配置:就是用來配置eureka介面對應服務的詳細監控資訊的:就介面status那裡每個服務有個連結點進去  http://xxxx:xxx/actuator/info
info:
  app.name: kuangshen-springcloud
  company.name: blog.kuangstudy.com

重新整理監控頁成功,再點一下成功:

EureKa自我保護機制

一句話總結就是:某時刻某一個微服務不可用,eureka不會立即清理,依舊會對該微服務的資訊進行儲存!

  • 預設情況下,當eureka server在一定時間內沒有收到例項的心跳,便會把該例項從登錄檔中刪除(預設是90秒),但是,如果短時間內丟失大量的例項心跳,便會觸發eureka server的自我保護機制,比如在開發測試時,需要頻繁地重啟微服務例項,但是我們很少會把eureka server一起重啟(因為在開發過程中不會修改eureka註冊中心),當一分鐘內收到的心跳數大量減少時,會觸發該保護機制。可以在eureka管理介面看到Renews threshold和Renews(last min),當後者(最後一分鐘收到的心跳數)小於前者(心跳閾值)的時候,觸發保護機制,會出現紅色的警告:EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.從警告中可以看到,eureka認為雖然收不到例項的心跳,但它認為例項還是健康的,eureka會保護這些例項,不會把它們從登錄檔中刪掉。
  • 該保護機制的目的是避免網路連線故障,在發生網路故障時,微服務和註冊中心之間無法正常通訊,但服務本身是健康的,不應該登出該服務,如果eureka因網路故障而把微服務誤刪了,那即使網路恢復了,該微服務也不會重新註冊到eureka server了,因為只有在微服務啟動的時候才會發起註冊請求,後面只會傳送心跳和服務列表請求,這樣的話,該例項雖然是執行著,但永遠不會被其它服務所感知。所以,eureka server在短時間內丟失過多的客戶端心跳時,會進入自我保護模式,該模式下,eureka會保護登錄檔中的資訊,不在登出任何微服務,當網路故障恢復後,eureka會自動退出保護模式。自我保護模式可以讓叢集更加健壯。
  • 但是我們在開發測試階段,需要頻繁地重啟發布,如果觸發了保護機制,則舊的服務例項沒有被刪除,這時請求有可能跑到舊的例項中,而該例項已經關閉了,這就導致請求錯誤,影響開發測試。所以,在開發測試階段,我們可以把自我保護模式關閉,只需在eureka server配置檔案中加上如下配置即可:eureka.server.enable-self-preservation=false【不推薦關閉自我保護機制】

這裡說下手動將無效例項從eureka例項列表刪除的方法:

用ssh或者postman等工具,向eureka server傳送delete請求即可刪除:

curl -XDELETE http://eureka server地址/eureka/apps/要刪除的服務名/要刪除的例項id(在Eureka Server管理介面可以看到例項的id)

詳細內容可以參考下這篇部落格內容:https://blog.csdn.net/wudiyong22/article/details/80827594

獲取註冊進來微服務的配置資訊

這個一般團隊開發會用到,我們在DeptController.java新增方法

/**
 * DiscoveryClient 可以用來獲取一些配置的資訊,得到具體的微服務!
 */
@Autowired
private DiscoveryClient client;
/**
 * 獲取一些註冊進來的微服務的資訊~,
 *
 * @return
 */
@GetMapping("/dept/discovery")
public Object discovery() {
    // 獲取微服務列表的清單
    List<String> services = client.getServices();
    System.out.println("discovery=>services:" + services);
    // 得到一個具體的微服務資訊,通過具體的微服務id,applicaioinName;
    List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
    for (ServiceInstance instance : instances) {
        System.out.println(
                instance.getHost() + "\t" + // 主機名稱
                        instance.getPort() + "\t" + // 埠號
                        instance.getUri() + "\t" + // uri
                        instance.getServiceId() // 服務id
        );
    }
    return this.client;
}

主啟動類中加入@EnableDiscoveryClient 註解

@SpringBootApplication
// @EnableEurekaClient 開啟Eureka客戶端註解,在服務啟動後自動向註冊中心註冊服務
@EnableEurekaClient
// @EnableEurekaClient 開啟服務發現客戶端的註解,可以用來獲取一些配置的資訊,得到具體的微服務
@EnableDiscoveryClient
public class DeptProvider_8001 {
    ...
}

在瀏覽器訪問http://localhost:8001/dept/discovery,後臺成功打印出相關資訊!

Eureka:叢集環境配置

修改hosts檔案

要進行eureka的叢集,要模擬出多臺機器,因此我們在本地測試採用修改hosts檔案的方法

hosts檔案路徑在(windows系統):C:\Windows\System32\drivers\etc

修改hosts檔案出現拒絕訪問的情況:
複製 hosts檔案到桌面,按需編輯後儲存;
貼上回系統盤hosts所在位置,選擇替換;
使用管理員許可權,點選繼續,覆蓋即可。

初始化

新建springcloud-eureka-7002、springcloud-eureka-7003 模組

為pom.xml新增依賴 (與springcloud-eureka-7001相同)

<!--導包~-->
<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
    <!--匯入Eureka Server依賴-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--熱部署工具-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

修改application.yml的配置,下面為springcloud-eureka-7001配置,springcloud-eureka-7002/springcloud-eureka-7003同樣分別修改為其對應的名稱即可

在叢集中使springcloud-eureka-7001關聯springcloud-eureka-7002、springcloud-eureka-7003;

springcloud-eureka-7002關聯springcloud-eureka-7001、springcloud-eureka-7003(照7001模組依葫蘆畫瓢);

springcloud-eureka-7003關聯springcloud-eureka-7001、springcloud-eureka-7002;

完整的springcloud-eureka-7001下的application.yml如下:

server:
  port: 7001


#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com #eureka服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registryr如果為false,則表示自己為註冊中心,客戶端的話為true
    service-url: #表示註冊中心的地址,其中http://${eureka.instance.hostname}:${server.port}是一個監控頁面
      #單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #叢集(我們就只需要關聯其他叢集的節點):
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

完整的springcloud-eureka-7002下的application.yml如下:

server:
  port: 7002


#Eureka配置
eureka:
  instance:
    hostname: eureka7002.com #eureka服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registryr如果為false,則表示自己為註冊中心,客戶端的話為true
    service-url: #表示註冊中心的地址,其中http://${eureka.instance.hostname}:${server.port}是一個監控頁面
      #單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #叢集(我們就只需要關聯其他叢集的節點):
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/

完整的springcloud-eureka-7003下的application.yml如下:

server:
  port: 7003


#Eureka配置
eureka:
  instance:
    hostname: eureka7003.com #eureka服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registryr如果為false,則表示自己為註冊中心,客戶端的話為true
    service-url: #表示註冊中心的地址,其中http://${eureka.instance.hostname}:${server.port}是一個監控頁面
      #單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #叢集(我們就只需要關聯其他叢集的節點):
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

修改springcloud-provider-dept-8001下的yml配置檔案,修改Eureka配置:配置服務註冊中心叢集的所有地址

#Eureka的配置,服務註冊到哪裡
eureka:
  client:
    service-url:
      #單機:defaultZone: http://localhost:7001/eureka/
      #叢集的話,要註冊到叢集的每個節點
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 #修改eureka監控介面對應此服務的實列id

這樣模擬叢集就搭建好了,就可以把一個服務掛載到三個eureka叢集節點上了,這樣即使某個eureka叢集節點掛了,其他的eureka節點也能找到服務!

Eureka和Zookeeper的區別

1. 回顧CAP原則

RDBMS (MySQL\Oracle\sqlServer) ===> ACID

NoSQL (Redis\MongoDB) ===> CAP

2. ACID是什麼?

  • A (Atomicity) 原子性
  • C (Consistency) 一致性
  • I (Isolation) 隔離性
  • D (Durability) 永續性

3. CAP是什麼?

  • C (Consistency) 強一致性
  • A (Availability) 可用性
  • P (Partition tolerance) 分割槽容錯性

CAP的三進二:CA、AP、CP

4. CAP理論的核心

  • 一個分散式系統不可能同時很好的滿足一致性,可用性和分割槽容錯性這三個需求
  • 根據CAP原理,將NoSQL資料庫分成了滿足CA原則,滿足CP原則和滿足AP原則三大類
    • CA:單點叢集,滿足一致性,可用性的系統,通常可擴充套件性較差
    • CP:滿足一致性,分割槽容錯的系統,通常效能不是特別高
    • AP:滿足可用性,分割槽容錯的系統,通常可能對一致性要求低一些

5. 作為分散式服務註冊中心,Eureka比Zookeeper好在哪裡?

著名的CAP理論指出,一個分散式系統不可能同時滿足C (一致性) 、A (可用性) 、P (容錯性),由於分割槽容錯性P再分散式系統中是必須要保證的,因此我們只能再A和C之間進行權衡。

  • Zookeeper 保證的是 CP —> 滿足一致性,分割槽容錯的系統,通常效能不是特別高
  • Eureka 保證的是 AP —> 滿足可用性,分割槽容錯的系統,通常可能對一致性要求低一些

Zookeeper保證的是CPEureka保證的是AP

當向註冊中心查詢服務列表時,我們可以容忍註冊中心返回的是幾分鐘以前的註冊資訊,但不能接受註冊中心直接down掉不可用。也就是說,服務註冊功能對可用性的要求要高於一致性。

但zookeeper會出現這樣一種情況,當master節點因為網路故障與其他叢集zookeeper節點失去聯絡時,剩餘節點會重新進行leader選舉。問題在於,選舉leader的時間太長,30-120s,且選舉期間整個zookeeper叢集是不可用的,這就導致在選舉期間註冊服務癱瘓。在雲部署的環境下,因為網路問題使得zookeeper叢集失去master節點是較大概率發生的事件,雖然服務最終能夠恢復,但是,漫長的選舉時間導致註冊長期不可用,是不可容忍的。

Eureka看明白了這一點,因此在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩餘的節點依然可以提供註冊和查詢服務。而Eureka的客戶端在向某個Eureka節點註冊時,如果發現連線失敗,則會自動切換至其他節點,只要有一臺Eureka還在,就能保證註冊服務的可用性,只不過查到的資訊可能不是最新的(就保證不了一致性),除此之外,Eureka還有一種自我保護機制,如果在15分鐘內超過85%的節點都沒有正常的心跳,那麼Eureka就認為客戶端與註冊中心出現了網路故障,此時會出現以下幾種情況:

  • Eureka不再從註冊列表中移除因為長時間沒收到心跳而應該過期的服務
  • Eureka仍然能夠接受新服務的註冊和查詢請求,但是不會被同步到其他節點上 (即保證當前節點依然可用)
  • 當網路穩定時,當前例項新的註冊資訊會被同步到其他節點中

因此,Eureka可以很好的應對因網路故障導致部分節點失去聯絡的情況,而不會像zookeeper那樣使整個註冊服務癱瘓!