近年来微服务非常流行,鼎鼎大名的 SpringCloud 就是专门为微服务技术开发而提供的解决方案。
SpringCloud 是一系列框架的有序集合,它将市场上各个公司比较成熟的并且经过实战检验的服务进行组合,采用 SpringBoot 技术进行再次封装,屏蔽掉复杂的配置和底层实现细节,最终提供给开发者一套简单易懂、易部署和易维护的分布式系统开发工具包,比如:服务注册与发现、配置中心、负载均衡、服务治理、数据监控等,都可以使用 Spring Boot 开发技术轻松做到一键启动和部署。
SpringCloud 下的各个 SpringBoot 微服务之间,采用 Restful 接口完成通信,这是一种使用非常广泛的通信协议,适应性很强。
本篇博客主要通过代码的方式,介绍 SpringCloud Eureka 注册中心的集群搭建和使用,在本篇博客的最后会提供源代码下载。
Eureka 是 Netflix 公司开源的一个服务注册与发现的组件 ,它连同 Netflix 公司的其它服务组件(如 Ribbon 负载均衡、Hystrix 服务治理、Gateway 网关等) 一起被 Spring Cloud 社区整合为 Spring-Cloud-Netflix 模块。Eureka 包含两个组件:Eureka Server (注册中心需要使用) 和 Eureka Client (服务提供者和服务消费者需要使用)。
限于篇幅,这里不会对 SpringCloud 及其相关组件进行详细的介绍,请从官网或其它网站查阅相关资料。
SpringCloud 官网地址为:https://spring.io/projects/spring-cloud
一、搭建工程
本篇博客的 Demo 将采用 SpringBoot 搭建 3 个 Eureka 注册中心,一个服务提供者和一个服务消费者。
有关 SpringBoot 的搭建细节,这里不再赘述,为了更好的管理整个工程,创建了一个 Maven 父工程进行管理。
父工程的名字是 springcloud_eureka ,其 pom 文件内容如下:
<?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.jobs</groupId>
<artifactId>springcloud_eureka</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>eureka1</module>
<module>eureka2</module>
<module>eureka3</module>
<module>consumerApp</module>
<module>providerApp</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<!--spring boot-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.11</version>
<relativePath/>
</parent>
<!--Spring Cloud-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
二、注册中心集群搭建
本篇博客采用 SpringBoot 搭建了 3 个 Eureka 注册中心,搭建过程非常简单,我们以 eureka1 来进行演示。
首先需要在 pom 文件中引入 spring-cloud-starter-netflix-eureka-server 的 jar 包依赖。
<?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">
<parent>
<artifactId>springcloud_eureka</artifactId>
<groupId>com.jobs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka1</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
然后在 SpringBoot 启动类上,使用 @EnableEurekaServer 注解。
package com.jobs.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
//启用EurekaServer
@EnableEurekaServer
@SpringBootApplication
public class EurekaApp1 {
public static void main(String[] args) {
SpringApplication.run(EurekaApp1.class,args);
}
}
最后在 application.yml 中进行相关配置即可。
server:
port: 8761
eureka:
instance:
# 配置主机名,请在【Host】文件中进行主机名与本机ip的映射配置
hostname: eureka-server1
# 显示 ip 地址,代替显示主机名
prefer-ip-address: true
# 所注册服务实例名称的显示形式
instance-id: ${eureka.instance.hostname}:${server.port}
# 每隔 3 秒发一次心跳包
lease-renewal-interval-in-seconds: 3
# 如果 15 秒没有发送心跳包,就让 eureka 把自己从服务列表中移除
lease-expiration-duration-in-seconds: 15
client:
service-url:
# 想要搭建 eureka 集群,需要将自己注册到其它的 eureka 中
# 因此这里需要配置其它 eureka 地址,多个地址以英文逗号分隔
defaultZone: http://eureka-server2:8762/eureka,http://eureka-server3:8763/eureka
# 是否将自己的路径注册到 eureka 上
register-with-eureka: true
# 是否需要从 eureka 中抓取路径
fetch-registry: true
server:
# 关闭 eureka 自我保护,当注册的服务未及时发送心跳时,自动移除服务
enable-self-preservation: false
# eureka 检查服务是否存在的时间间隔(毫秒)
eviction-interval-timer-in-ms: 5000
# 集群需要使用相同的 application 名称
spring:
application:
name: eureka-server-cluster
其它两个注册中心:eureka2 和 eureka3 的搭建过程一模一样,只需要修改 application.yml 中相应端口、实例名称、服务地址即可。其中服务地址(service-url)需要配置另外两个 Eureka 的地址,因为必须保证所有的 Eureka 互相注册,才能确保 Eureka 之间互相感知,从而实现 Eureka 集群的搭建。
另外需要注意的是:
- 3 个 Eureka 的应用名称(application 下的 name)的配置需要保持一致。
- 需要将 instance 下面的 hostname 对应的 ip 地址配置到 hosts 文件中(本 demo 都映射到了 127.0.0.1)
此时分别启动 3 个 Eureka 注册中心,查看集群搭建情况,比如访问的是 eureka1 的界面 localhost:8761 如下图所示:
DS Replicas 表示 Eureka 的副本数,可以发现当前 eureka-server1 的副本为 eureka-server2 和 eureka-server3 。
Instances currently registered with Eureka 表示注册到 Eureka 中的服务实例,下面列出了 EUREKA-SERVER-CLUSTER ,其后面对应了 3 个注册中心的实例,分别为 eureka-server1:8761 , eureka-server2:8762, eureka-server3:8763
当然你可以访问 localhost:8762 和 localhost:8763 来查看 eureka2 和 eureka3 的界面,可以 3 个注册中心互相为副本。
到此为止,Eureka 注册中心集群搭建完毕,为了验证其使用效果,需要搭建服务提供者和服务消费者进行测试。
三、服务提供者搭建
无论是服务的提供者,还是服务消费者,也可能既是服务提供者,也是服务消费者,搭建都很简单。
首先需要在 pom 文件中引入 spring-cloud-starter-netflix-eureka-client 的 jar 包依赖。
<?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">
<parent>
<artifactId>springcloud_eureka</artifactId>
<groupId>com.jobs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>providerApp</artifactId>
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
然后在 application.yml 中进行相关配置即可。
server:
port: 8200
eureka:
instance:
# 配置主机名,请在【Host】文件中进行主机名与本机ip的映射配置
hostname: provider_service
# 显示 ip 地址,代替显示主机名
prefer-ip-address: true
# 所注册服务实例名称的显示形式
instance-id: ${eureka.instance.hostname}:${server.port}
# 每隔 3 秒发一次心跳包
lease-renewal-interval-in-seconds: 3
# 如果 15 秒没有发送心跳包,就让 eureka 把自己从服务列表中移除
lease-expiration-duration-in-seconds: 15
client:
service-url:
# 将当前 springboot 服务注册到所有的 eureka 中,多个地址以英文逗号分隔
defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka,http://eureka-server3:8763/eureka
# 是否将自己的路径注册到 eureka 上
register-with-eureka: true
# 是否需要从 eureka 中抓取路径
fetch-registry: true
# 集群需要使用相同的 application 名称
spring:
application:
name: provider-App
最后我们编写一个 Controller 接口,用于后续的测试
package com.jobs.provider.controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RequestMapping("/provider")
@RestController
public class ProviderController {
@RequestMapping("/getdata/{id}")
public Map GetData(@PathVariable("id") int id) {
Map result = new HashMap();
result.put("status",0);
result.put("msg","success");
result.put("get_id_value",id);
result.put("version", UUID.randomUUID().toString());
return result;
}
}
四、服务消费者搭建
服务的消费者搭建过程,与服务提供者搭建过程基本上一模一样。
首先需要在 pom 文件中引入 spring-cloud-starter-netflix-eureka-client 的 jar 包依赖。
<?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">
<parent>
<artifactId>springcloud_eureka</artifactId>
<groupId>com.jobs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumerApp</artifactId>
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
然后在 application.yml 中进行相关配置即可。
server:
port: 8100
eureka:
instance:
# 配置主机名,请在【Host】文件中进行主机名与本机ip的映射配置
hostname: consumer_service
# 显示 ip 地址,代替显示主机名
prefer-ip-address: true
# 所注册服务实例名称的显示形式
instance-id: ${eureka.instance.hostname}:${server.port}
# 每隔 3 秒发一次心跳包
lease-renewal-interval-in-seconds: 3
# 如果 15 秒没有发送心跳包,就让 eureka 把自己从服务列表中移除
lease-expiration-duration-in-seconds: 15
client:
service-url:
# 将当前 springboot 服务注册到所有的 eureka 中,多个地址以英文逗号分隔
defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka,http://eureka-server3:8763/eureka
# 是否将自己的路径注册到 eureka 上
register-with-eureka: true
# 是否需要从 eureka 中抓取路径
fetch-registry: true
# 集群需要使用相同的 application 名称
spring:
application:
name: consumer-App
最后我们需要编写一个 Controller 接口,采用 RestTemplate 调用服务提供者的接口,进行测试验证。
package com.jobs.consumer.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
// RestTemplate 简化了调用 Restful 接口的开发方式
return new RestTemplate();
}
}
package com.jobs.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@RequestMapping("/consumer")
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/getdata/{id}")
public Map GetData(@PathVariable("id") int id) {
//使用服务在 eureka 上注册的 application 名称代替 ip 和端口号
String url = "http://PROVIDER-APP/provider/getdata/" + id;
Map result = restTemplate.getForObject(url, Map.class);
return result;
}
}
五、测试验证
启动 3 个 Eureka 注册中心、服务提供者、服务消费者,访问其中一个注册中心界面,比如 localhost:8762 进行查看:
从上图可以发现,Eureka 集群、服务提供者、服务消费者,都已经注册到 Eureka 集群中,可以随时监控状态。
此时访问 localhost:8200/provider/getdata/1 这个地址,可以直接访问服务提供者的接口进行测试。
也可以访问 localhost:8100/consumer/getdata/6 这个地址,访问服务消费者的接口进行测试,此时服务消费者的接口中的代码通过 Eureka 注册中心获取到服务提供者的地址,然后再去调用服务提供者的地址获取数据。
另外一个非常重要的测试是:当 Eureka 集群中,有一个或两个 Eureka 注册中心被停掉(模拟公网上宕掉)的情况下,此时访问服务消费者的接口,服务消费者接口中的代码仍然可以从生下的一个 Eureka 注册中心中,获取到服务提供者的地址,并且调用服务提供者的接口成功,并返回数据。
OK,到此为止,SpringCloud Eureka 注册中心集群搭建和使用,已经介绍完毕。
本篇博客的 Demo 下载地址为:https://files.cnblogs.com/files/blogs/699532/springcloud_eureka.zip
需要注意的是:运行本 Demo 需要提前在 hosts 文件中,建议 3 个 Eureka 的 hostname 与 127.0.0.1 的映射关系。