Spring Cloud 地址硬編碼問題解決(第三天)

一、服務發現原理深入

服務發現組件後的架構圖,如圖所示。

圖-服務發現-02

1.1 服務提供者、服務消費者、服務發現組件這三者之間的關係大致如下:

  • 各個微服務在啓動時,將自己的網絡地址等信息註冊到服務發現組件中,服務發現組件會存儲這些信息;

  • 服務消費者可從服務發現組件查詢服務提供者的網絡地址,並使用該地址調用服務提供者的接口;

  • 各個微服務與服務發現組件使用一定機制(例如心跳)通信。服務發現組件如長時間無法與某微服務實例通信,就會自動註銷(即:刪除)該實例;

  • 當微服務網絡地址發生變更(例如實例增減或者IP端口發生變化等)時,會重新註冊到服務發現組件;

  • 客戶端緩存:各個微服務將需要調用服務的地址緩存在本地,並使用一定機制更新(例如定時任務更新、事件推送更新等)。這樣既能降低服務發現組件的壓力,同時,即使服務發現組件出問題,也不會影響到服務之間的調用。

1.2 服務發現組件應具備以下功能:

  • 服務註冊表:服務註冊表是服務發現組件的核心(其實就是類似於上面的registry表),它用來記錄各個微服務的信息,例如微服務的名稱、IP、端口等。服務註冊表提供查詢API和管理API,查詢API用於查詢可用的微服務實例,管理API用於服務的註冊和註銷;

  • 服務註冊與服務發現:服務註冊是指微服務在啓動時,將自己的信息註冊到服務發現組件上的過程。服務發現是指查詢可用微服務列表及其網絡地址的機制;

  • 服務檢查:服務發現組件使用一定機制定時檢測已註冊的服務,如發現某實例長時間無法訪問,就會從服務註冊表中移除該實例。

參考文章:http://www.itmuch.com/spring-cloud/finchley-4/

二、Eureka入門

2.1 Eureka簡介

        Eureka是Netflix開源的服務發現組件,本身是一個基於REST的服務,包含Server和Client兩部分,Spring Cloud將它集成在子項目Spring Cloud Netflix中。

2.2 編寫Eureka Server

2.2.1 創建microservice-discovery-eureka模塊

2.2.2 配置pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!--<parent>
        <artifactId>cloud-study</artifactId>
        <groupId>com.qhr.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>-->
    <groupId>com.qhr.cloud</groupId>
    <modelVersion>4.0.0</modelVersion>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <artifactId>microservice-discovery-eureka</artifactId>

    <!-- 引入spring boot的依賴 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

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

    <!-- 引入spring cloud的依賴 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 添加spring-boot的maven插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.2.3 配置application.yml

server:
  port: 8761
eureka:
  client:
    # 是否要註冊到其他Eureka Server實例
    register-with-eureka: false
    # 是否要從其他Eureka Server實例獲取數據
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

2.2.4 配置啓動類EurekaApplication

package com.qhr.cloud.study;

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

/**
 * @Author : qhr
 * @Description :
 * @Date : Created in 15:32 2020/7/1
 * @Modified By :
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

2.2.5 複製microservice-simple-provider-user和microservice-simple-consumer-movie子模塊,並修改模塊名稱爲microservice-provider-user和microservice-consumer-movie

2.2.6 分別在兩個微服務,添加依賴

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

2.2.7 修改啓動類

package com.qhr.cloud.study;

import com.qhr.cloud.study.entity.User;
import com.qhr.cloud.study.repository.UserRepository;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.math.BigDecimal;
import java.util.stream.Stream;

/**
 * @Author : qhr
 * @Description :
 * @Date : Created in 15:49 2020/7/1
 * @Modified By :
 */
