前言
Eureka作为服务注册与发现的组件,提供了一种简单且可靠的方式来实现微服务架构中的服务注册与发现功能,帮助开发人员构建高可用、可伸缩的分布式系统。
一、服务注册与发现
1. 什么是Eureka?
服务注册与发现是微服务架构中的关键概念之一,而Eureka是Spring Cloud提供的一个开源的服务注册与发现组件。它采用了客户端-服务器的架构模式。通过Eureka的服务注册与发现机制,服务实例可以动态地注册和发现其他服务。当有新的服务实例加入时,Eureka Server会自动更新服务注册表;而当服务实例下线或不可用时,Eureka Server也会相应地将其从注册表中删除。这样,服务实例之间的调用可以更加灵活和自动化。
2. Eureka的工作原理
2.1 Eureka Server 启动:
首先,启动 Eureka Server,它会创建并维护一个服务注册表,用于存储所有已注册的服务实例的信息。
2.2 服务实例注册:
服务实例在启动时,会向 Eureka Server 发送注册请求。服务实例需要在启动配置中指定 Eureka Server 的地址,以便能够找到注册中心。注册请求中包含了服务名称、主机名、端口号等。Eureka Server 在接收到注册请求后,将服务实例的信息存储到注册表中。
2.3 心跳和续约:
注册成功后的服务实例会周期性地发送心跳请求给 Eureka Server,这样 Eureka Server 可以根据心跳信息来判断服务实例的健康状态。如果 Eureka Server 在一定时间内没有收到某个服务实例的心跳请求,就会认为该实例不可用,并从注册表中移除。
2.4 获取服务信息:
其他服务或客户端可以通过 Eureka Client 从 Eureka Server 获取服务实例的信息。Eureka Client 会定期从 Eureka Server 获取注册表的副本,并缓存在本地。当需要访问某个服务时,Eureka Client 可以根据服务名称从本地缓存中获取该服务的实例列表,并通过负载均衡算法选择一个实例进行调用。
2.3 服务调用:
在获取到服务实例的地址后,服务之间可以通过远程调用的方式进行通信。调用方使用服务实例的地址和接口信息来发起请求,被调用方接收请求并返回相应的结果。
2.4 服务下线:
当服务实例需要下线时,它会发送取消注册请求给 Eureka Server,Eureka Server 接收到取消注册请求后会将该服务实例从注册表中移除。
二、EurekaClient实战
1. 搭建项目结构
springcloud-parent //父项目
pom.xml //父项目的pom
springcloud-eureka-server //注册中心EurekaServer
springcloud-user-server //用户服务EurekaClient ,提供者
springcloud-order-server //订单服务EurekaClient ,消费者
2. 父项目管理依赖
springcloud-parent 是一个 Maven 父项目,它是 Spring Cloud 微服务框架的一个常用起步依赖。
<!--1.管理 SpringBoot的jar包-->
<!--SpringBoot-->
<parent>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<!--2.管理 SpringCloud的jar包
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--3.这里是所有子项目都可以用的jar包-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
3. 搭建Eureka Server
在springcloud-parent
父工程下子工程springcloud-eureka-server
进行操作。
3.1 导入依赖
需要同时添加 spring-cloud-starter-netflix-eureka-server
和 spring-boot-starter-web
这两个依赖,以确保 Eureka Server
可以正常运行并提供 Web 服务能力。
<dependencies>
<!--spring-cloud-starter-netflix-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
3.2 主配置类
/**
* 注册中心启动类
* @EnableEurekaServer : 开启EurekaServer服务端
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication{
public static void main( String[] args ){
SpringApplication.run(EurekaServerApplication.class);
}
}
3.3 application.yml配置文件
server: #端口号
port: 8761
eureka:
instance:
hostname: localhost
client: #客户端配置
registerWithEureka: false #表示该服务不会注册到 Eureka Server,禁止自己向自己注册。
fetchRegistry: false #是否从 Eureka Server 获取注册表信息,默认为 true。
serviceUrl: #注册中心的注册地址。
defaultZone: http://localhost:8761/eureka/
server:
enable-self-preservation: false #关闭自我保护警告。
注意:
如果项目运行后显示Failed to load property source from location 'classpath:/application.yml'
报错,请删除yml中的注释重试。
自我保护:
当EurekaServer接收到服务续约的心跳失败比例在15分钟之内低于85%,EurekaServer会把这些服务保护起来,即不会把该服务从服务注册地址清单中剔除掉。
3.4 启动测试
启动springcloud-eureka-server工程,浏览器访问 http://localhost:8761。
4. EurekaClient-用户
4.1 导入依赖
导入EurekaClient基础依赖:spring-cloud-starter-netflix-eureka-client
,和web的基础依赖:spring-boot-starter-web
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
4.2 主配置类
/**
* 用户的启动类
* @EnableEurekaClient: 标记该应用是 Eureka客户端,默认开启
*/
@SpringBootApplication
@EnableEurekaClient
public class UserServerApplication{
public static void main( String[] args ) {
SpringApplication.run(UserServerApplication.class);
}
}
4.3 application.yml配置
server:
port: 8762
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true #使用ip地址进行注册
instance-id: user-server:8762 #实例ID
spring:
application:
name: user-server
使用ip进行注册,为了方便区分和管理服务实例。
4.4 测试EurekaClient
启动springcloud-eureka-server和springcloud-user-server,浏览器再次访问http://localhost:8761,就可以看到user-server服务已经被注册到EurekaServer。
5. Eureka Client-订单
与用户服务注册一样,修改yml就可以了。
略...
application.yml配置
server:
port: 8763
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
instance-id: order-server:8763
spring:
application:
name: order-server
测试
:略…
三、 使用RestTemplate实现服务通信
1. RestTemplate介绍
RestTemplate 是 Spring Framework 提供的用于发送 HTTP 请求和处理 HTTP 响应的类。它是基于 HttpClient 封装的一个高级 RESTful 客户端,用于简化与 RESTful Web 服务进行通信的过程。
2. 实战
2.1 搭建公共模块
springcloud-parent下再新建一个springcloud-user-common(公共User模块):
springcloud-parent
springcloud-eureka-server
springcloud-order-server
springcloud-user-common //公共User模块
springcloud-user-server
在springcloud-user-common中创建User对象:
package top.itimmortal.springboot.domain;
@Data //需要导lombok依赖
public class User {
private Long id;
private String username;
private String desc;
}
2.2 依赖User模块
在用户和订单的pom.xml都导入springcloud-user-common 模块
<dependency>
<groupId>top.itimmortal</groupId>
<artifactId>springcloud-user-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.3 用户服务返回User
编写controller,返回User对象:
package top.itimmortal.controller;
//用户服务:暴露接口给订单访问
@RestController
public class UserController {
//订单服务来调用这个方法
// @GetMapping(value = "/user/{id}" )
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
public User getById(@PathVariable("id")Long id){
//根据id去数据库查询User
return new User(id,"zs:"+id,"我是zs");
}
}
2.4 订单服务获取User
需要在启动类中配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具。
@SpringBootApplication
@EnableEurekaClient
public class OrderServerApplication {
//把RestTmplate配置成Bean方便使用
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main( String[] args ) {
SpringApplication.run(OrderServerApplication.class);
}
}
然后创建controller,通过RestTemplate调用用户服务:
//订单服务
@RestController
public class OrderController {
//需要配置成Bean
@Autowired
private RestTemplate restTemplate ;
//浏览器调用该方法
@RequestMapping(value = "/order/{id}",method = RequestMethod.GET)
public User getById(@PathVariable("id")Long id){
//发送http请求调用 user的服务,获取user对象 : RestTemplate
//目标资源路径:user的ip,user的端口,user的Controller路径
String url = "http://localhost:8762/user/"+id;
//发送http请求
return restTemplate.getForObject(url, User.class);
}
}
2.5 测试服务通信
浏览器访问订单服务:http://localhost:8763/order/1,返回json。
四、Ribbon客户端负载均衡
1.什么是Ribbon?
Ribbon 是一款用于在微服务架构中实现客户端负载均衡的工具,可以平衡多个服务实例间的请求流量,并提供故障转移和容错机制,从而提高系统的可用性和弹性。 提供了丰富的负载均衡策略,如随机、轮询、加权轮询、最少连接等。
2. 实战
2.1 用户服务集群配置
第一步:先开启idea多实例运行
第二步:启动原springcloud-user-server项目(原yml配置)
server:
port: 8762
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
instance-id: user-server:8762
spring:
application:
name: user-server
第三步:项目启动后,修改yml文件中的端口号和实例ID再次运行
server:
port: 8760
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
instance-id: user-server:8760
spring:
application:
name: user-server
第四步:修改Controller
添加端口号,为了后续测试的时候方便区分不同的用户服务实例。
//用户服务:暴露接口给订单访问
@RestController
public class UserController {
//加载端口
@Value("${server.port}")
private int port;
//订单服务来调用这个方法
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
public User getById(@PathVariable("id")Long id){
//根据id去数据库查询User
return new User(id,"zs:"+id,"我是zs, "+port); //端口随User返回
}
}
2.2 消费者Order-server集成Ribbon
第一步:导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
第二步:开启负载均衡
加上Ribbon的负载均衡注解@LoadBalanced赋予RestTemplate有负债均衡的能力。
@SpringBootApplication
@EnableEurekaClient
public class OrderServerApplication {
//配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main( String[] args ) {
SpringApplication.run(OrderServerApplication.class);
}
}
第三步:修改Controller调用方式
把 “localhost:8762” 修改为 用户服务的服务名 。底层会通过服务发现的方式使用Ribbin进行负载均衡调用。
//订单服务
@RestController
public class OrderController {
//需要配置成Bean
@Autowired
private RestTemplate restTemplate ;
//浏览器调用该方法
@RequestMapping(value = "/order/{id}",method = RequestMethod.GET)
public User getById(@PathVariable("id")Long id){
//发送http请求调用 user的服务,获取user对象 : RestTemplate
//目标资源路径:user的ip,user的端口,user的Controller路径
String url = "http://user-server/user/"+id;
//发送http请求
return restTemplate.getForObject(url, User.class);
}
}
第四步:测试Ribbon
分别启动EurekaServer注册中心 ,两个UserServer用户服务,OrderServer订单消费者服务,浏览器访问订单服务:http://localhost:8763/order/1
,发送多次请求。
观察响应的结果中的端口变化 - 端口会交替出现8762
、8760
,我们可以推断出Ribbon默认使用的是轮询策略。