天天看點

springcloud eureka叢集_SpringCloud入門學習之Eureka

springcloud eureka叢集_SpringCloud入門學習之Eureka
Eureka

什麼是Eureka

Eureka 是一個基于 REST(Representational State Transfer)的服務,主要用于 AWS cloud, 提供服務定位(locating services)、負載均衡(load balancing)、故障轉移(failover of middle-tier servers)。是 Netflix 開源的服務發現元件,包括 Server 和 Client 兩部分.在 Spring Cloud 子項目 Spring Cloud Netflix 中。

Eureka Server 和 Eureka Client

  • Eureka Server : 提供服務發現的能力,各服務啟動時,會向 Eureka Server 注冊自己的資訊(IP,端口,服務資訊等),Eureka Server 會存儲這些資訊.
  • Eureka Client : 服務提供者,簡化與Eureka Server的互動.

Eureka能做什麼

微服務的注冊與發現,功能類似于 Zookeeper。

原理講解

  • Eureka 采用了 C-S 的架構設計,Eureka Server 作為服務注冊功能的伺服器,提供服務發現的能力。
  • 微服務啟動後,會周期性(預設30秒)的向 Eureka Server 發送心跳以續約自己的”租期”。
  • 如果 Eureka Server 在一定時間内沒有收到某個微服務執行個體(Eureka Client)的心跳,Eureka Server 将會登出該執行個體(預設90秒)。
  • 預設請求下,Eureka Server 同時也是 Eureka Client。多個 Eureka Server 執行個體,互相之間通過複制的方式,來實作服務系統資料庫中的資料.(實作叢集,高可用)
  • Eureka Client 會緩存系統資料庫中的資訊.這種方式有一定的優勢。首先,微服務無需每次請求都查詢Eureka Server,進而降低了 Eureka Server 的壓力;其次,即使 Eureka Server 所有節點都宕掉,服務消費者依然可以使用緩存中的資訊找到服務提供者并完成調用。這樣,Eureka通過心跳檢測,用戶端緩存等機制,提高了系統的靈活性,可伸縮性和可用性。

畫一張簡單的功能圖來展示其作用:

springcloud eureka叢集_SpringCloud入門學習之Eureka

可以發現同 Zookeeper 功能很相似。

Eureka Server示例

1、建立一個名為 springcloud-config-eureka-7001 的普通 maven 項目

2、導入相關依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <!--熱部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
           

3、

resources

中添加

application.yml

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: localhost #Eureka服務端的執行個體名稱
  client:
    register-with-eureka: false   #表示是否向注冊中心注冊自己
    fetch-registry: false   #為false表示自己是注冊中心
    service-url:    #監控頁面
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
           

4、編寫入口類