@SpringBootApplication
public class ProviderUserApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderUserApplication.class, args);
    }

    /**
     * 初始化用戶信息
     * 注:Spring Boot2不能像1.x一樣,用spring.datasource.schema/data指定初始化SQL腳本,否則與actuator不能共存
     * 原因詳見:
     * https://github.com/spring-projects/spring-boot/issues/13042
     * https://github.com/spring-projects/spring-boot/issues/13539
     *
     * @param repository repo
     * @return runner
     */
    @Bean
    ApplicationRunner init(UserRepository repository) {
        return args -> {
            User user1 = new User(1L, "account1", "張三", 20, new BigDecimal(100.00));
            User user2 = new User(2L, "account2", "李四", 28, new BigDecimal(180.00));
            User user3 = new User(3L, "account3", "王五", 32, new BigDecimal(280.00));
            Stream.of(user1, user2, user3)
                    .forEach(repository::save);
        };
    }
}
package com.qhr.cloud.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * @Author : qhr
 * @Description :
 * @Date : Created in 16:01 2020/7/1
 * @Modified By :
 */
@SpringBootApplication
public class ConsumerMovieApplication {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

注:早期的版本(Dalston及更早版本)還需在啓動類上添加註解@EnableDiscoveryClient 或@EnableEurekaClient ,從Edgware開始,該註解可省略。

2.2.8 修改microservice-provider-user的application.yml配置文件

server:
  port: 8000
spring:
  application:
    # 指定註冊到eureka server上的服務名稱
    name: microservice-provider-user
  jpa:
    # 讓hibernate打印執行的SQL
    show-sql: true
logging:
  level:
    root: INFO
    # 配置日誌級別,讓hibernate打印出執行的SQL參數
    org.hibernate: INFO
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE
    org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
management:
  endpoints:
    web:
      exposure:
        # 開放所有監控端點
        include: '*'
  endpoint:
    health:
      # 是否展示健康檢查詳情
      show-details: always

eureka:
  client:
    service-url:
      # 指定eureka server通信地址,注意/eureka/小尾巴不能少
      defaultZone: http://localhost:8761/eureka/
  instance:
    # 是否註冊IP到eureka server,如不指定或設爲false,那就會註冊主機名到eureka server
    prefer-ip-address: true


2.2.9 修改microservice-consumer-movie的application.yml配置文件

server:
  port: 8010
spring:
  application:
    # 指定註冊到eureka server上的服務名稱
    name: microservice-consumer-movie

eureka:
  client:
    service-url:
      # 指定eureka server通信地址,注意/eureka/小尾巴不能少
      defaultZone: http://localhost:8761/eureka/
  instance:
    # 是否註冊IP到eureka server,如不指定或設爲false,那就會註冊主機名到eureka server
    prefer-ip-address: true

2.2.10 測試

      按照microservice-discovery-eureka、microservice-provider-user和microservice-consumer-movie的啓動順序,先後啓動微服務。訪問:http://localhost:8761/

如上:現在服務就已經註冊成功。

參考文章:http://www.itmuch.com/spring-cloud/finchley-5/

三、Eureka深入

3.1 Eureka原理

圖-Region And Availibility Zone

Netflix公司將他們的應用都部署在了AWS上,所以Eureka的架構使用到了AWS中的一些概念:

Region和Availability Zone均是AWS的概念。

  • Region表示AWS中的地理位置,例如us-east-1、us-east-2、eu-west-1等;
  • 每個Region都有多個Availability Zone,彼此內網打通
  • 各個Region之間完全隔離,彼此內網不打通
  • AWS通過這種方式實現了最大的容錯和穩定性。

        Spring Cloud中,默認使用的Region是us-east-1 。非AWS環境下,可將將Region理解爲內網沒有打通的機房,將Availability Zone理解成相同機房的不同機架(內網打通)。

3.2 Eureka架構圖

Eureka架構

 

3.2.1 節點信息

  • Application Service:服務提供者;

  • Application Client:服務消費者;

  • Make Remote Call調用RESTful API;

  • us-east-1c、us-east-1d等都是Availability Zone,它們都屬於us-east-1這個region。

3.2.2 工作原理

  • Eureka Server提供服務發現的能力,各個微服務啓動時,會向Eureka Server註冊自己的信息(例如IP、端口、微服務名稱等),Eureka Server會存儲這些信息;

  • Eureka Client是一個Java客戶端,用於簡化與Eureka Server的交互;

