1. 程式人生 > >Spring Cloud Eureka-服務註冊與發現

Spring Cloud Eureka-服務註冊與發現

效應 code ack size init -- 編輯 rep pid

Spring Cloud Eureka

Spring Cloud是目前用於開發微服務的主流框架之一,我們都知道在微服務架構中最為基礎、核心的模塊,就是服務註冊與發現。

在Spring Cloud裏我們可以使用它的Eureka模塊來實現服務註冊與發現,Spring Cloud Eureka是基於Netflix Eureka做了二次封裝,它主要負責完成各個微服務實例的自動化註冊和發現功能。

Eureka由兩個組件組成:

  • Eureka Server(註冊中心)
  • Eureka Client (服務註冊)

分布式系統中為什麽需要服務發現:

在實際的分布式環境下,架構規模往往不再是幾臺服務器,而是每個獨立服務都跑在多臺機器上。例如A服務部署在10臺機器上,B服務也部署在10臺機器上,C服務部署在5臺機器上。

現在A服務的一些功能需要調用B服務來實現,那麽問題來了,A服務要如何才能調用B服務呢?通常情況下,我們可以想到將B服務所在的所有機器地址,通過配置文件來配置到A服務中,使其能夠通過配置好的地址去發現並調用B服務。

這也的確是一個可行的方法,但是這些機器的地址都是有可能發生變化的,而且在生產環境中也會出現部分服務宕機的情況,這樣就有可能導致一些連鎖效應。隨著業務的擴展,機器也會越來越多,也沒辦法再手動通過配置文件這種方式來配置機器地址了。

鑒於人類的懶惰天性。。。呸,鑒於人類對高效工作、美好生活的追求。所以專門用於服務註冊與發現的工具被一一開發出來。有了服務治理框架後,服務發現就可以交由它來自動完成。這時候A服務只需要到註冊中心進行服務註冊,同樣的B服務也到註冊中心進行服務註冊。註冊之後,註冊中心會通過類似心跳機制來確認服務的存活。如果確認某個服務宕機後,註冊中心會把宕機的服務剔除掉。當A服務要調用B服務的時候,則到註冊中心去獲取B服務的調用地址即可,B服務調用A服務也是同理。註冊中心就相當於一個服務與服務之間的橋梁或者說中間人,可以說幫我們管理了服務之間瑣事。

Eureka服務治理體系如下:
技術分享圖片

Spring Cloud官網地址如下:

https://projects.spring.io/spring-cloud/


Eureka Server

廢話不多說,本小節我們來搭建一個Eureka Server,即服務註冊中心。打開IDEA,新建一個Spring Initializr項目:
技術分享圖片
技術分享圖片

勾選Eureka Server模塊:
技術分享圖片

完成項目的創建:
技術分享圖片

項目生成的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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.zero</groupId>
    <artifactId>eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <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>
    </dependencies>

    <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>

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

註:SpringBoot與SpringCloud組件的版本是有一個對應關系的,這個在官網上有詳細的對照圖。值得註意的是,SpringCloud不是以2.0.1這種數字的方式來標識版本號,而是以倫敦地鐵站的名稱來標識版本號,並且這些名稱是符合字母順序的。

項目創建好後,我們可以試著啟動看看,但是在啟動之前需要在啟動類中加上@EnableEurekaServer註解,表示啟用Eureka Server,否則訪問就會報404。代碼如下:

package org.zero.eureka;

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

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

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

啟動項目後,能夠訪問到如下Eureka註冊中心的頁面代表成功:
技術分享圖片

此時雖然能夠正常訪問到註冊中心的頁面,但是會發現控制臺一直在報錯,提示Cannot execute request on any known server。這是因為這個Eureka Server既是server的同時,也是一個client,它也是需要把自己註冊到一個註冊中心去的。因為我們並沒有配置註冊中心的地址,所以它沒辦法註冊自己就會報這個錯誤。

既然如此,我們只需配置一下註冊中心的地址即可,編輯application.yml配置文件內容如下:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  # 指定註冊中心的url
    register-with-eureka: false  # 指定不進行註冊操作,默認為true,若進行註冊的話,會顯示在Eureka信息面板上
  server:
    enable-self-preservation: false  # 禁用eureka server的自我保護機制,建議在生產環境下打開此配置
spring:
  application:
    name: eureka  # 指定應用的名稱
server:
  port: 8761  # 指定項目的端口號

