1. 程式人生 > >搭建 Spring Cloud Eureka Server 高可用註冊中心叢集

搭建 Spring Cloud Eureka Server 高可用註冊中心叢集

什麼是註冊中心

Eureka Server 在微服務中承擔的角色是服務註冊中心,也是最最基礎的核心設施之一。從“Eureka”單詞的含義**“我找到了!我發現了!”可以看出,其實 Eureka 就是用來實現服務註冊、服務發現的工具**,和 dubbo 這類的分散式服務治理框架類似。各種獨立的微服務將自己註冊到 Eureka Server,Eureka Client 則提供了服務發現的能力。

本文目的

Eureka的特點在於可以相互註冊,形成高可用註冊中心叢集。這篇文章記錄一下本地搭建兩個 Eureka Server 註冊中心,讓他們互相註冊自己到對方的服務中心,最後建立一個名為 hello-service

的微服務,將它們註冊到註冊中心。

開發環境

  • IntelliJ IDEA 2018.1.6
  • Maven-3.5.3
  • JDK8
  • spring cloud版本:Finchley.RELEASE
  • spring-boot-starter版本:2.0.3.RELEASE

準備工作

由於是本地在同一臺機器上模擬搭建兩個註冊中心,需要修改 HOSTS 檔案,這裡以 Win10 系統為例,HOSTS 檔案的路徑在 C:\Windows\System32\drivers\etc

在末尾追加內容如下,表示訪問 eureka-server1 和 eureka-server2 時,等於訪問 127.0.0.1:

127.0.0.1 eureka-server1
127.0.0.1 eureka-server2

第1步:搭建註冊中心1

在IDEA建立工程,取名為 cat-spring-cloud-eureka-server-1,通過Spring初始化工具,新增 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>me.zebe</groupId> <artifactId>cat-spring-cloud-eureka-server-1</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>cat-spring-cloud-eureka-server-1</name> <description>pring Cloud Eureka 註冊中心1</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.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.RELEASE</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>

application.yml

server:
  port: 20001
eureka:
  instance:
    # eureka-server1 是一個別名,需要在 hosts 檔案裡面將其對映為 127.0.0.1
    hostname: eureka-server1
  client:
    serviceUrl:
      # 將自身反註冊到eureka-server2,利用相互註冊,形成高可用註冊中心叢集
      defaultZone: http://eureka-server2:20002/eureka/
    # 將當前服務註冊中心本身也作為服務註冊到別的服務註冊中心(eureka-server2)
    register-with-eureka: true
    # 不將當前服務註冊中心本身也作為服務註冊到別的服務註冊中心(如設為false,則 eureka-server2 中,unavailable-replicas 會包含此註冊中心)
    # register-with-eureka: false

應用啟動器類

package me.zebe.cat.spring.cloud.eureka.server;

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

/**
 * Spring Cloud Eureka 註冊中心1
 *
 * @author Zebe
 */
@EnableEurekaServer
@SpringBootApplication
public class CatSpringCloudEurekaServer1Application {

    /**
     * 執行入口
     * @param args 執行引數
     */
    public static void main(String[] args) {
        SpringApplication.run(CatSpringCloudEurekaServer1Application.class, args);
        System.out.println("Spring Cloud Eureka 註冊中心1 -> 已啟動。");
    }
}

執行該類,啟動時會丟擲異常,提示找不到 eureka-server2,這是因為 eureka-server2 我們沒有啟動,不用管它。

第2步:搭建註冊中心2

第二個註冊中心和第一個註冊中心沒有本質上的區別,只不過是換了執行埠和註冊地址。將第二個工程取名為 cat-spring-cloud-eureka-server-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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>me.zebe</groupId>
    <artifactId>cat-spring-cloud-eureka-server-2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>cat-spring-cloud-eureka-server-2</name>
    <description>pring Cloud Eureka 註冊中心2</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.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.RELEASE</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>

application.yml

server:
  port: 20002
eureka:
  instance:
    # eureka-server2 是一個別名,需要在 hosts 檔案裡面將其對映為 127.0.0.1
    hostname: eureka-server2
  client:
    serviceUrl:
      # 將自身反註冊到eureka-server1,利用相互註冊,形成高可用註冊中心叢集
      defaultZone: http://eureka-server1:20001/eureka/
    # 將當前服務註冊中心本身也作為服務註冊到別的服務註冊中心(eureka-server1)
    register-with-eureka: true
    # 不將當前服務註冊中心本身也作為服務註冊到別的服務註冊中心(如設為false,則 eureka-server1 中,unavailable-replicas 會包含此註冊中心)
    # register-with-eureka: false

應用啟動器類

