1. 程式人生 > 資料庫 >修改mysql root密碼

修改mysql root密碼

Eureka服務註冊與發現

1. Eureka基礎知識

1. 什麼是服務治理

SpringCloud封裝了Netflix公司開發的Eureka模組來實現服務治理

在傳統的RPC遠端呼叫框架中,管理每個服務與服務之間依賴關係比較複雜,管理比較複雜,所以需要使用服務治理,管理服務與服務之間依賴關係,可以實現服務呼叫、負載均衡、容錯等,實現服務發現與註冊

2. 什麼是服務註冊與發現

Eureka採用了CS的設計架構,Eureka Server作為服務註冊功能的伺服器,它是服務註冊中心,而系統中的其他微服務,使用Eureka的客戶端連線到Eureka Server並維持 心跳連結 。這樣系統的維護人員就可以通過Eureka Server來監控系統中各個微服務是否正常執行。

在服務註冊與發現中,有一個註冊中心。當伺服器啟動的時候,會把當前自己伺服器的資訊(比如:服務地址、通訊地址等)以別名方式註冊到註冊中心中。另一方(消費者/服務提供者),以該別名的方式去註冊中心上獲取到實際的服務通訊地址,然後再實現本地RPC呼叫。RPC遠端呼叫框架核心設計思想:在於註冊中心,因為使用註冊中心管理每個服務與服務之間的依賴關係(服務治理概念)。在任何RPC遠端框架中,都會有一個註冊中心(存放服務地址相關資訊(介面地址))

下左圖是Eureka系統架構,右圖是Dubbo系統架構

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

  • Eureka Server

    提供服務註冊中心

    各個微服務節點通過配置啟動後,會在EurekaServer中進行註冊,這樣EurekaServer中的服務登錄檔中將儲存所有可用服務節點的資訊,服務節點的資訊可以在介面中直觀看到。

  • Eureka Client通過註冊中心進行訪問

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

2. 單機Eureka構建步驟

1. IDEA生成Eureka Server端服務註冊中心

  • 1 建Module

  • 2 改POM

    1.X和2.X的對比說明:

    SpringBoot1.X對應的SpringCloud中,不要再用了!!!

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

    SpringBoot2.X對應的SpringCloud中

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    
  • 3 寫配置檔案YML

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: localhost #eureka服務端的例項名稱
      client:
        #false表示不向註冊中心註冊自己
        register-with-eureka: false
        #false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要去檢索服務
        fetch-registry: false     
        service-url:
          # 設定與Eureka Server互動的地址查詢服務和註冊服務都需要依賴這個地址
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
  • 4 SpringBoot應用主啟動類

    package cn.sher6j.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * @author sher6j
     */
    @SpringBootApplication
    @EnableEurekaServer//宣告我是服務註冊中心
    public class EurekaMain7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain7001.class);
        }
    }
    
  • 5 測試

    完成以上步驟後,執行該Eureka Server主啟動類,訪問 localhost:7001,就會看到下面的服務註冊中心:

    可以發現,目前還沒有任何服務入駐進服務註冊中心中,在應用中顯示:No instances available

2. 將Eureka Client端中的服務提供端註冊進Eureka Server作為Service Provider

  • 1 建module

  • 2 改POM

    1.X和2.X的對比說明:

    SpringBoot1.X對應的SpringCloud中,不要再用了!!!

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

    SpringBoot2.X對應的SpringCloud中

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  • 3 寫配置檔案YML

    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service  # 入駐Eureka服務註冊中心的服務名稱
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource  # 當前資料來源操作型別
        driver-class-name: org.gjt.mm.mysql.Driver    # mysql驅動包
        url: jdbc:mysql://localhost:3306/cloud20?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    eureka:
      client:
        #表示是否將自己註冊進EurekaServer預設為true。
        register-with-eureka: true
        #是否從EurekaServer抓取已有的註冊資訊,預設為true。單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
        fetchRegistry: true
        service-url:
          #單機版
          defaultZone: http://localhost:7001/eureka # 入駐的服務註冊中心地址
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
      type-aliases-package: cn.sher6j.springcloud.entities  # 所有Entity別名類所在包
    
  • 4 SpringBoot應用主啟動類

    package cn.sher6j.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    /**
     * 主啟動類
     * @author sher6j
     */
    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class);
        }
    }
    
  • 5 測試

    先要啟動EurekaServer,因為有了服務註冊中心,具體的服務提供者才能後向其中註冊自己的服務,如下圖:

    可以發現,註冊到服務註冊中心的服務名(圖中藍框)即為我們在yml配置檔案中設定的服務名,上面頁面中出現的 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. 是Eureka的自我保護機制

