2019-07-07

Eureka簡單學(xué)習(xí)

這是個人學(xué)習(xí)筆記,如有錯誤,還望海涵、斧正。

一、簡介

Eureka 是一個專門用于服務(wù)發(fā)現(xiàn)的服務(wù)器,一些服務(wù)注冊到該服務(wù)器,而另一些服務(wù)通過該服務(wù)器查找其所要調(diào)用執(zhí)行的服務(wù)。

其本身是一個基于 REST 的服務(wù),主要用于定位運(yùn)行在 AWS 域中的中間層服務(wù),以達(dá)到負(fù)載均衡和中間層服務(wù)故障轉(zhuǎn)移的目的。

可以充當(dāng)服務(wù)發(fā)現(xiàn)服務(wù)器的組件很多,例如 Zookeeper、Consul、Eureka 等。

下圖是一張Eureka的體系架構(gòu):

eureka_architecture.png

(圖片引自:https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance

二、使用方法

通過idea的Spring Initializr創(chuàng)建一個springcloud項(xiàng)目

創(chuàng)建步驟1.png

1.創(chuàng)建server

(1)導(dǎo)入Eureka Server依賴

創(chuàng)建步驟2.png

(2)修改application配置文件為yml格式

? 直接改后綴名就行(個人習(xí)慣,yml更舒服)

(3)修改配置文件

eureka:
  instance:
    hostname: localhost  #指定Eureka主機(jī)
  client:
    register-with-eureka: false  #是否向Eureka注冊自己(主機(jī)不注冊自己)
    fetch-registry: false  #指定此客戶端是否可以獲取eureka的注冊信息
    service-url: #暴露服務(wù)中心地址
        defaultZone: http://localhost:8081/eureka
server:
  port: 8081

(4)啟動

給啟動類加上 開啟Eureka的注解 @EnableEurekaServer

@SpringBootApplication
@EnableEurekaServer
public class TigerApplication {

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

}

啟動項(xiàng)目,訪問項(xiàng)目地址http://localhost:8081/,成功啟動后如下圖

server啟動.png

2.創(chuàng)建provider

有兩種方式供選擇:

第一種方式

引用依賴

嫌麻煩就直接復(fù)制剛剛創(chuàng)建的server項(xiàng)目,重命名為eureka-provider-8082。然后手動修改pom文件(復(fù)制粘貼下面的的依賴就行)

*刪掉刪掉刪掉刪掉原來的server依賴,就是下面這個:

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

然后引入一個client的依賴:

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

provider引入上面兩個依賴就夠了,但是為了和數(shù)據(jù)庫做連接,我們還要引入下面的依賴:

     <!--數(shù)據(jù)庫連接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--修改MySQL驅(qū)動版本-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
            <scope>runtime</scope>
        </dependency>
        <!-- jpa -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

除了數(shù)據(jù)庫,作為一個web項(xiàng)目還要引入以下依賴:

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

下面兩個是輔助用的依賴,可引可不引。lombok用來生成實(shí)體類的get/set方法,actuator用來配置監(jiān)控終端的顯示信息

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
         <!--actuator 依賴-->
        <dependency> <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
配置

配置文件(info為actuator配置)

eureka:
  instance:
    hostname: localhost #指定Eureka主機(jī)
    instance-id: eureka-provider-8082 #指定當(dāng)前客戶端在服務(wù)中心注冊的名稱

  # 指定服務(wù)中心
  client:
    # register-with-eureka: true #是否向Eureka注冊自己(主機(jī)不注冊自己)
    # fetch-registry: true #指定此客戶端是否可以獲取eureka的注冊信息
    service-url: #暴露服務(wù)中心地址
        defaultZone: http://localhost:8081/eureka
server:
  port: 8082

spring:
  # 指定當(dāng)前微服務(wù)對外暴露的名稱
  application:
    name: eureka-provider-1
  # 配置spring-data-jap
  jpa:
   # 是否在spring容器啟時創(chuàng)建表
    generate-ddl: true
    show-sql: true
    hibernate:
      ddl-auto: none


 # 配置數(shù)據(jù)源
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///test_my?useUnicode=true&amp;characterEncoding=utf8
    username: root
    password: root

logging:
  # 設(shè)置日志輸出格式
  pattern:
    console: level-%level %msg%n
  level:
    root: info
    org.hibernate: info
    org.hibernate.type.descriptor.sql.BasicBinder: trace
    org.hibernate.type.descriptor.sql.BasicExtractor: trace
    com.abc.provider: debug

# Eureka工作界面中instance-id處鏈接的信息 參數(shù)都是自定義的
info:
    author: tiger
    app.name: eureka-provider-8082
    app.desc: a desc





第二種方式

重新創(chuàng)建一個項(xiàng)目,在依賴處選擇照下圖選擇就行

clientconfig.png
配置

配置文件:

由于數(shù)據(jù)庫連接驅(qū)動不同,所以datasource配置和第一種方法的不太一樣。其他配置則一致

eureka:
  instance:
    hostname: localhost #指定Eureka主機(jī)
    instance-id: eureka-provider-8082 #指定當(dāng)前客戶端在服務(wù)中心注冊的名稱

  # 指定服務(wù)中心
  client:
    # register-with-eureka: true #是否向Eureka注冊自己(主機(jī)不注冊自己)
    # fetch-registry: true #指定此客戶端是否可以獲取eureka的注冊信息
    service-url: #暴露服務(wù)中心地址
        defaultZone: http://localhost:8081/eureka
server:
  port: 8083

spring:
  # 指定當(dāng)前微服務(wù)對外暴露的名稱
  application:
    name: eureka-provider-1
  # 配置spring-data-jap
  jpa:
   # 是否在spring容器啟時創(chuàng)建表
    generate-ddl: true
    show-sql: true
    hibernate:
      ddl-auto: none


 # 配置數(shù)據(jù)源
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///test_my?useUnicode=true&amp&characterEncoding=utf8&serverTimezone=GMT
    username: root
    password: root

logging:
  # 設(shè)置日志輸出格式
  pattern:
    console: level-%level %msg%n
  level:
    root: info
    org.hibernate: info
    org.hibernate.type.descriptor.sql.BasicBinder: trace
    org.hibernate.type.descriptor.sql.BasicExtractor: trace
    com.abc.provider: debug

# Eureka工作界面中instance-id處鏈接的信息 參數(shù)都是自定義的
info:
    author: tiger
    app.name: eureka-provider-8082
    app.desc: a desc





啟動

在啟動類上加上啟動注解@EnableEurekaClient,項(xiàng)目跑起來后在 http://localhost:8081/ 上可以看到已經(jīng)注冊進(jìn)去了

注冊provider.png

至于controller service dao entity 這些,相信大家都會的,這里就不寫出來了。

3.創(chuàng)建consumer

依賴

consumer依賴.png

配置

eureka:
  instance:
    hostname: localhost #指定Eureka主機(jī)
    instance-id: eureka-consumer-8083 #指定當(dāng)前客戶端在服務(wù)中心注冊的名稱

  # 指定服務(wù)中心
  client:
    # register-with-eureka: true #是否向Eureka注冊自己(主機(jī)不注冊自己)
    # fetch-registry: true #指定此客戶端是否可以獲取eureka的注冊信息
    service-url: #暴露服務(wù)中心地址
        defaultZone: http://localhost:8081/eureka
server:
  port: 8083

spring:
  # 指定當(dāng)前微服務(wù)對外暴露的名稱
  application:
    name: eureka-consumer-1


# Eureka工作界面中instance-id處鏈接的信息 參數(shù)都是自定義的
info:
    author: tiger
    app.name: eureka-provider-8082
    app.desc: a desc

啟動

啟動類加上注解@EnableEurekaClient,啟動完成后在 http://localhost:8081/ 上可以看到已經(jīng)注冊進(jìn)去了

注冊成功consumer.png

4.創(chuàng)建集群

由于都使用同一個機(jī)器進(jìn)行測試,先配一下host文件,加入以下配置

#eureka server 
127.0.0.1  eureka-server-8081 
127.0.0.1  eureka-server-8088
127.0.0.1  eureka-server-8089

然后將之前端口為8081的eureka-server項(xiàng)目復(fù)制兩份,共三個項(xiàng)目組成集群

三個項(xiàng)目的yml文件配置如下:

eureka-server-8081:

eureka:
  instance:
    hostname: eureka-server-8081  #指定Eureka主機(jī)
  client:
    register-with-eureka: false  #是否向Eureka注冊自己(主機(jī)不注冊自己)
    fetch-registry: false  #指定此客戶端是否可以獲取eureka的注冊信息
    service-url: #暴露服務(wù)中心地址
        defaultZone: http://eureka-server-8081:8081/eureka,http://eureka-server-8088:8088/eureka,http://eureka-server-8089:8089/eureka
server:
  port: 8081

eureka-server-8088:

eureka:
  instance:
    hostname: eureka-server-8088  #指定Eureka主機(jī)
  client:
    register-with-eureka: false  #是否向Eureka注冊自己(主機(jī)不注冊自己)
    fetch-registry: false  #指定此客戶端是否可以獲取eureka的注冊信息
    service-url: #暴露服務(wù)中心地址
        defaultZone: http://eureka-server-8081:8081/eureka,http://eureka-server-8088:8088/eureka,http://eureka-server-8089:8089/eureka
server:
  port: 8088

eureka-server-8089:

eureka:
  instance:
    hostname: eureka-server-8089  #指定Eureka主機(jī)
  client:
    register-with-eureka: false  #是否向Eureka注冊自己(主機(jī)不注冊自己)
    fetch-registry: false  #指定此客戶端是否可以獲取eureka的注冊信息
    service-url: #暴露服務(wù)中心地址
        defaultZone: http://eureka-server-8081:8081/eureka,http://eureka-server-8088:8088/eureka,http://eureka-server-8089:8089/eureka
server:
  port: 8089

可以看到,要組成集群,則將所有的server的地址都配置到defaultZone上即可,每個地址通過逗號分隔(注意逗號不能有空格,因?yàn)閥ml里空格是有效字符)

