SpringCloud系列之一---搭建高可用的Eureka注冊中心

前言

本篇文章主要介紹的是SpringCloud相關知識、微服務架構以及搭建服務注冊與發現的服務模塊(Eureka)以及Eureka集群。

GitHub源碼鏈接位于文章底部。

什么是SpringCloud

Spring Cloud 是一系列框架的有序集合。 它利用 Spring Boot 的開發便利性巧妙地簡化了分布式系統基礎設施的開發, 如服務發現注冊、配置中心、消息總線、負載均衡、熔斷器、數據監控等,都可以用 Spring Boot 的開發風格做到一鍵啟動和部署。Spring 并沒有復制造輪子,它只是將目前各家公司開發的比較成熟、經得起實際考驗的服務框架組合起來,通過 SpringBoot 風格進行再封裝屏蔽掉了復雜的配置和實現原理,最終開發者留出了一套簡單易懂、易部署和易維護的分布式系統開發工具包。

SpringCloud 與 SpringBoot 的關系

Spring Boot是Spring的一套快速配置腳手架,可以基于Spring Boot快速開發單個微服務,Spring Cloud是一個基于Spring Boot實現的云應用開發工具;Spring Boot專注于快速、方便集成的單個微服務個體,Spring Cloud關注全局的服務治理框架;Spring Boot 使用了默認大于配置的理念,很多集成方案已經幫你選擇好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot來實現,可以不基于Spring Boot嗎?不可以。
Spring Boot可以離開Spring Cloud獨立使用開發項目, 但是Spring Cloud離不開Spring Boot,屬于依賴的關系。

SpringCloud 主要組件

用途 組件
服務發現 Netflix Eureka
服務調用 Netflix Feign
熔斷器 Netflix Hystrix
服務網關 Netflix Zuul
分布式配置 Spring Cloud Config
消息總線 Spring Cloud Bus

SpringCloud 與 Dubbo 對比

dubbo由于是二進制的傳輸,占用帶寬會更少。
springCloud是http協議傳輸,帶寬會比較多,同時使用http協議一般會使用JSON報文,消耗會更大。
dubbo的開發難度較大,原因是dubbo的jar包依賴問題很多大型工程無法解決。
Dubbo只是實現了服務治理,而Spring Cloud下面有很多個子項目分別覆蓋了微服務架構下的方方面面,服務治理只是其中的一個方面,一定程度來說,Dubbo 只是 Spring CloudNetflix 中的一個子集。

Dubbo SpringCloud
服務注冊中心 Zookeeper Spring Cloud Netflix Eureka
服務調用方式 RPC REST API
服務網關 Spring Cloud Netflix Zuul /Spring Cloud GateWay
熔斷器 不完善 Spring Cloud Netflix Hystrix
分布式配置 Spring Cloud Config
服務跟蹤 Spring Cloud Sleuth
消息總線 Spring Cloud Bus
數據流 Spring Cloud Stream
批量任務 Spring Cloud Task
...... ...... ......

SpringCloud 的版本

SpringCloud 由于是一系列框架組合,為了避免與包含的自框架版本產生混淆,采用倫敦地鐵站的名稱作為版本名,形式為版本名+里程碑號。M9為第 9 個里程碑版本。以下是SpringBoot與Spring Cloud版本的對照表。

Spring Boot Spring Cloud
1.2.x Angel 版本
1.3.x Brixton 版本
1.4.x Camden 版本
1.5.x Dalston 版本、 Edgware 版本
2.0.x Finchley 版本

服務發現組件 Eureka

Eureka是Netflix 開發的服務發現框架,SpringCloud將它集成在自己的子項目spring-cloud-netflix中,實現SpringCloud的服務發現功能。Eureka包含兩個組件:Eureka Server和Eureka Client。

Eureka Server提供服務注冊服務,各個節點啟動后,會在Eureka Server中進行注冊,這樣EurekaServer中的服務注冊表中將會存儲所有可用服務節點的信息,服務節點的信息可以在界面中直觀的看到。

自我保護機制

Eureka Client是一個java客戶端,用于簡化與Eureka Server的交互,客戶端同時也就別一個內置的、使用輪詢(round-robin)負載算法的負載均衡器。在應用啟動后,將會向EurekaServer發送心跳,默認周期為30秒,如果Eureka Server在多個心跳周期內沒有接收到某個節點的心跳,Eureka Server將會從服務注冊表中把這個服務節點移除(默認90秒)。但是在短時間內丟失大量的實例心跳,這時候EurekaServer會開啟自我保護機制,Eureka不會踢出該服務,這就是Eureka的自我保護機制。
產生原因:在開發測試時,需要頻繁地重啟微服務實例,但是我們很少會把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基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客戶端與 Eureka 服務端進行交互的地址
      defaultZone: http://127.0.0.1:${server.port}/eureka
    #是否將自己注冊到Eureka服務中,本身就是注冊中心所以無需注冊
    register-with-eureka: false
    #是否從Eureka中檢索注冊信息,本身就是注冊中心所以無需檢索
    fetch-registry: false
  server:
    # 測試時關閉自我保護機制,保證不可用服務及時踢出
    enable-self-preservation: false
    ##剔除失效服務間隔
    eviction-interval-timer-in-ms: 2000