3. 將Eureka Client端中的服務消費端註冊進Eureka Server稱為Service Consumer

  • 1 建module

  • 2 改POM

  • 3 寫配置檔案

    server:
      port: 80
    
    spring:
      application:
        name: cloud-order-service
    
    eureka:
      client:
        #表示是否將自己註冊進EurekaServer預設為true。
        register-with-eureka: false
        #是否從EurekaServer抓取已有的註冊資訊,預設為true。單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
        fetchRegistry: true
        service-url:
          #單機
          defaultZone: http://localhost:7001/eureka
    
  • 4 主啟動類

    package cn.sher6j.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    /**
     * @author sher6j
     */
    @SpringBootApplication
    @EnableEurekaClient
    public class OrderMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain80.class);
        }
    }
    
    
  • 5 測試

    如圖此時80,8001兩個微服務都已經註冊到Eureka服務註冊中心

    此時,再回看最開始的Eureka系統架構,在服務註冊中心和服務提供者沒有叢集的情況下,7001埠的微服務就對應了服務註冊中心,而該服務不需要向服務註冊中心註冊自己,8001埠的微服務作為服務提供方入住到服務註冊中心,8002埠的微服務作為服務消費方也同樣註冊到服務註冊中心

3. 叢集Eureka構建步驟

1. Eureka叢集原理說明

服務註冊中心Eureka Server中分為 服務註冊服務發現,服務註冊過程將服務資訊註冊進服務註冊中心,服務發現過程從服務註冊中心上獲取服務資訊,而這個過程的實質就是:將服務名作為key儲存,然後根據value取得服務的呼叫地址

整個Eureka的過程如果:

  1. 先啟動Eureka註冊中心
  2. 啟動服務提供者服務
  3. 服務提供者服務將自身資訊(比如服務地址)以別名方式註冊到Eureka註冊中心
  4. 消費者服務在需要呼叫介面時,使用服務別名到註冊中心獲取實際的RPC遠端呼叫地址
  5. 消費者獲得呼叫地址後,底層實際是利用 HttpClient 技術實現遠端呼叫
  6. 消費者獲得服務地址後會快取字本地JVM記憶體中,預設每間隔30秒更新一次服務呼叫地址

那麼微服務RPC遠端服務呼叫最核心的是什麼呢???

高可用!!!,如果註冊中心只有一個,而這個註冊中心出現了故障,那麼整個微服務就直接GG了,整個微服務環境就不可用了,所以應該搭建Eureka註冊中心叢集, 實現 負載均衡 + 故障容錯

那怎麼實現Eureka註冊中心的叢集呢?用一句話總結就是——互相註冊,相互守望,如下圖所示:

服務註冊中心實現相互註冊,讓彼此都知道對方的存在,也就是註冊中心叢集中的每一個註冊中心都知道整個叢集中的其他註冊中心,比如如果有三個註冊服務中心7001,7002,7003,那麼就將7002和7003註冊給7001, 將7002和7001註冊給7003, 將7003和7001註冊給7002, 以此類推,而這些個註冊服務中心作為一個整體對外看做一個註冊服務中心。