  • 微服務啓動後,會週期性(默認30秒)地向Eureka Server發送心跳以續約自己的“租期”;

  • 如果Eureka Server在一定時間內沒有接收到某個微服務實例的心跳,Eureka Server將會註銷該實例(默認90秒);

  • 默認情況下,Eureka Server同時也是Eureka Client。多個Eureka Server實例,互相之間通過增量複製的方式,來實現服務註冊表中數據的同步。Eureka Server默認保證在90秒內,Eureka Server集羣內的所有實例中的數據達到一致(從這個架構來看,Eureka Server所有實例所處的角色都是對等的,沒有類似Zookeeper、Consul、Etcd等軟件的選舉過程,也不存在主從,所有的節點都是主節點。Eureka官方將Eureka Server集羣中的所有實例稱爲“對等體(peer)”)

  • Eureka Client會緩存服務註冊表中的信息。這種方式有一定的優勢——首先,微服務無需每次請求都查詢Eureka Server,從而降低了Eureka Server的壓力;其次,即使Eureka Server所有節點都宕掉,服務消費者依然可以使用緩存中的信息找到服務提供者並完成調用。

3.3 案例代碼

3.3.1 配置pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!--<parent>
        <artifactId>cloud-study</artifactId>
        <groupId>com.qhr.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>-->
    <groupId>com.qhr.cloud</groupId>
    <version>1.0-SNAPSHOT</version>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>

    <artifactId>microservice-provider-user-ha</artifactId>

    <!-- 引入spring boot的依賴 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

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

    <!-- 引入spring cloud的依賴 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 添加spring-boot的maven插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3.3.2 配置application.yml文件

spring:
  application:
    name: microservice-discovery-eureka-ha
---
spring:
  profiles: peer1                                 # 指定profile=peer1
server:
  port: 8761
eureka:
  instance:
    hostname: peer1                               # 指定當profile=peer1時,主機名是peer1
  client:
    serviceUrl:
      defaultZone: http://peer2:8762/eureka/      # 將自己註冊到peer2這個Eureka上面去

---
spring:
  profiles: peer2
server:
  port: 8762
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/

注:由於我們是通過profiles方式,在同一臺電腦上配Eureka的高可用性,所以我們必須在本地主機名,配置方式如下:

vim /etc/hosts
# 添加如下內容
127.0.0.1 peer1 peer2

對於Windows系統,請修改C:\windows\system32\drivers\etc\hosts文件

3.3.3 配置啓動文件EurekaApplication

package com.qhr.cloud.study;

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

/**
 * @Author : qhr
 * @Description :
 * @Date : Created in 10:21 2020/7/4
 * @Modified By :
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

3.3.4 啓動

先將項目打成jar包,然後打開兩個cmd在jar包目錄下,先後運行一下兩個命令:

java -jar microservice-discovery-eureka-ha-1.0-SNAPSHOT.jar --spring.profiles.active=peer1
java -jar microservice-discovery-eureka-ha-1.0-SNAPSHOT.jar --spring.profiles.active=peer2

注:第一個cmd一定會報錯:com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect,但是不要緊,這是由於實例peer2還沒運行所報的錯,當peer2運行了就不會報錯了。

訪問:http://peer1:8761/

訪問:http://peer2:8762/

3.3.5 將服務註冊到Eureka集羣

修改microservice-provider-user的application.yml配置文件(連接多節點配置):

eureka:
  client:
    service-url:
      # 指定eureka server通信地址,注意/eureka/小尾巴不能少
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/

或者是(連接單節點配置):

eureka:
  client:
    service-url:
      # 指定eureka server通信地址,注意/eureka/小尾巴不能少
      defaultZone: http://peer1:8761/eureka/

兩種配置均可,因爲eureka集羣節點數據是共享的,但是爲了系統的穩定性,一般採用多節點配置,這樣可以避免一些極端的問題。

訪問:http://peer1:8761/

可以發現microservice-provider-user微服務已經註冊成功了。

參考文章:http://www.itmuch.com/spring-cloud/finchley-6/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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