在eureka client配置文件中加上:

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客戶端與 Eureka 服務端進行交互的地址
      defaultZone: http://127.0.0.1:8100/eureka/
  # 心跳檢測檢測與續約時間
  # 測試時將值設置設置小些,保證服務關閉后注冊中心能及時踢出服務
  instance:
    # Eureka客戶端向服務端發送心跳的時間間隔,單位為秒(客戶端告訴服務端自己會按照該規則)
    lease-renewal-interval-in-seconds: 1
    # Eureka服務端在收到最后一次心跳之后等待的時間上限,單位為秒,超過則剔除(客戶端告訴服務端按照此規則等待自己)
    lease-expiration-duration-in-seconds: 2

但在生產環境,不會頻繁重啟,所以,一定要把自我保護機制打開,否則網絡一旦中斷,就無法恢復。
當然關于自我保護還有很多個性化配置,這里不詳細說明。

注意考慮網絡不可達情況下:調用接口冪等、重試、補償等。

創建工程

1. 目前工程結構
image
2. 首先創建父工程springcloud,以后這個工程下存放子工程eureka,feign,zuul等組件

將該工程的src文件夾刪除,在pom文件中添加依賴

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <!--引用倉庫-->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <!--管理依賴,子項目中的依賴不用列出版本號-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

創建eureka父工程

新建springcloud-eureka項目,在pom文件中添加依賴

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

創建eureka服務端

以springcloud-eureka為父工程,新建springboot-eureka-server項目,這里不需要添加eureka-server依賴,因為父工程中有了。

1. 添加配置

在resources目錄中添加application.yml文件,在文件中添加配置

#服務端口號
server:
  port: 8100

spring:
  application:
    name: eureka-server
    
#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客戶端與 Eureka 服務端進行交互的地址
      defaultZone: http://127.0.0.1:${server.port}/eureka
    #是否將自己注冊到Eureka服務中,本身就是注冊中心所以無需注冊
    register-with-eureka: false
    #是否從Eureka中檢索注冊信息,本身就是注冊中心所以無需檢索
    fetch-registry: false
  server:
    # 測試時關閉自我保護機制,保證不可用服務及時踢出
    enable-self-preservation: false
    ##剔除失效服務間隔
    eviction-interval-timer-in-ms: 2000

2. 啟動類

java目錄下創建com.lxg二級目錄,然后創建EurekaServerApp啟動類

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

在類上加EnableEurekaServer注解,啟動EurekaServer。

創建eureka客戶端

以springcloud-eureka為父工程,新建springboot-eureka-client項目。在pom文件中添加依賴:

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
1. 添加配置

在resources目錄中添加application.yml文件,在文件中添加配置

#端口號
server:
  port: 9100

spring:
  application:
    name: eureka-client

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客戶端與 Eureka 服務端進行交互的地址
      defaultZone: http://127.0.0.1:8100/eureka/
  # 心跳檢測檢測與續約時間
  # 測試時將值設置設置小些,保證服務關閉后注冊中心能及時踢出服務
  instance:
    # Eureka客戶端向服務端發送心跳的時間間隔,單位為秒(客戶端告訴服務端自己會按照該規則)
    lease-renewal-interval-in-seconds: 1
    # Eureka服務端在收到最后一次心跳之后等待的時間上限,單位為秒,超過則剔除(客戶端告訴服務端按照此規則等待自己)
    lease-expiration-duration-in-seconds: 2
2. 啟動類

java目錄下創建com.lxg二級目錄,然后創建EurekaClientApp啟動類,這里啟動類名稱不能為EurekaClient,否則會起沖突導致啟動失敗。類上使用EnableEurekaClient注解。

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

測試

先啟動服務端,再啟動客戶端,訪問127.0.0.1:8100 ,訪問監控頁面。


image

圖中的紅色字體是在提示已經關閉了eureka的自我保護機制,此時如果關閉客戶端,頁面中的服務就會被踢出,如果沒有關閉的話,即使客戶端關閉了,服務依然會存在。

高可用注冊中心(Eureka集群)

