近年来微服务非常流行,鼎鼎大名的 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 注册中心,查看集群搭建情况,比如访问的是 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 的映射关系。