然后分別啟動三個項(xiàng)目,得出以下界面,即為集群搭建成功:

http://eureka-server-8081:8081/、

集群1.png

http://eureka-server-8088:8088/、

集群2.png

http://eureka-server-8089:8089/

集群3.png

這時候啟動 provider 和 consumer 的微服務(wù),只要 provider 和 consumer 的 defaultZone 中配了上面任意一個server 的地址,就可以在三個 server 中都注冊。

當(dāng)然,provider 和 consumer 最好將三個地址都配上,這樣某個 server 掛掉后, 還能繼續(xù)使用其他 server

啟動 provider 和 consumer 后,我們查看三個 server 的界面,他們都會存在同樣的服務(wù)列表如下:

服務(wù)列表.png

三、底層原理

Eureka 注冊信息管理機(jī)制

描述

Eureka 的注冊信息則是通過“緩存 + 存儲”的雙 Map 機(jī)制完成的。

Eureka 的數(shù)據(jù)存儲分了兩層:數(shù)據(jù)存儲層和數(shù)據(jù)緩存層。
Eureka Client 在拉取服務(wù)信息時,先從緩存層獲取,若獲取不到,則先把數(shù)據(jù)存儲層的數(shù)據(jù)加載到緩存中,再從緩存中獲取。(也就是說,Eureka Client永遠(yuǎn)都是從緩存層拉取服務(wù)信息)

