Spring Cloud 入門到進階 - 01 Eureka集羣搭建(中)


博主整理的SpringCloud系列:目錄

上篇:Spring Cloud 入門到進階 - 01 Eureka介紹及簡單服務搭建(上)


一、Eureka 集羣搭建

在上篇,運行第一個 Eureka 應用時,服務器實例、服務提供者實例都只啓動了一個,並沒有體現高可用的特性,本篇將對上篇的 Eureka 應用進行改造,使其可以進行集羣部署。
請提前編寫或下載上篇的示例代碼,本篇將基於上篇的示例代碼,進行修改演示。

1、本例集羣結構圖

本例將會運行兩個服務器實例、兩個服務提供者實例,然後服務調用者請求服務。

第一個 Eureka 應用,使用的是瀏覽器訪問 Eureka 的服務調用者,而改造後,爲了能看到負載均衡的效果,會編寫一個 HttpClient 的 REST 客戶端訪問服務調用者發佈的服務。

由於博主的開發環境只有一臺電腦,操作系統爲 Windows ,如果要構建集羣,需要修改 hosts 文件,爲其添加主機名的映射。修改 C:\Windows\System32\drivers\etc 文件,添加以下內容:

127.0.0.1 slave1 slave1

Eureka集羣架構圖

2、改造服務器端

新建項目 first-cloud-server,使用的 Maven 配置與上篇的 first-ek-server 一樣,可直接複製過來使用。

2.1、配置 application.yml

由於我們需要對同一個應用程序啓動兩次(啓動兩個服務中心),因此需要在配置文件中使用 profiles 如下。

spring:
  profiles:
    active: slave1 #可通過JVM啓動參數修改

---

server:
  port: 8761
spring:
  application:
    name: first-cloud-server
  profiles: slave1
eureka:
  instance:
    hostname: slave1
  client:
    serviceUrl:
      defaultZone: http://slave2:8762/eureka/

---

server:
  port: 8762
spring:
  application:
    name: first-cloud-server
  profiles: slave2
eureka:
  instance:
    hostname: slave2
  client:
    serviceUrl:
      defaultZone: http://slave1:8761/eureka/

上面配置文件中,配置了兩個 profiles ,名稱分別爲 slave1slave2
slave1 中,配置了應用端口爲 8761,主機名爲 slave1。當使用 slave1 這個 profiles 來啓動服務器時,將會向 http://slave2:8762/eureka/ 註冊自己。
slave2 中,配置了應用端口爲 8762,主機名爲 slave2。當使用 slave2 這個 profiles 來啓動服務器時,將會向 http://slave1:8761/eureka/ 註冊自己。
簡單點說,就是兩個服務器啓動後,它們會互相註冊。

2.2、服務啓動方式

啓動多實例加載不同配置,這裏提供兩種方式,任選一種即可(博主這裏使用第二種)。

  • 1.使用 SpringApplicationBuilder 設置
    修改啓動類,讓類在啓動時讀取控制檯的輸入,決定使用哪個 profiles 來啓動服務器。

    package com.swotxu.firstcloudserver;
    
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    import java.util.Scanner;
    
    /**
     * Eureka 集羣服務
     *
     * 啓動多實例加載不同配置的兩種方式:
     * 方式一:
     * 啓動時,添加JVM參數: -Dspring.profiles.active=slave1
     *
     * 方式二:
     * 從控制檯輸入環境參數,並通過 SpringApplicationBuilder 進行設置。
     *
     * @Date: 2020/6/27 22:05
     * @Author: swotXu
     */
    @SpringBootApplication
    @EnableEurekaServer // 聲明這是一個 Eureka 服務器
    public class FirstCloudServer {
    
        public static void main(String[] args) {
            /*System.out.println("請輸入當前服務的環境 profiles = ");
            Scanner scanner = new Scanner(System.in);
            String profiles = scanner.nextLine();
            new SpringApplicationBuilder(FirstCloudServer.class).profiles(profiles).run(args);*/
            // 這裏採用第二種方式
            new SpringApplicationBuilder(FirstCloudServer.class).run(args);
        }
    }
    

    在啓動類中,先讀取控制檯的輸入,再調用 profiles 方法設置啓動的 profiles 。

  • 2.設置JVM啓動參數
    這裏以IDEA爲例,我們可以複製兩個啓動類配置,分別設置爲 -Dspring.profiles.active=slave1-Dspring.profiles.active=slave2,最後依次啓動即可。
    在這裏插入圖片描述
    在這裏插入圖片描述

需要注意的是,第一個啓動的服務器會拋出異常,異常原因我們在上篇中己經講述過,拋出的異常不必理會。

2.3、項目完整結構圖 - first-cloud-server

在這裏插入圖片描述

3、改造服務提供者

服務提供者也需要啓動兩個實例,服務提供者的改造與服務端類似。
我們將上篇的 first-ek-server-provider 複製出來,並改名爲 first-cloud-provider

3.1、配置 application.yml

修改配置文件,將服務提供者註冊到兩個服務器中,配置文件如下:

spring:
  application:
    name: first-cloud-provider
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
3.2、服務啓動方式