2. EurekaServer叢集環境構建步驟

  • 參考cloud-eureka-server7001新建一個服務註冊中心cloud-eureka-server7001。

  • 2 改POM,copy複製cloud-eureka-server7001的POM檔案即可。

  • 3 修改對映配置

    找到C:\Windows\System32\drivers\etc路徑下的hosts檔案,將其內容修改成如下內容:

    # learn-spring-cloud
    127.0.0.1 eureka7001.com
    127.0.0.1 eureka7002.com
    

    當然我是用的SwitchHosts對該檔案進行的修改。這樣的話就可以通過一臺主機(127.0.0.1即localhost)的不同埠模擬實現不同的主機(127.0.0.1:7001和127.0.0.1:7002)。

  • 4 寫配置檔案YML(區別於單機)

    以前單機的時候,註冊中心的配置檔案是這樣的:

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: localhost #eureka服務端的例項名稱
      client:
        #false表示不向註冊中心註冊自己
        register-with-eureka: false
        #false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要去檢索服務
        fetch-registry: false
        service-url:
          # 設定與Eureka Server互動的地址查詢服務和註冊服務都需要依賴這個地址
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    

    而現在已經有兩個註冊中心,可以看做兩臺機器,顯然 hostname 不能再叫localhost,而叢集不能再這樣,對於7001埠的註冊中心,修改其配置檔案:

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: eureka7001.com #eureka服務端的例項名稱
      client:
        #false表示不向註冊中心註冊自己
        register-with-eureka: false
        #false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要去檢索服務
        fetch-registry: false
        service-url:
          # 互相註冊,相互守望
          defaultZone: http://eureka7002.com:7002/eureka/
    

    首先更改了其服務端的例項名稱,最重要的是在defaultZone中將自己註冊給7002,舉一反三,7002的配置檔案顯然如下:

    server:
      port: 7002
    
    eureka:
      instance:
        hostname: eureka7002.com #eureka服務端的例項名稱
      client:
        #false表示不向註冊中心註冊自己
        register-with-eureka: false
        #false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要去檢索服務
        fetch-registry: false
        service-url:
          # 互相註冊,相互守望
          defaultZone: http://eureka7001.com:7001/eureka/
    

    這樣就實現了兩個服務註冊中心的相互註冊。

  • 主啟動類

    7002的主啟動類和7001一樣

    package cn.sher6j.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    /**
     * @author sher6j
     */
    @SpringBootApplication
    @EnableEurekaServer//宣告我是服務註冊中心
    public class EurekaMain7002 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain7002.class);
        }
    }
    
  • 測試

    如圖:兩個服務中心已經完成了互相註冊。DS Replicas這個下面的資訊就表示是這個Eureka Server相鄰節點,且這些節點加上自己互為一個叢集。

3. 將服務提供方服務8001釋出到上面2臺Eureka叢集配置中

修改其配置檔案即可

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service  # 入駐Eureka服務註冊中心的服務名稱
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource  # 當前資料來源操作型別
    driver-class-name: org.gjt.mm.mysql.Driver    # mysql驅動包
    url: jdbc:mysql://localhost:3306/cloud20?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

eureka:
  client:
    #表示是否將自己註冊進EurekaServer預設為true。
    register-with-eureka: true
    #是否從EurekaServer抓取已有的註冊資訊,預設為true。單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 入駐的服務註冊中心地址

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: cn.sher6j.springcloud.entities  # 所有Entity別名類所在包

也就是將自己的微服務註冊到每一個服務註冊中心裡去,見配置檔案中的defaultZone

4. 將服務消費方服務80釋出到上面2臺Eureka叢集配置中

和上面的是一樣的,只需要修改其配置檔案,將自己註冊進兩個服務註冊中心中。

下面進行測試:首先 要啟動EurekaServer服務,即7001和7002服務,這樣就有了服務註冊中心,然後 再啟動服務提供方即8001, 最後 啟動服務消費方即80。如圖:7001和7002已經構成叢集,且都可以拉取到80和8001兩個服務:

5. 服務提供方8001服務的叢集環境構建

  • 參考8001服務新建8002服務

  • 改POM:和8001的POM檔案一樣

  • 寫配置檔案:將埠改為8002,其他和8001相同,兩個微服務 對外暴露的服務名相同 均為cloud-payment-service 從而構成叢集

    server:
      port: 8002
    
    spring:
      application:
        name: cloud-payment-service  # 入駐Eureka服務註冊中心的服務名稱
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource  # 當前資料來源操作型別
        driver-class-name: org.gjt.mm.mysql.Driver    # mysql驅動包
        url: jdbc:mysql://localhost:3306/cloud20?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    eureka:
      client:
        #表示是否將自己註冊進EurekaServer預設為true。
        register-with-eureka: true
        #是否從EurekaServer抓取已有的註冊資訊,預設為true。單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
        fetchRegistry: true
        service-url:
          # 單機版
          #      defaultZone: http://localhost:7001/eureka # 入駐的服務註冊中心地址
          # 叢集版
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 入駐的服務註冊中心地址
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
      type-aliases-package: cn.sher6j.springcloud.entities  # 所有Entity別名類所在包
    
  • 主啟動類、業務類:直接從8001裡copy即可

    package springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    /**
     * 主啟動類
     * @author sher6j
     */
    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentMain8002 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8002.class);
        }
    }
    
  • 修改controller新增埠號已區分這兩個具體的微服務:讀取配置檔案中設定的埠號。8002的修改同8001。

    package cn.sher6j.springcloud.controller;
    
    import cn.sher6j.springcloud.entities.CommonResult;
    import cn.sher6j.springcloud.entities.Payment;
    import cn.sher6j.springcloud.service.PaymentService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.*;
    
    /**
     * @author sher6j
     */
    @RestController
    @Slf4j
    public class PaymentController {
    
        @Autowired
        private PaymentService paymentService;
    
        @Value("${server.port}")
        private String serverPort;
    
        /**
         * 插入payment
         * @param payment
         * @return
         */
        @PostMapping("/payment/create")
        public CommonResult create(@RequestBody Payment payment) {
            int result = paymentService.create(payment);
            log.info("=======插入結果:" + result);
    
            if (result > 0) {
                return new CommonResult(200, "插入資料庫成功, 埠號:" + serverPort, result);
            } else {
                return new CommonResult(444, "插入資料庫失敗", null);
            }
        }
    
        /**
         * 根據id查詢訂單
         * @param id
         * @return
         */
        @GetMapping("/payment/get/{id}")
        public CommonResult getPaymentById(@PathVariable("id") Long id) {
            Payment payment = paymentService.getPaymentById(id);
            log.info("=======查詢結果:" + payment);
    
            if (payment != null) {
                return new CommonResult(200, "查詢資料庫成功, 埠號:" + serverPort, payment);
            } else {
                return new CommonResult(444, "沒有對應記錄,查詢ID:" + id, null);
            }
        }
    }
    
  • 測試

    如圖,可以看到此時服務註冊中心構成叢集,而相同名字的服務提供方的實際提供者已經出現了兩個,分別是8001和8002,,也就是說服務提供方微服務也實現了叢集。

    此時再回看最開始的Eureka微服務架構圖,其叢集架構圖對應本例項應為:

6. 負載均衡

此時,我們使用80埠的服務消費方來訪問 CLOUD-PAYMENT-SERVICE 服務,輸入網址http://localhost/consumer/payment/get/1,但是我們每次得到的資料都是:

{
	code: 200,
	message: "查詢資料庫成功, 埠號:8001",
	data: {
		id: 1,
		serial: "aaaa001"
	}
}

也就是說每次訪問的具體微服務都是8001埠的CLOUD-PAYMENT-SERVICE服務,這明顯是不符合業務邏輯的,原因就是在消費方程式碼中我們將服務訪問地址寫死了,沒有實現負載均衡,這顯然是不對的,所以我們應該讓80訪問服務名,而不是具體的服務,同時在配置檔案中通過 @LoadBalanced 註解賦予RestTemplate負載均衡能力,該負載均衡預設為輪詢方式,所以講80服務的配置檔案修改如下:

package cn.sher6j.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author sher6j
 */
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced//使用該註解賦予RestTemplate負載均衡的能力
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
//applicationContext.xml <bean id="" class="">

然後重啟80埠,發現每次訪問 CLOUD-PAYMENT-SERVICE 服務時,具體的微服務在8001和8002之間進行輪詢切換:

當然此時負載均衡我們還沒有用到Ribbon,再Ribbon和Eureka整個後消費者可以直接呼叫服務而不用再關心地址和埠號,且該服務還有負載功能。

4. actuator微服務資訊完善

1. 主機名稱:服務名稱修改

當前問題:在註冊中心顯示的微服務中,我們發現服務名含有主機名稱,這顯然不是我們希望看到的

怎麼能解決這個問題呢,只需要修改服務提供方(8001和8002)的配置檔案,向其中的eureka部分加入即可配置該服務顯示的服務名稱

instance:
  instance-id: payment8001

最終的整體配置檔案如下:

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service  # 入駐Eureka服務註冊中心的服務名稱
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource  # 當前資料來源操作型別
    driver-class-name: org.gjt.mm.mysql.Driver    # mysql驅動包
    url: jdbc:mysql://localhost:3306/cloud20?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

eureka:
  client:
    #表示是否將自己註冊進EurekaServer預設為true。
    register-with-eureka: true
    #是否從EurekaServer抓取已有的註冊資訊,預設為true。單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
    fetchRegistry: true
    service-url:
      # 單機版
#      defaultZone: http://localhost:7001/eureka # 入駐的服務註冊中心地址
      # 叢集版
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 入駐的服務註冊中心地址
  instance:
    instance-id: payment8001

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: cn.sher6j.springcloud.entities  # 所有Entity別名類所在包

8002服務的修改同上,此時再訪問註冊中心,看到的服務具體名稱中就沒有主機名了,而是我們配置好的服務名稱:

2. 訪問資訊有IP資訊提示

當前問題:我們在滑鼠移動到具體服務時,提示的地址資訊中並沒有服務所在具體主機的IP地址,這在開發中不方便定位具體微服務。