數(shù)據(jù)存儲層

數(shù)據(jù)存放位置

數(shù)據(jù)存儲層中的信息是存放在內(nèi)存中的,不做持久化。

原因:

1.若不是所有 Eureka Server 都宕機(jī),則宕機(jī)的 Server 重啟后,會從其它 Server 中同步注冊信息

2.若全部 Eureka Server 宕機(jī),則重新接受客戶端的注冊

數(shù)據(jù)存放方式

用于存儲注冊信息的是一個雙層 ConcurrentHashMap。如:Map<String, Map<String, Lease>>

第一層的 key 是 spring.application.name

第二層的 key 是微服務(wù)主機(jī)的 InstanceId(即配置文件里的 instance-id),value 是 Lease 對象(續(xù)租對象)。Lease 對象包含了服務(wù)詳情和服務(wù)治理相關(guān)的信息。

當(dāng)出現(xiàn)客戶端向 Eureka 服務(wù)器提交 register、renew 和 cancel 請求時,都會修改這 個雙層 Map 中的數(shù)據(jù)。

數(shù)據(jù)緩存層

一級緩存 readOnlyCacheMap

一級緩存中的數(shù)據(jù)只要不被替換就會一直存在,客戶端拉取注冊信息時就是從這個緩存中拉取

二級緩存 readWriteCacheMap

二級緩存中的數(shù)據(jù)會隨著客戶端的 register、renew 和 cancel 請求而更新,因?yàn)楫?dāng)客戶端發(fā)起這些請求,數(shù)據(jù)存儲層的數(shù)據(jù)會被更新,為了保證緩存層和存儲層數(shù)據(jù)的一致性,二級緩存會從存儲層從新加載數(shù)據(jù)。

新數(shù)據(jù)的加載不會立即引發(fā)一級緩存的更新或清空,一級緩存會定期從二級緩存中同步數(shù)據(jù)。

Eureka 的自我保護(hù)機(jī)制

現(xiàn)象

在上面啟動 provider 和 consumer 項(xiàng)目的時候,我們都能在 server 的界面上看到一句紅色的警告

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

這是因?yàn)镋ureka開啟了自我保護(hù)機(jī)制,翻譯過來就是:

緊急情況!當(dāng)微服務(wù)主機(jī)聯(lián)系不上時,Eureka 不能夠正確判斷它們是否處于 up 狀態(tài)。當(dāng)更新(指收到的微服務(wù)主機(jī)的心跳)小于閾值時,為了安全,微服務(wù)主機(jī)將不再失效。