@EnableEurekaServer //啟動服務發現,接受注冊
@SpringBootApplication
public class EurekaServer_7001 {

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

5、啟動項目,通路 http://localhost:7001/ ,頁面顯示如下:

springcloud eureka叢集_SpringCloud入門學習之Eureka

Eureka Client示例

基于我們之前建立的 Rest 服務提供者 springcloud-provider-dept-8001 進行修改。

1、導入依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
           

2、在入口類上增加

@EnableEurekaClient

注解

@SpringBootApplication
@EnableEurekaClient
public class DeptProvider_8001 {

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

3、

application.yml

檔案中增加 Eureka 配置

#Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept-8001   # 修改eureka上的預設描述資訊
    prefer-ip-address: true  # true,可以顯示服務的IP位址
           

4、啟動項目,通路 http://localhost:7001/ ,頁面結果如下:

springcloud eureka叢集_SpringCloud入門學習之Eureka

當我們點選 Status 标簽下的連結時,頁面會進行跳轉,結果如下所示:

springcloud eureka叢集_SpringCloud入門學習之Eureka

那麼我們考慮如何讓它正常顯示内容。

actuator完善監控資訊

1、首先導入依賴

<!--actuator完善監控資訊-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
           

2、

application.yml

檔案中增加 info 配置

#info配置
info:
  app.name: hresh-springcloud
  company.name: blog.csdn.net/Herishwater
           

3、稍等片刻,再次點選上述連結,内容展示如下:

springcloud eureka叢集_SpringCloud入門學習之Eureka

服務發現Discovery

在團隊多服務建構過程中,如果别人想擷取你所建構的微服務資訊,可以通過注入

org.springframework.cloud.client.discovery.DiscoveryClient

,擷取到微服務清單,然後選擇想要的服務ID,周遊列印具體資訊。

在 DeptController 增加實作方法。

//擷取一些配置的資訊,得到具體的微服務
    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/dept/discovery")
    public Object getService(){
        List<String> services = discoveryClient.getServices();
        System.out.println("discovery=>services:"+services);

        List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
        for (ServiceInstance instance : instances) {
            System.out.println(
                    instance.getHost()+"t"+
                            instance.getPort()+"t"+
                            instance.getUri()+"t"+
                            instance.getServiceId()
            );
        }
        return discoveryClient;
    }
           

前台通路 http://localhost:8001/dept/discovery ,頁面展示結果如下:

{"discoveryClients":[{"services":["springcloud-provider-dept"],"order":0},{"services":[],"order":0}],"services":["springcloud-provider-dept"],"order":0}
           

叢集

在上文中我們建立了一個名為 springcloud-config-eureka-7001 的普通 maven 項目,參考該項目,再建立兩個僅名字不同的項目,内容基本一緻,對

application.yml

稍作修改:

springcloud-config-eureka-7001

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: eureka7001 #Eureka服務端的執行個體名稱
  client:
    register-with-eureka: false   #表示是否向注冊中心注冊自己
    fetch-registry: false   #為false表示自己是注冊中心
    service-url:    #監控頁面
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #叢集(關聯)
      defaultZone: http://eureka7002:7002/euraka/,http://eureka7003:7003/euraka/
           

springcloud-config-eureka-7002

server:
  port: 7002

#Eureka配置
eureka:
  instance:
    hostname: eureka7002 #Eureka服務端的執行個體名稱
  client:
    register-with-eureka: false   #表示是否向注冊中心注冊自己
    fetch-registry: false   #為false表示自己是注冊中心
    service-url:    #監控頁面
      defaultZone: http://eureka7001:7001/euraka/,http://eureka7003:7003/euraka/
           

springcloud-config-eureka-7003

server:
  port: 7003

#Eureka配置
eureka:
  instance:
    hostname: eureka7003 #Eureka服務端的執行個體名稱
  client:
    register-with-eureka: false   #表示是否向注冊中心注冊自己
    fetch-registry: false   #為false表示自己是注冊中心
    service-url:    #監控頁面
      defaultZone: http://eureka7002:7002/euraka/,http://eureka7001:7001/euraka/
           

因為我們本地端口預設為 localhost,實際上指向的是 127.0.0.1,為了更好地了解叢集的思想,我們将修改 C:WindowsSystem32driversetc 下的 host 檔案,内容如下:

127.0.0.1       eureka7001
127.0.0.1       eureka7002
127.0.0.1       eureka7003
           
注意:上述内容必須進行修改,否則沿用 localhost,無法得到正确的結果。

依次啟動這3個項目,通路 http://eureka7001:7001/ ,頁面展示結果為:

springcloud eureka叢集_SpringCloud入門學習之Eureka

接着修改 springcloud-provider-dept-8001 的配置檔案如下:

#Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept-8001   # 修改eureka上的預設描述資訊
    prefer-ip-address: true  # true,可以顯示服務的IP位址
           

啟動服務提供項目 springcloud-provider-dept-8001,再次通路 http://eureka7001:7001/,頁面展示結果為:

springcloud eureka叢集_SpringCloud入門學習之Eureka

依次再通路 http://eureka7002:7002/ 和 http://eureka7003:7003/ 時,是看不到服務的注冊,雖然這3個注冊中心構成了一個叢集,但是隻有當一個垮了之後,才會去通路下一個叢集節點。 Eureka Client 在發送注冊請求時,會按照 Eureka Server 叢集節點 serviceUrlList 順序逐個去嘗試,如果有一個請求成功了,那麼直接傳回response ,不再去向其他節點請求。

在本例中服務注冊請求在 eureka7001 中注冊成功,即 eureka7001 對應的 Eureka Server服務的狀态是UP,則不會向另外兩個節點(eureka7002,eureka7003)發送請求,相應地頁面上也就沒有顯示。一旦停止 eureka7001 服務注冊中心,則 dept-8001 服務會向 eureka7002 發送注冊請求。

關于此處的結果本人疑惑了很久,在網上一直沒有找到合适的答案,最後在 Eureka高可用之Client重試機制:RetryableEurekaHttpClient 一文中解開了自己的疑惑。

問題記錄

當叢集中服務注冊中心正常使用時,控制台會列印出以下内容:

2020-04-29 22:51:06.468 ERROR 14732 --- [t_eureka7003-16] c.n.e.cluster.ReplicationTaskProcessor   : Batch update failure with HTTP status code 404; discarding 1 replication tasks
2020-04-29 22:51:06.468 ERROR 14732 --- [et_eureka7002-3] c.n.e.cluster.ReplicationTaskProcessor   : Batch update failure with HTTP status code 404; discarding 1 replication tasks
2020-04-29 22:51:06.469  WARN 14732 --- [t_eureka7003-16] c.n.eureka.util.batcher.TaskExecutors    : Discarding 1 tasks of TaskBatchingWorker-target_eureka7003-16 due to permanent error
2020-04-29 22:51:06.469  WARN 14732 --- [et_eureka7002-3] c.n.eureka.util.batcher.TaskExecutors    : Discarding 1 tasks of TaskBatchingWorker-target_eureka7002-3 due to permanent error
2020-04-29 22:51:23.489  INFO 14732 --- [a-EvictionTimer] c.n.e.registry.AbstractInstanceRegistry  : Running the evict task with compensationTime 0ms
           

在網上一番查詢之後無果,如果有大神知道此處如何解決,望不吝賜教。

安全驗證

在 springcloud-config-eureka-7001 項目中,我們通路 http://eureka7001:7001/,該注冊中心的面闆是公開通路的。這裡可以簡單加入使用者名密碼,讓通路更安全。

1、添加依賴

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

2、配置 application.yml

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: eureka7001 #Eureka服務端的執行個體名稱
    prefer-ip-address: true
  client:
    register-with-eureka: false   #表示是否向注冊中心注冊自己
    fetch-registry: false   #為false表示自己是注冊中心
    service-url:    #監控頁面
      #單機
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@${eureka.instance.hostname}:${server.port}/eureka/
      #叢集(關聯)
#      defaultZone: http://eureka7002:7002/euraka/,http://eureka7003:7003/euraka/


spring:
  application:
    name: eureka-server
  security:
    user:
      name: admin
      password: admin
           

3、啟動該項目,再次通路 http://eureka7001:7001/,效果如下:

springcloud eureka叢集_SpringCloud入門學習之Eureka

擴充

CAP原則

springcloud eureka叢集_SpringCloud入門學習之Eureka

CAP 原則又稱CAP定理,指的是在一個分布式系統中, Consistency(一緻性)、 Availability(可用性)、Partition tolerance(分區容錯性),三者不可得兼。

CAP原則是NOSQL資料庫的基石。

分布式系統的CAP理論:理論首先把分布式系統中的三個特性進行了如下歸納:

  • 一緻性(C):在分布式系統中的所有資料備份,在同一時刻是否同樣的值。(等同于所有節點通路同一份最新的資料副本)
  • 可用性(A):在叢集中一部分節點故障後,叢集整體是否還能響應用戶端的讀寫請求。(對資料更新具備高可用性)
  • 分區容忍性(P):以實際效果而言,分區相當于對通信的時限要求。系統如果不能在時限内達成資料一緻性,就意味着發生了分區的情況,必須就目前操作在C和A之間做出選擇。

著名的CAP理論指出,一個分布式系統不可能同時滿足C(一緻性)、A(可用性)和P(分區容錯性)。由于分區容錯性在是分布式系統中必須要保證的,是以我們隻能在A和C之間進行權衡。在此Zookeeper保證的是CP, 而Eureka則是AP。

Zookeeper保證CP ​ 當向注冊中心查詢服務清單時,我們可以容忍注冊中心傳回的是幾分鐘以前的注冊資訊,但不能接受服務直接down掉不可用。也就是說,服務注冊功能對可用性的要求要高于一緻性。但是zk會出現這樣一種情況,當master節點因為網絡故障與其他節點失去聯系時,剩餘節點會重新進行leader選舉。問題在于,選舉leader的時間太長,30 ~ 120s, 且選舉期間整個zk叢集都是不可用的,這就導緻在選舉期間注冊服務癱瘓。在雲部署的環境下,因網絡問題使得zk叢集失去master節點是較大機率會發生的事,雖然服務能夠最終恢複,但是漫長的選舉時間導緻的注冊長期不可用是不能容忍的。 Eureka保證AP ​ Eureka看明白了這一點,是以在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點挂掉不會影響正常節點的工作,剩餘的節點依然可以提供注冊和查詢服務。而Eureka的用戶端在向某個Eureka注冊或時如果發現連接配接失敗,則會自動切換至其它節點,隻要有一台Eureka還在,就能保證注冊服務可用(保證可用性),隻不過查到的資訊可能不是最新的(不保證強一緻性)。除此之外,Eureka還有一種自我保護機制,如果在15分鐘内超過85%的節點都沒有正常的心跳,那麼Eureka就認為用戶端與注冊中心出現了網絡故障,此時會出現以下幾種情況:
  1. Eureka不再從注冊清單中移除因為長時間沒收到心跳而應該過期的服務
  2. Eureka仍然能夠接受新服務的注冊和查詢請求,但是不會被同步到其它節點上(即保證目前節點依然可用)
  3. 當網絡穩定時,目前執行個體新的注冊資訊會被同步到其它節點中

是以, Eureka可以很好的應對因網絡故障導緻部分節點失去聯系的情況,而不會像zookeeper那樣使整個注冊服務癱瘓。

詳情代碼通路: https://github.com/Acorn2/springcloud-eureka ,如有疑惑可聯系我。

參考文獻

Eureka高可用之Client重試機制:RetryableEurekaHttpClient

spring cloud eureka注冊原理-注冊失敗填坑

分布式理論(一) - CAP定理

SpringCloud學習1-服務注冊與發現(Eureka)

學習SpringCloud Eureka帶你從0到1