同上,爲了避免端口衝突,啓動多實例加載不同配置,這裏提供兩種方式,任選一種即可(博主這裏使用第二種)。

  • 1.使用 SpringApplicationBuilder 設置
    修改啓動類,讓類在啓動時讀取控制檯輸入的端口,來設置並啓動服務器。

    package com.swotxu.firstekcloudprovider;
    
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    /**
     * 啓動多實例加載不同配置的兩種方式:
     * 方式一:
     * 啓動時,添加JVM參數: -Dserver.port=8081
     *
     * 方式二:
     * 從控制檯輸入環境參數,並通過 SpringApplicationBuilder 進行設置。
     */
    @EnableEurekaClient
    @SpringBootApplication
    public class FirstCloudProviderApplication {
    
        public static void main(String[] args) {
            /*System.out.println("請輸入當前服務的端口 port = ");
            Scanner scanner = new Scanner(System.in);
            String port = scanner.nextLine();
            new SpringApplicationBuilder(FirstEkServerProviderApplication.class).properties("server.port=" + port).run(args);*/
            // 這裏採用第二種方式
            new SpringApplicationBuilder(FirstCloudProviderApplication.class).run(args);
        }
    }
    
  • 2.設置JVM啓動參數
    這裏以IDEA爲例,我們可以複製兩個啓動類配置,分別設置JVM參數爲 -Dserver.port=8081-Dserver.port=8081,最後依次啓動即可。
    在這裏插入圖片描述

3.3、修改服務提供類

爲了能看到效果,還需要改造控制器,將服務調用者請求的 URL 保存起來並返回,修改後的控制器代碼如下:

package com.swotxu.firstekcloudprovider.web;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @Date: 2020/6/25 20:50
 * @Author: swotXu
 */
@RestController
public class FirstController {

    @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public UserInfo findUser(@PathVariable("userId") Integer userId, HttpServletRequest request){
    	// 爲了查看結果,獲取請求的 url
        String url = request.getRequestURL().toString();
        UserInfo userInfo = new UserInfo(userId, "swotxu", 18, url);
        return userInfo;
    }
}
3.4、項目完整結構圖 - first-cloud-provider

在這裏插入圖片描述

4、改造服務調用者

服務提供者只需要啓動一個實例。我們將上篇的 first-ek-server-invoker 複製出來,並改名爲 first-cloud-invoker

4.1、配置 application.yml

修改配置文件,將服務調用者註冊到兩個服務器中,配置文件如下:

server:
  port: 9000
spring:
  application:
    name: first-cloud-invoker
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
4.2、修改服務調用者
package com.swotxu.firstcloudinvoker;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * @Date: 2020/6/27 17:09
 * @Author: swotXu
 */
@Slf4j
@Configuration
@RestController
public class lnvokerController {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    @RequestMapping(value = "/router", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public String router(){
        RestTemplate restTemplate = getRestTemplate();
        // 根據應用名稱調用服務。其中 first-cloud-provider 是服務提供者配置的服務名(spring.application.name)
        String json = restTemplate.getForObject("http://first-cloud-provider/user/1", String.class);
        log.info("result: {}", json);
        return json;
    }
}
4.3、項目完整結構圖 - first-cloud-invoder

在這裏插入圖片描述

5、編寫 REST 客戶端進行測試

這裏我們使用的是 HttpClient,HttpClient 是 Apache 提供的一個 HTTP 工具包。通過代碼的方式,模擬用戶瀏覽器請求。

我們新建一個名爲 first-cloud-rest-client 的 MAVEN 項目,在 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>com.swotxu</groupId>
    <artifactId>first-cloud-rest-client</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>
    </dependencies>

</project>

新建一個類,在 main 方法中編寫調用 REST 服務的代碼。

package com.swotxu.firstcloudrestclient;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

/**
 * @Date: 2020/6/28 16:20
 * @Author: swotXu
 */
public class TestHttpClient {

    public static void main(String[] args) throws IOException {
        // 創建默認的 HttpClient
        CloseableHttpClient client = HttpClients.createDefault();
        // 調用 6 次服務並輸出結果
        for (int i = 0; i < 6; i++) {
            // 調用 GET 方法請求服務
            HttpGet httpGet = new HttpGet("http://localhost:9000/router");
            // 獲取響應
            CloseableHttpResponse response = client.execute(httpGet);
            // 根據響應解析出字符串
            System.out.println(EntityUtils.toString(response.getEntity()));
        }
    }
}

項目完整結構圖 - first-cloud-rest-client
在這裏插入圖片描述

二、Eureka 集羣測試

1、啓動 Eureka 集羣

集羣項目搭建完成後,我們按以下順序依次啓動各個組件:

  1. 啓動兩個 Eureka 服務器。
    slave1 服務
    在這裏插入圖片描述
    slave2 服務
    在這裏插入圖片描述

  2. 啓動兩個 Eureka 服務提供者。
    在這裏插入圖片描述
    服務提供者發佈的 REST 接口:
    在這裏插入圖片描述

  3. 啓動一個 Eureka 服務調用者。
    在這裏插入圖片描述

2、測試訪問集羣

整個集羣啓動成功以後,我們運行 TestHttpClient,查看運行結果。
在這裏插入圖片描述
根據輸出結果可知, 8081 與 8082 端口分別被請求了 3 次,可見己經達到負載均衡的目的,關於負載均衡更詳細的內容,我們後面再說。

三、項目下載

1、項目完整結構圖

在這裏插入圖片描述

2、源碼下載

碼雲Gitee倉庫地址:https://gitee.com/swotxu/Spring-Cloud-Study.git
項目路徑:Spring-Cloud-Study/01/springcloud02


爲了能演示 Eureka 高可用特性,下篇,我們將會以本案例爲基礎,講解服務實例的健康自檢。

下篇:Spring Cloud 入門到進階 - 01 Eureka 服務實例的健康自檢 (下)

別忘了點贊關注收藏~

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