(Spring Cloud 入门到进阶 - 01 Eureka集群搭建(中))
内容关联篇(建议先看): Spring Cloud 入门到进阶 - 01 Eureka 介绍及简单服务搭建(上)
一、Eureka 集群搭建
在上篇,运行第一个 Eureka 应用时,服务器实例、服务提供者实例都只启动了一个,并没有体现高可用的特性,本篇将对上篇的 Eureka 应用进行改造,使其可以进行集群部署。 请提前编写或下载上篇的示例代码,本篇将基于上篇的示例代码,进行修改演示。
1、本例集群结构图
本例将会运行两个服务器实例、两个服务提供者实例,然后服务调用者请求服务。
第一个 Eureka 应用,使用的是浏览器访问 Eureka 的服务调用者,而改造后,为了能看到负载均衡的效果,会编写一个 HttpClient 的 REST 客户端访问服务调用者发布的服务。
由于博主的开发环境只有一台电脑,操作系统为 Windows ,如果要构建集群,需要修改 hosts 文件,为其添加主机名的映射。修改 C:\Windows\System32\drivers\etc
文件,添加以下内容:
127.0.0.1 slave1 slave2
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 ,名称分别为 slave1
和 slave2
。
在 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=8082
,最后依次启动即可。
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 集群
集群项目搭建完成后,我们按以下顺序依次启动各个组件:
-
启动两个 Eureka 服务器。 启动
slave1
服务 启动slave2
服务 可以看到我们的两个服务中心已经相互注册成功! -
启动两个 Eureka 服务提供者。 服务提供者发布的 REST 接口:
-
启动一个 Eureka 服务调用者。
2、测试访问集群
整个集群启动成功以后,我们运行 TestHttpClient,查看运行结果。 根据输出结果可知, 8081 与 8082 端口分别被请求了 3 次,可见己经达到负载均衡的目的,关于负载均衡更详细的内容,我们后面再说。
三、项目下载
1、项目完整结构图
2、源码下载
码云Gitee仓库地址:https://gitee.com/swotxu/Spring-Cloud-Study.git
>>戳这里<<
项目路径:Spring-Cloud-Study/01/springcloud02
为了能演示 Eureka 高可用特性,下篇,我们将会以本案例为基础,讲解服务实例的健康自检。
别忘了点赞关注收藏~