原因

默認(rèn)情況下,Eureka Server 在 90 秒內(nèi)(微服務(wù)默認(rèn)30秒發(fā)一次心跳)沒有收到某微服務(wù)的心跳,則判斷改為服務(wù)的主機(jī)宕機(jī),將該微服務(wù)從服務(wù)注冊信息表中刪除。

但很多時候,因?yàn)?strong>網(wǎng)絡(luò)抖動等原因,導(dǎo)致微服務(wù)主機(jī)發(fā)送的心跳沒有被 Eureka Server 收到,從而被 Eureka Server 刪除。

若短時間內(nèi)網(wǎng)絡(luò)恢復(fù)正常,但由于服務(wù)列表中刪除了該微服務(wù),所以該微服務(wù)不能再提供服務(wù)。

為了防止上述情況發(fā)生,Eureka 便有了自我保護(hù)機(jī)制。

即在短時間內(nèi),如果 Eureka Server 丟失了較多的服務(wù),即收到的心跳數(shù)量小于閾值,為了保證系統(tǒng)的可用性,Eureka會進(jìn)入自我保護(hù)模式,此時服務(wù)列表只可以讀取、注冊,不可以刪除。這樣便給了那些因?yàn)榫W(wǎng)絡(luò)抖動而被Eureka Server 誤認(rèn)為宕機(jī)的微服務(wù)主機(jī)重新復(fù)活的機(jī)會。當(dāng)網(wǎng)絡(luò)恢復(fù)正常,微服務(wù)主機(jī)得以繼續(xù)發(fā)送心跳,當(dāng)心跳數(shù)達(dá)到閾值以上,則退出自我保護(hù)模式。

關(guān)于閾值:自我保護(hù)機(jī)制的默認(rèn)閾值是85%。當(dāng)一定時間內(nèi)收到的心跳數(shù)小于總微服務(wù)數(shù)量的85%時,開啟自我保護(hù)模式。

從頁面上的兩個參數(shù),我們可以判斷出來什么時候會開啟自我保護(hù)

自我保護(hù)說明.png

Renews threshold 是 15分鐘內(nèi)每分鐘應(yīng)該收到的數(shù)量。

Renews (last min) 是 最后一分鐘實(shí)際收到的數(shù)量。

注意,Eureka默認(rèn)你的是微服務(wù)應(yīng)用是100個,所以(100*85%)/15 取整后為 5,即每分鐘應(yīng)該收到5個以上的心跳。

所以,很容易判斷,當(dāng)Renews (last min) < Renews threshold時,自我保護(hù)就會開啟。

但由上我們又知道,如果注冊到 Eureka 的 微服務(wù)不達(dá)到一定的數(shù)量,這個自我保護(hù)機(jī)制并不能由明顯效果。

下面給出自定義自我保護(hù)閾值和關(guān)閉自我保護(hù)的參數(shù):

eureka:
  server:
    renewal-percent-threshold: 0.75 #默認(rèn)0.85
    enable-self-preservation: true # 關(guān)閉自我保護(hù)機(jī)制
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 為什么需要服務(wù)發(fā)現(xiàn) 簡單來說,服務(wù)化的核心就是將傳統(tǒng)的一站式應(yīng)用根據(jù)業(yè)務(wù)拆分成一個一個的服務(wù),而微服務(wù)在這個基...
    謙小易閱讀 25,327評論 4 93
  • 當(dāng)我們使用一項(xiàng)新的技術(shù)時, 我們通常應(yīng)該先思考一個問題:為什么要使用這項(xiàng)技術(shù), 或者說這項(xiàng)技術(shù)能解決什么問題, 這...
    0d1b415a365b閱讀 720評論 0 2
  • Demo 源碼下載 本案例為源碼分支的 eureka 分支 服務(wù)發(fā)現(xiàn)概述 服務(wù)發(fā)現(xiàn)機(jī)制是為了解決硬網(wǎng)絡(luò)編碼問題,服...
    聰明的奇瑞閱讀 5,247評論 0 13
  • 一、Eureka的基礎(chǔ)架構(gòu) Spring Cloud 封裝了 Netflix 公司開發(fā)的 Eureka 模塊來實(shí)現(xiàn)...
    努力努力再努力_y閱讀 974評論 0 0
  • 3月7號上線的app,先擼為敬 1.掃二維碼或者通過鏈接地址進(jìn)入 注冊地址:https://www.flowdmc...
    ea1723d66189閱讀 399評論 0 1

友情鏈接更多精彩內(nèi)容