註:由於server和client是采用心跳機制來確認存活的,所以在啟動項目的過程可能依舊會報錯。但是只要啟動後不是一直報錯,並且能正常訪問Eureka信息面板頁面的話,則代表項目是在正常運行的


Eureka Client的使用

在上一小節中,我們簡單介紹了如何創建、配置Eureka Server項目。既然我們已經知道了如何搭建Eureka Server,那麽本小節我們將介紹Eureka Client的使用,會簡單演示一下如何通過Eureka Client進行服務註冊。

同樣的,使用IDEA創建一個Spring Initializr項目,只不過在勾選模塊的時候需要選擇Eureka Discovery,如下:
技術分享圖片

項目生成的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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.zero.eureka</groupId>
    <artifactId>client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>client</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <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>
    </dependencies>

    <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>

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

項目的依賴都加載完成後,在啟動類中加上@EnableDiscoveryClient,聲明這是一個eureka client,否則不會進行服務註冊:

package org.zero.eureka.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ClientApplication {

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

接著就是在application.yml配置文件中,配置註冊中心即eureka server的地址,以及項目的名稱和啟動端口號。如下:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: eureka-client
server:
  port: 9088

完成以上配置後,即可啟動項目。但是我這裏啟動項目的時候失敗了,控制臺輸出如下警告信息:

Invocation of destroy method failed on bean with name ‘scopedTarget.eurekaClient‘: org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name ‘eurekaInstanceConfigBean‘: Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)

這是因為client裏不包含Tomcat的依賴,所以Spring容器無法創建一些實例,從而導致項目無法啟動,只需在pom.xml文件中,加上web依賴即可:

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

項目啟動成功後,可以在eureka server的信息面板中查看到已註冊的實例信息,如下:
技術分享圖片


Eureka的高可用

高可用是在服務架構設計中,頻繁出現的詞匯。微服務架構裏自然也一樣需要保證服務的高可用性,所以本小節將簡單說明一下Eureka是如何實現高可用的。

在實際生產環境中服務器是很脆弱的,單臺服務器肯定是無法滿足高可用的需求,為了保證高可用性我們通常會準備多臺服務器。但可以發現上文中所搭建的eureka server是單機的,若這個eureka server宕機,則會導致與之關聯的全部微服務發生故障。

既然單機無法保證高可用,那麽我們就加多一臺機器好了,然後讓這兩個eureka server互相進行關聯。例如我現在有兩臺eureka server。一臺名叫eureka-server01跑在8761端口上,另一臺名叫eureka-server02跑在8762端口上。然後只需要兩個步驟即可實現高可用:

  • 1.編輯這兩臺eureka server的配置文件,讓它們的註冊地址互相指向,即可關聯在一起
  • 2.在eureka client的配置文件中,配置上這兩臺eureka server的地址,讓client能夠同時註冊到這兩臺eureka server上。這樣即便其中一臺eureka server掛掉,另一臺依舊可以繼續工作

1.編輯兩臺eureka server的配置文件,eureka-server01:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8762/eureka/  # 指向eureka-server02的url
    register-with-eureka: false
  server:
    enable-self-preservation: false 
spring:
  application:
    name: eureka-server01 
server:
  port: 8761 

eureka-server02:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  # 指向eureka-server01的url
    register-with-eureka: false
  server:
    enable-self-preservation: false
spring:
  application:
    name: eureka-server02 
server:
  port: 8762 

2.編輯eureka client的配置文件,多個url使用英文逗號分隔:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
spring:
  application:
    name: eureka-client
server:
  port: 9088

如果項目規模比較大,有兩個以上的eureka server,那該如何在配置文件中配置呢?其實只需要每臺eureka server分別配置除自己之外的eureka server機器,然後eureka client則配置所有的eureka server地址即可。如下圖:
技術分享圖片

配置文件示例,eureka-server01:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8762/eureka/,http://localhost:8763/eureka/
    register-with-eureka: false
spring:
  application:
    name: eureka-server01 
server:
  port: 8761 

配置文件示例,eureka-server02:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8763/eureka/
    register-with-eureka: false
spring:
  application:
    name: eureka-server02 
server:
  port: 8762 

配置文件示例,eureka-server03:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
    register-with-eureka: false
spring:
  application:
    name: eureka-server03 
server:
  port: 8763 

eureka client的配置文件示例:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/,http://localhost:8763/eureka/
spring:
  application:
    name: eureka-client
server:
  port: 9088

Spring Cloud Eureka-服務註冊與發現