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 服务实例的健康自检 (下)

别忘了点赞关注收藏~

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