在微服務中,注冊中心非常核心,可以實現服務治理,如果一旦注冊出現故障的時候,可能會導致整個微服務無法訪問,在這時候就需要對注冊中心實現高可用集群模式。

Eureka高可用原理

默認情況下Eureka是讓服務注冊中心,不注冊自己,但是在集群中,需要設置能注冊自己,因為這兩個屬性默認為true,只需要不寫就行了。

###使該注冊中心注冊自己
    register-with-eureka: true
###需要去注冊中心上檢索服務
    fetch-registry: true

Eureka高可用實際上將自己作為服務向其他服務注冊中心注冊自己,這樣就可以形成一組相互注冊的服務注冊中心,從而實現服務清單的互相同步,達到高可用效果。

Eureka集群環境搭建

新增server1,server2,server3三個節點。


image

server1配置:

#服務端口號
server:
  port: 8100

spring:
  application:
    name: eureka-server

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客戶端與 Eureka 服務端進行交互的地址
      defaultZone: http://127.0.0.1:8200/eureka,http://127.0.0.1:8300/eureka
  server:
    # 測試時關閉自我保護機制,保證不可用服務及時踢出
    enable-self-preservation: false
    ##剔除失效服務間隔
    eviction-interval-timer-in-ms: 2000

server2配置:

#服務端口號
server:
  port: 8200

spring:
  application:
    name: eureka-server

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客戶端與 Eureka 服務端進行交互的地址
      defaultZone: http://127.0.0.1:8100/eureka,http://127.0.0.1:8300/eureka
  server:
    # 測試時關閉自我保護機制,保證不可用服務及時踢出
    enable-self-preservation: false
    ##剔除失效服務間隔
    eviction-interval-timer-in-ms: 2000

server3配置:

#服務端口號
server:
  port: 8300

spring:
  application:
    name: eureka-server

#eureka基本配置信息
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8100/eureka,http://127.0.0.1:8200/eureka
  server:
    # 測試時關閉自我保護機制,保證不可用服務及時踢出
    enable-self-preservation: false
    ##剔除失效服務間隔
    eviction-interval-timer-in-ms: 2000

然后修改客戶端的配置,因為以前是單個eureka注冊中心,只需要注冊進一個地址就行了,現在要注冊進所有的注冊中心。

#端口號
server:
  port: 9100

spring:
  application:
    name: eureka-client

#eureka基本配置信息
eureka:
  client:
    service-url:
      #Eureka 客戶端與 Eureka 服務端進行交互的地址
      #單機
      #defaultZone: http://127.0.0.1:8100/eureka/
      #集群
      defaultZone: http://127.0.0.1:8100/eureka/,http://127.0.0.1:8200/eureka/,http://127.0.0.1:8300/eureka/
  # 心跳檢測檢測與續約時間
  # 測試時將值設置設置小些,保證服務關閉后注冊中心能及時踢出服務
  instance:
    # Eureka客戶端向服務端發送心跳的時間間隔,單位為秒(客戶端告訴服務端自己會按照該規則)
    lease-renewal-interval-in-seconds: 1
    # Eureka服務端在收到最后一次心跳之后等待的時間上限,單位為秒,超過則剔除(客戶端告訴服務端按照此規則等待自己)
    lease-expiration-duration-in-seconds: 2

先啟動所有的服務端節點,再啟動客戶端。訪問localhost:8100 ,localhost:8200 ,localhost:8300 都能進入eureka的界面,同時看到客戶端服務和其他的注冊中心。這個時候即使有某一個節點掛了,服務依然是可用的,而且性能肯定比單機版要好。

搭建eureka集群有幾點需要注意的:

1.與先前獨立運行注冊不同,注意defaultZone屬性,它的值為除了自己以外的所有eureka節點的地址,以英文逗號分割。
2.去掉fetch-registry 與 register-with-eureka配置(其實這樣做就會取對應的默認值,兩個值均為true),需要讓自己能被注冊和檢索。
3.啟動第一個注冊中心時會報Cannot execute request on any known server的錯誤,暫時不管它,實際上eureka注冊中心的ui界面是能打開的,當所有的節點啟動完畢,就能找到服務,此錯誤就會消失。
4.所有注冊中心的節點的spring.application.name必須保持一致。
5.當客戶端需要往注冊中心集群注冊服務時defaultZone屬性需要把所有節點地址都加上,如果像單節點一樣的話,你連接的那個節點掛了,集群中其他節點就無法獲取到該服務,也就不能達到高可用。

本文GitHub源碼:https://github.com/lixianguo5097/springcloud/tree/master/springcloud-eureka

CSDN:https://blog.csdn.net/qq_27682773
簡書:http://www.lxweimin.com/u/e99381e6886e
博客園:https://www.cnblogs.com/lixianguo

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容