解決方式仍然是通過配置檔案,在配置檔案中向其中的eureka部分加入即可配置該服務訪問路徑可以顯示IP地址:

instance:
  prefer-ip-address: true  # 訪問路徑可以顯示IP地址

最終的配置檔案如下:

server:
  port: 8001
......
eureka:
  client:
    ......
  instance:
    instance-id: payment8001
    prefer-ip-address: true  # 訪問路徑可以顯示IP地址
......

滑鼠再次移動到該服務時,可以發現,已經提示了IP地址:

5. 服務發現Discovery

對於註冊進Eureka服務註冊中心的微服務,可以通過服務發現來獲取該服務的資訊。

1. 修該微服務的Controller,向其中注入DiscoveryClient,並編寫相應Controller方法

package cn.sher6j.springcloud.controller;

......
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
......
/**
 * @author sher6j
 */
@RestController
@Slf4j
public class PaymentController {

    .......

    @Autowired
    private DiscoveryClient discoveryClient;
	
    .......

    @GetMapping("/payment/discovery")
    public Object discovery() {
        List<String> services = discoveryClient.getServices(); //獲取服務列表的資訊
        for (String service : services) {
            log.info("=======service:" + service + "=======");
        }

        //根據微服務名稱獲取具體服務例項
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance : instances) {
            log.info("=======" + instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri() + "=======");
        }

        return this.discoveryClient;
    }
}

DiscoveryClient物件中的 getServices 方法用於獲取服務列表的資訊,也就是有哪些服務,如cloud-payment-service服務, getInstances 方法用於獲取服務列表對應的具體服務例項,如cloud-payment-service服務對應的8001和8002服務。

2. 修改主啟動類

只需要在主啟動類上添加註解@EnableDiscoveryClient,修改後的主啟動類:

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

3. 測試

訪問地址http://localhost:8001/payment/discovery,我們可以看到獲取的服務資訊,即完成了服務發現:

後臺也對服務列表進行了日誌列印:

6. Eureka自我保護(CAP裡面的AP分支)

1. 自我保護機制

保護模式主要用於一組客戶端和EurekaServer之間存在網路分割槽場景下的保護。一旦進入保護模式,Eureka Server將會嘗試保護其服務登錄檔中的資訊,不再刪除服務登錄檔中的資料,也就是不會登出任何微服務

如果在Eureka Server的首頁看到以下提示,說明Eureka進入了保護模式(上面2. 單機Eureka構建步驟中提到過):

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.

換句話說就是,某時刻某一個微服務不可用了,Eureka不會立刻清理,而是依舊會對該微服務的資訊進行儲存。

2. 產生原因

  • 為什麼會產生Eureka自我保護機制???

    為了防止 EurekaClient可以正常執行,但是與EurekaServer網路不通 情況下,EurekaServer不會立刻將EurekaClient服務剔除。

  • 什麼是自我保護模式?

    預設情況下,如果EurekaServer在一定時間內沒有接收到某個微服務例項的心跳,EurekaServer將會登出該例項(預設90秒)。但是當網路分割槽故障發生(延時、卡頓、擁擠)時,微服務與EurekaServer之前無法正常通訊,以上行為可能變得非常危險——因為微服務本身是健康的,只是由於網路問題連結不到EurekaServer,此時本不應該登出這個微服務。Eureka通過“自我保護模式”來解決這個問題——當EurekaServer節點在短時間內丟失過多客戶端時(可能發生了網路分割槽故障,網路延時),那麼這個節點就會進入自我保護模式。

    在自我保護模式中,EurekaServer會保護服務登錄檔中的資訊,不再登出任何服務例項,寧可保留錯誤的服務註冊資訊,也不盲目登出任何可能健康的服務例項。使用自我保護模式,可以讓Eureka叢集更加的健壯、穩定。

3. 怎麼禁止自我保護

  • 在EurekaServer端修改配置檔案即可設定關閉自我保護機制

    eureka:
      server:
      	# 關閉自我保護機制,保證不可用服務被及時剔除
        enable-self-preservation: false
        # 時間間隔
        eviction-interval-time-in-ms: 2000 
    
  • 在EurekaClient端修改配置檔案

    eureka:
      instance:
        instance-id: payment8001
        # Eureka客戶單向服務端傳送心跳的時間間隔,默然是30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服務端在收到最後一次心跳後等待時間上限,默然為90秒,超時將剔除服務
        lease-expiration-duration-in-seconds: 2 
    

    這樣就會使EurekaClient客戶端的微服務很快死亡。