Spring Could-02-服務註冊和發現Eureka

1. Eureka簡介

1.1 什麼是Eureka

        和Consul和Zookeeper類似,Eureka是一個用於服務註冊和發現的組件.Eureka分爲Eureka Server和Eureka Client,Eureka Server爲Eureka服務註冊中心,Eureka Client爲Eureka客戶端.

1.2 爲什麼選擇Eureka

        首先,Eureka完全開源,是Netflix公司的開源產品,不斷迭代,在功能和性能上都非常穩定.
        其次,Eureka是Spring Could首選推薦的服務註冊與發現組件,與Spring Could其他組件可以無縫對接.
        最後,Eureka和其他組件,比如負載均衡組件Ribbon,熔斷器Hystrix,熔斷器監控組件Hystrix Dashboard組件,熔斷器聚合監控Turbine組件,以及網關Zuul組件相互配合,能夠很容易實現服務註冊、負載均衡、熔斷和智能路由等功能。這些組件都是由Netflix 公司開源的,一起被稱爲Netflix OSS 組件。Netflix OSS 組件由Spring Cloud 整合爲Spring Cloud Netflix 組件,它是Spring Cloud 構架微服務的核心組件,也是基礎組件。

1.3 Eureka的基本結構

Eureka 的基本架構其中主要包括以下3 種角色:

  • Register Service :服務註冊中心,它是一個Eureka Server ,提供服務註冊和發現的功能。
  • Provider Service :服務提供者,它是一個Eureka Client ,提供服務。
  • Consumer Service :服務消`費者,它是一個Eureka Cient ,消費服務。
    服務消費的基本過程如下:
            首先前要一個服務註冊中心Eureka Server ,服務提供者Eureka Client 向服務註冊中心Eureka Server 註冊,將自己的信息(比如服務名和服務的IP 地址等)通過阻ST A 凹的形式提交給服務註冊中心Eureka Server 。同樣,服務消費者Eureka Client 也向服務註冊中心Eureka Server 註冊,同時服務消費者獲取一份服務註冊列表的信息, 該列表包含了所有向脫務註冊中心Eureka Server 註冊的服務信息。獲取服務註冊列表信息之後,服務消費者就知道服務提供者的IP 地址,可以通過HTTP遠程調度來消費服務提供者的服務。

2. 編寫Eureka Server

源碼:

鏈接:https://pan.baidu.com/s/1UH49ooGk7LroKfrjoLiEng 
提取碼:k9fy

由於本案例有多個Spring Boot 工程,爲了方便管理,採用Maven 多Module 的結構,所以需要創建一個Maven 主工程:
在主工程Maven的pom.xml文件中引入依賴:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
                <!--使用此版本可能eureka-client無法引入-->
        <!--<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>-->
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

創建一個Module工程,命名爲eureka-server,作爲服務註冊中心Eureka Server的工程,繼承主工程的pom.xml依賴:

    <parent>
        <artifactId>eureka-01</artifactId>
        <groupId>com.wyc</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
     <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

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

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

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

        在工程的application.yml中做程序的相關配置,首先通過server.port指定Eureka Server的端口爲8761.eureka.instance.prefer-ip-address設置爲true,即提交IP信息.在默認情況下,Eureka Server會向自己註冊 ,這時需要配置eureka.client.registerWithEureka和eureka.client.fetchRegistry爲false,防止自己註冊自己.

server:
  port: 8761
eureka:
  instance:
    prefer-ip-address: true # 設置爲true,即提交IP信息
    status-page-url-path: /actuator/info #信息查詢的url link
    health-check-url-path: /actuator/health #健康檢查的url
    hostname: localhost
 # Eureka Server必須禁止向自己註冊 必須將eureka.client.register-with-eureka和eureka.client.fetch-registry 設置爲false
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

在啓動類上加上註解@EnableEurekaServer,開啓Eureka Server的功能:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * Created by : wyc
 * Created time 2020/6/22 22:21
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

啓動程序啓動類,訪問: http://localhost:8761/
在界面Instances currently registered with Eureka這一項沒有任何的註冊實例,是因爲還沒有Eureka Client向註冊中心Eureka Server 註冊實例.
在這裏插入圖片描述

3. 編寫Eureka Client

在主Maven工程中創建一個新的Module工程,命名爲eureka-client,該工程作爲Eureka Client向服務註冊中心Eureka Server註冊,在pom.xml中引入依賴,繼承主工程:


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

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

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

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

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

在application.yml做Eureka Client的相關配置,配置程序名爲eureka-client,程序端口爲8762,服務註冊地址爲 http://localhost:8761/eureka/

spring:
  application:
    name: eureka-client  # 程序名

server:
  port: 8762

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/   # 服務註冊地址

defaultZone爲默認的Zone,來源於AWS的概念.區域(Region)和可用區域(Availability Zone,AZ)是AWS的另外兩個概念.區域是指服務器所在的區域,比如北美洲,南美洲,歐洲和亞洲等,每一個區域由多個可用區組成.
在程序啓動類上加上@EnableEurekaClient開啓Eureka Client功能

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * Created by : wyc
 * Created time 2020/6/23 7:08
 */
@EnableEurekaClient
@SpringBootApplication
public class EurekaClientApplication {

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

啓動Eureka Server工程,然後啓動Eureka Client工程,控制檯會打印下面信息:
在這裏插入圖片描述
啓動服務後,在瀏覽器上訪問Eureka Server主界面: http://localhost:8761/
在這裏插入圖片描述
在主頁上的Instances currently registered with Eureka 選項中己經有一個實例被註冊, Application 爲EUREKA-CLIENT, Staus 爲UP( 在線) , 端口爲8762 。
在Eureka Client工程中寫一個API接口.新建一個類HiController.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by : wyc
 * Created time 2020/6/23 21:48
 */
@RestController
public class HiController {

    @Value("${server.port}")
    private String port;

    @GetMapping("/hi")
    public String home(@RequestParam String name){
        return "hi "+name+",i am from port:" +port;
    }
}

在瀏覽器上訪問http://localhost:8762/hi?name=forezp
在這裏插入圖片描述

4. 源碼分析Eureka

4.1 Eureka的一些概念

(1) Register: 服務註冊
        當Eureka Client 向Eureka Server 註冊時, Eureka Client 提供自身的元數據,比如IP 地址、端口、運行狀況指標的Url、主頁地址等信息。
(2) Renew: 服務續約
        Eureka Client 在默認的情況下會每隔30 秒發送一次心跳來進行服務續約。通過服務續約來告知Eureka Server該Eureka Client 仍然可用,沒有出現故障。正常情況下,如果Eureka Server在90 秒內沒有收到Eureka Client 的心跳, Eureka Server 會將Eureka Client 實例從註冊列表中刪除。
注意:官方建議不要更改服務續約的間隔時間。
(3) Fetch Registries: 獲取服務註冊列表信息
        Eureka Client 從Eureka Server 獲取服務註冊表信息,井將其緩存在本地。Eureka Client 會使用服務註冊列表信息查找其他服務的信息,從而進行遠程調用。該註冊列表信息定時(每30 秒) 更新一次,每次返回註冊列表信息可能與Eureka Client 的緩存信息不同, Eureka Client會自己處理這些信息。如果由於某種原因導致註冊列表信息不能及時匹配, Eureka Client 會重新獲取整個註冊表信息。Eureka Server 緩存了所有的服務註冊列表信息,並將整個註冊列表以及每個應用程序的信息進行了壓縮,壓縮內容和沒有壓縮的內容完全相同。Eureka Client 和Eureka Server 可以使用JSON 和XML 數據格式進行通信。在默認的情況下, Eureka Client 使用JSON 格式的方式來獲取服務註冊列表的信息。
(4) Cancel: 服務下線
        Eureka Client 在程序關閉時可以向Eureka Server 發送下線請求。發送請求後,該客戶端的實例信息將從Eureka Server 的服務註冊列表中刪除。該下線請求不會自動完成,需要在程序關閉時調用以下代碼:

DiscoveryManager.getinstance().shutdownComponent();

(5) Eviction: 服務剔除
        在默認情況下,當Eureka Client 連續90 秒沒有向Eureka Server 發送服務續約(即心跳) 時, Eureka Server 會將該服務實例從服務註冊列表刪除,即服務剔除。

4.2 Eureka的高可用架構

https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance
在這裏插入圖片描述
        架構中有兩個角色,即Eureka Server 和Eureka Client 。而EurekaClient 又分爲Applicaton Service 和Application Client , 即服務提供者和服務消費者。每個區域有一個Eureka 集羣, 並且每個區域至少有一個Eureka Server 可以處理區域故障, 以防服務器癱瘓。
        Eureka Client 向Eureka Server 註冊, 將自己的客戶端信息提交給Eureka Server 。然後,Eureka Client 通過向Eureka Server 發送心跳(每30 秒一次)來續約服務。如果某個客戶端不能持續續約,那麼Eureka Server 斷定該客戶端不可用, 該不可用的客戶端將在大約90 秒後從Eureka Serve 服務註冊列表中刪除。
        服務註冊列表信息和服務續約信息會被複制到集羣中的每個Eureka Serve 節點。來自任何區域的Eureka Client 都可以獲取整個系統的服務註冊列表信息。根據這些註冊列表信息, Application Client 可以遠程調用Applicaton Service 來消費服務。

4.3 爲什麼Eureka Client獲取服務實例這麼慢

(1) Eureka Client 的註冊延遲
        Eureka Client 啓動之後,不是立即向Eureka Server 註冊的,而是有一個延遲向服務端註冊的時間。通過跟蹤源碼,可以發現默認的延遲時間爲40 秒。
源碼在eureka-client-1.9.8.jar的DefaultEurekaClientConfig類中:

    public int getInitialInstanceInfoReplicationIntervalSeconds() {
        return this.configInstance.getIntProperty(this.namespace + "appinfo.initial.replicate.time", 40).get();
    }

(2) Eureka Server 的響應緩存
        Eureka Server 維護每30 秒更新一次響應緩存,可通過更改配置eureka.server.responseCacheUpdatelntervalMs 來修改。所以即使是剛剛註冊的實例,也不會立即出現在服務註冊列表中。
(3) Eureka Client 的緩存
        Eureka Client 保留註冊表信息的緩存。該緩存每30 秒更新一次(如前所述)。因此, Eureka Client刷新本地緩存並發現其他新註冊的實例可能需要30 秒。
(4) LoadBalancer 的緩存
        Ribbon 的負載平衡器從本地的Eureka Client 獲取服務註冊列表信息。Ribbon 本身還維護了緩存,以避免每個請求都需要從Eureka Client 獲取服務註冊列表。此緩存每3 0 秒刷新一次(可由ribbon.ServerListRefreshlnterval 配置) ,所以可能至少需要30 秒的時間才能使用新註冊的實例。
        綜上因素,一個新註冊的實例,默認延遲40 秒向服務註冊中心註冊,所以不能馬上被Eureka Server 發現。另外,剛註冊的Eureka Client 也不能立即被其他服務調用,原因是調用方由於各種緩存沒有及時獲取到最新的服務註冊列表信息。

4.4 Eureka的自我保護模式

        當有一個新的Eureka Server 出現時,它嘗試從相鄰Peer 節點獲取所有服務實例註冊表信息。如果從相鄰的Peer 節點獲取信息時出現了故障, Eureka Server 會嘗試其他的Peer 節點。如果Eureka Serve 能夠成功獲取所有的服務實例信息,則根據配置信息設置服務續約的閥值。在任何時間,如果Eureka Serve 接收到的服務續約低於爲該值配置的百分比(默認爲15 分鐘內低於85% ),則服務器開啓自我保護模式,即不再剔除註冊列表的信息。
         這樣做的好處在於,如果是Eureka Server 自身的網絡問題而導致Eureka Client 無法續約,Eureka Client 的註冊列表信息不再被刪除,也就是Eureka Client 還可以被其他服務消費。
        在默認情況下, Eureka Server 的自我保護模式是開啓的,如果需要關閉,則在配置文件添加以下代碼:

eureka:
  server:
    enable-self-preservation: false

5. 構建高可用的Eureka Server集羣

源碼:

鏈接:https://pan.baidu.com/s/1UQCYaxdmo0c6Yo8aWIs3hg 
提取碼:07pn

在實際上項目中,可能有幾十個或者幾百個的微服務實例,這時Eureka Server承擔了非常高的負載.由於Eureka Server在微服務架構中有着舉足輕重的作用,所以需要構建高可用性的Eureka Server集羣.
該部分源碼是在上面代碼的基礎上進行改造的.
首先更改eureka-server的配置文件application.yml,在該配置文件中採用多profile的格式:

#定義了兩個profile 文件,分別爲peer1 和peer2 ,它們的hostname 分別爲peerl
#和peer2 。在實際開發中,可能是具體的服務器F 地址,它們的端口分別爲87618762
#因爲是在本地搭建Eureka Server 集羣,所以需要修改本地的host文件,windows系統的電腦
#在C:\Windows\System32\drivers\etc\hosts 中修改
# 127.0.0.1 peer1
# 127.0.0.1 peer2
---
spring:
   profiles: peer1
server:
   port: 8761
eureka:
  instance:
    hostname: peer1
  client:
    service-url:
      defaultZone: http://peer2:8762/eureka/ # 注意: peer1要連接peer2的eureka地址
  server:
      peer-node-read-timeout-ms: 2000
---
spring:
   profiles: peer2
server:
   port: 8762
eureka:
  instance:
    hostname: peer2
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/ # 注意: peer2要連接peer1的eureka地址
  server:
    peer-node-read-timeout-ms: 2000

        定義了兩個profile 文件,分別爲peerl 和peer2 ,它們的hostname 分別爲peer1和peer2 。在實際開發中,可能是具體的服務器F 地址,它們的端口分別爲8761 和8762因爲是在本地搭建Eureka Server 集羣,所以需要修改本地的host文件,windows系統的電腦在C:\Windows\System32\drivers\etc\hosts 中修改

127.0.0.1 peer1
127.0.0.1 peer2

啓動Eureka Server 開始
第一種方法:
在這裏插入圖片描述
將啓動類複製一份改名爲peer1,配置啓動參數
在這裏插入圖片描述
在這裏插入圖片描述
同樣複製一份給名爲peer2
在這裏插入圖片描述
第二種方法:
打成jar包運行:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
進入eureka-server-1.0-SNAPSHOT.jar所在的目錄,cmd打開黑窗口執行命令:

java -jar eureka-server-1.0-SNAPSHOT.jar --spring.profiles.active=peer1

cmd新打開一個黑窗口執行命令:

java -jar eureka-server-1.0-SNAPSHOT.jar --spring.profiles.active=peer2

啓動Eureka Server 結束

修改eureka-client的配置文件application.yml

spring:
  application:
    name: eureka-client  # 程序名

server:
  port: 8763

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/   # 服務註冊地址

啓動eureka-client工程,訪問: http://peer1:8761/ 可以發現,eureka-client已向peer1結點的Eureka Server註冊了,並且在DS Replicas選項中顯示了結點peer2:
在這裏插入圖片描述
這時eureka-client工程的配置文件中並沒有指定向peer2的節點Eureka Server註冊,訪問Eureka Server的節點peer2的主界面,界面的Url地址爲: http://peer1:8762/ 。節點peer2的主界面顯示Eureka Client已經向peer2節點註冊,可見peer1的註冊列表信息已經同步到了peer2節點,節點peer2的主界面展示如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章