package me.zebe.cat.spring.cloud.eureka.server;

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

/**
 * Spring Cloud Eureka 註冊中心2
 *
 * @author Zebe
 */
@EnableEurekaServer
@SpringBootApplication
public class CatSpringCloudEurekaServer2Application {

    /**
     * 執行入口
     * @param args 執行引數
     */
    public static void main(String[] args) {
        SpringApplication.run(CatSpringCloudEurekaServer2Application.class, args);
        System.out.println("Spring Cloud Eureka 註冊中心2 -> 已啟動。");
    }
}

執行該類,只要 hosts 檔案裡面按照配置裡面修改好了,啟動時就不會報異常了。

第3步:啟動註冊中心

先啟動註冊中心1,忽略報錯資訊,然後再啟動註冊中心2。分別訪問 http://127.0.0.1:20001http://127.0.0.1:20002
可以看到兩個註冊中心已經互相註冊,配置檔案的註釋裡面已經寫清楚瞭如何觀察。

註冊中心1
spring-cloud-eureka-server-1

註冊中心2
spring-cloud-eureka-server-2

第4步:製作快速啟動指令碼(非必需)

將這兩個註冊中心工程,分別用Maven打包成JAR檔案,然後寫好批處理檔案,後面就可以一健啟動了,比如我為這兩個應用寫了批處理檔案,如下所示:

  • 01 一健啟動 Eureka 註冊中心-1 執行在 20001.cmd
  • 02 一健啟動 Eureka 註冊中心-2 執行在 20002.cmd

內容參考:

title EurekaServer1-20001
java -jar cat-spring-cloud-eureka-server-1-0.0.1-SNAPSHOT.jar
title EurekaServer2-20002
java -jar cat-spring-cloud-eureka-server-2-0.0.1-SNAPSHOT.jar

強烈建議寫為批處理檔案,因為如果要本地搭建為服務學習環境,註冊中心是首先要啟動的基礎設施。

第5步:編寫 HELLO-SERVICE 微服務

建立工程,取名為 cat-spring-cloud-hello-service。該工程很簡單,需要依賴於 eureka client 來實現服務發現,注意需要引用 starter-web 提供WEB訪問功能。

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>me.zebe</groupId>
    <artifactId>cat-spring-cloud-hello-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>cat-spring-cloud-hello-service</name>
    <description>Spring Cloud Hello-Service 服務實現</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.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.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- spring-boot-starter-web -->
        <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>

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

application.yml

server:
  port: 8001
spring:
  application:
    name: hello-service
eureka:
  client:
    serviceUrl:
      # 如果這裡只配置一個服務註冊中心 eureka-server1,那麼當 eureka-server1 掛掉,服務便無法註冊上去
      # defaultZone: http://eureka-server1:20001/eureka/
      # 因此,通常的做法是,將註冊中心的地址寫成多個(用逗號隔開時,不要有空格,不然可能會報解析錯誤)
      defaultZone: http://eureka-server1:20001/eureka/,http://eureka-server1:20002/eureka/
    # 將當前服務註冊到eureka服務註冊中心,這樣消費者就可以發現服務
    register-with-eureka: true
    # 如果設定為false,則不會註冊到服務中心
    #register-with-eureka: false

應用啟動器類

package me.zebe.cat.spring.cloud.service.hello;

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

/**
 * Spring Cloud {Hello-Service} 服務提供者
 *
 * @author Zebe
 */
@EnableEurekaClient
@SpringBootApplication
public class CatSpringCloudEurekaHelloServiceApplication {

    /**
     * 執行入口
     * @param args 執行引數
     */
    public static void main(String[] args) {
        SpringApplication.run(CatSpringCloudEurekaHelloServiceApplication.class, args);
        System.out.println("Spring Cloud Eureka {Hello-Service} 服務提供者 -> 已啟動。");
    }
}

服務提供控制器類

package me.zebe.cat.spring.cloud.service.hello;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * {Hello-Service} 服務提供者控制器
 *
 * @author Zebe
 */
@RestController
public class HelloServiceController {

    @Value("${server.port}")
    private int port;

    /**
     * Hello
     * @return 返回字串
     */
    @GetMapping("/hello")
    public String hello() {
        // 返回值裡面顯示當前的埠號,這樣可以用來測試單個服務節點掛掉之後的執行情況
        return "{Hello} From " + port;
    }

}

啟動該服務,觀察註冊中心,可以看到服務註冊成功。到此為止,一個簡單的微服務註冊例子就完成了。

服務執行截圖

spring-cloud-hello-service-1

spring-cloud-hello-service-2


本文首發於個人獨立部落格,文章連結:http://www.zebe.me/spring-cloud-eureka-server