在【在线教育平台-快乐学习】项目中,我们团队使用了Spring Cloud Gateway作为网关,网关在请求路由时需要知道每个微服务实例的地址,接着项目使用Nacos作用服务发现中心和配置中心,并使用Feign远程调用。

这里,对所用技术进行简单的回顾梳理。

img

流程如下:

1、微服务启动,将自己注册到Nacos,Nacos记录了各微服务实例的地址。

2、网关从Nacos读取服务列表,包括服务名称、服务地址等。

3、请求到达网关,网关将请求路由到具体的微服务。

要使用网关首先搭建Nacos,Nacos有两个作用:

1、服务发现中心

微服务将自身注册至Nacos,网关从Nacos获取微服务列表。

2、配置中心

微服务众多,它们的配置信息也非常复杂,为了提供系统的可维护性,微服务的配置信息统一在Nacos配置。

Nacos

统一配置管理

Spring Cloud :一套规范Spring Cloud alibaba: nacos服务注册中心,配置中心

Nacos 作为配置中心功能是基于 Raft 算法来实现的。

补充:Spring Cloud:是基于 Spring Boot 的扩展,专门用于构建和管理 分布式系统,包括微服务架构中的服务发现、负载均衡、熔断、配置管理等功能。适合构建复杂的企业级微服务系统。

首先搭建Nacos服务发现中心。

在搭建Nacos服务发现中心之前需要搞清楚两个概念:namespace和group

namespace:用于区分环境、比如:开发环境、测试环境、生产环境。

group:用于区分项目,比如:xuecheng-plus项目、xuecheng2.0项目

首先在nacos配置namespace:

登录Centos,启动Naocs,使用sh /data/soft/restart.sh将自动启动Nacos。

访问:http://192.168.101.65:8848/nacos/

账号密码:nacos/nacos

登录成功,点击左侧菜单“命名空间”进入命名空间管理界面,

img

点击“新建命名空间”,填写命名空间的相关信息。如下图:

img

使用相同的方法再创建“测试环境”、"生产环境"的命名空间。

img

img

创建成功,如下图:

img

拉取配置文件

image-20240930202538213

1)引入nacos-config依赖

首先,在user-service服务中,引入nacos-config的客户端依赖:

1
2
3
4
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2)添加bootstrap.yaml

然后,在user-service中添加一个bootstrap.yaml文件,内容如下:

1
2
3
4
5
6
7
8
9
10
spring:
application:
name: userservice # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
file-extension: yaml # 文件后缀名

这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据

${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id,来读取配置。

本例中,就是去读取userservice-dev.yaml

配置3要素

先将项目中的配置文件分分类:

1、每个项目特有的配置

是指该配置只在有些项目中需要配置,或者该配置在每个项目中配置的值不同。

比如:spring.application.name每个项目都需要配置但值不一样,以及有些项目需要连接数据库而有些项目不需要,有些项目需要配置消息队列而有些项目不需要。

2、项目所公用的配置

是指在若干项目中配置内容相同的配置。比如:redis的配置,很多项目用的同一套redis服务所以配置也一样。

另外还需要知道nacos如何去定位一个具体的配置文件,即:namespace、group、dataid.

1、通过namespace、group找到具体的环境和具体的项目。

2、通过dataid找到具体的配置文件,dataid有三部分组成

比如:content-service-dev.yaml配置文件 由(content-service)-(dev). (yaml)三部分组成

content-service:第一部分,它是在application.yaml中配置的应用名,即spring.application.name的值。

dev:第二部分,它是环境名,通过spring.profiles.active指定,

Yaml: 第三部分,它是配置文件 的后缀,目前nacos支持properties、yaml等格式类型,本项目选择yaml格式类型。

所以,如果我们要配置content-service工程的配置文件:

在开发环境中配置content-service-dev.yaml

在测试环境中配置content-service-test.yaml

在生产环境中配置content-service-prod.yaml

我们启动项目中传入spring.profiles.active的参数决定引用哪个环境的配置文件,例如:传入spring.profiles.active=dev表示使用dev环境的配置文件即content-service-dev.yaml。

3)读取nacos配置

这部分参考:

热配置

为了实现 Nacos 配置的热更新,使得微服务在不重启的情况下能够动态生效,可以使用两种方式:

  1. 方式一:使用 @RefreshScope 注解
    • @Value 注解通常用于直接从配置文件注入单个属性值。如果要实现配置变更后的热更新,可以在注入了 @Value 的类上使用 @RefreshScope 注解。
    • 当 Nacos 中的配置发生变化时,Spring Cloud 会自动刷新带有 @RefreshScope 的 Bean,更新其内部的配置值。
  2. 方式二:使用 @ConfigurationProperties 注解
    • @ConfigurationProperties 注解用于将一组属性自动映射到一个类中,适合读取多项配置。
    • @Value 不同,@ConfigurationProperties 允许更灵活的配置结构,并且在 Nacos 配置变更时无需手动刷新。
    • 这种方式更推荐,因为它更符合 Spring Boot 配置管理的最佳实践。

1. 创建配置类 PatternProperties

  • 通过 @ConfigurationProperties 注解,绑定 pattern.dateformat 属性,方便在其他类中使用:
1
2
3
4
5
6
7
8
9
10
11
12
package cn.itcast.user.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}
  • 作用:该类会自动读取 Nacos 配置中 pattern.dateformat 的值,将其绑定到 dateformat 属性中。

2. 修改 UserController 使用 PatternProperties

  • 在控制器中,使用 PatternProperties 读取 dateformat 属性,而不再使用 @Value 注解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package tech.wangkay.user.web;

import tech.wangkay.user.config.PatternProperties;
import tech.wangkay.user.pojo.User;
import tech.wangkay.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@Autowired
private PatternProperties patternProperties; // 自动注入属性配置类

@GetMapping("now")
public String now() {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
}

@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id) {
return userService.queryById(id);
}
}
  • 作用:通过 PatternProperties 类读取 pattern.dateformat 配置属性,当 Nacos 中的配置发生变化时,PatternProperties 会自动更新。

3. 热更新方式的选择

  • 使用 @RefreshScope 注解时,需要确保类的生命周期是“刷新作用域”下的。这意味着类中的配置在 Nacos 更新后会重新加载。
  • 使用 @ConfigurationProperties 注解时,无需额外的 @RefreshScope 注解,Spring Cloud Config 会自动刷新配置类中的属性。

配置共享

nacos提供了shared-configs可以引入公用配置。

在content-api中配置了swagger,所有的接口工程 都需要配置swagger,这里就可以将swagger的配置定义为一个公用配置,哪个项目用引入即可。

单独在xuecheng-plus-common分组下创建xuecheng-plus的公用配置,进入nacos的开发环境,添加swagger-dev.yaml公用配置

img

删除接口工程中对swagger的配置。

项目使用shared-configs可以引入公用配置。在接口工程的本地配置文件 中引入公用配置,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
spring:
application:
name: content-api
cloud:
nacos:
server-addr: 192.168.101.65:8848
discovery:
namespace: dev
group: xuecheng-plus-project
config:
namespace: dev
group: xuecheng-plus-project
file-extension: yaml
refresh-enabled: true
extension-configs:
- data-id: content-service-${spring.profiles.active}.yaml
group: xuecheng-plus-project
refresh: true
shared-configs:
- data-id: swagger-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
- data-id: logging-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
profiles:
active: dev

再以相同 的方法配置日志的公用配置。

img

在接口工程和业务工程,引入loggin-dev.yaml公用配置文件

img

配置完成,重启content-api接口工程,访问http://localhost:63040/content/swagger-ui.html 查看swagger接口文档是否可以正常访问,查看控制台log4j2日志输出是否正常。

面试

Nacos详解使用

了解哪些注册中心

工具 特点 主要功能 使用场景
Zookeeper 最早流行的开源分布式协调服务框架之一,需要用户自行实现分布式配置功能。 提供分布式配置中心功能,高可用、可靠性高,但配置功能需自行开发。 适用于需要强一致性和高可用性的分布式系统,且用户有能力开发分布式配置功能。
Nacos 阿里巴巴开源的服务注册中心和配置中心,集成了配置管理工具。 提供服务注册、发现、配置管理和可视化工具,目标是云原生服务平台。 适用于云原生架构的微服务系统,尤其是需要统一配置管理的场景。
Eureka Netflix 开源的服务注册中心,广泛应用于 Spring Cloud 微服务架构。 提供 REST API 和 Web 界面,支持 Region 和 Zone 的服务分组与负载均衡。 适用于 Spring Cloud 微服务架构,提供便捷的服务注册与发现。
Consul HashiCorp 开源的服务注册中心,拥有丰富的功能,如健康检查和 KV 存储。 提供服务注册、发现、健康检查、KV 数据存储、API 和 Web UI 管理,支持健康检查和复杂路由。 适用于需要健康检查、动态路由及配置管理的微服务系统。

Nacos作用

功能 描述
配置管理 将应用程序的配置信息存储在 Nacos 的配置中心,通过动态配置管理和灰度发布,实现微服务的动态热更新和配置。
服务发现与注册 将服务注册到 Nacos 注册中心,Nacos 会自动发现服务并进行负载均衡,实现服务的高可用性和伸缩性。
服务治理 提供健康检查、故障转移、服务限流、熔断降级等治理能力,提升服务的可靠性和稳定性。
事件监听和推送 实现配置变更、服务注册、注销等事件的监听和推送,支持应用程序的自动化部署和管理。

Nacos配置变化客户端感知

Nacos 是一个用于服务注册、发现和配置管理的平台,支持配置热更新、服务治理、健康检查等功能。它通过动态配置和服务负载均衡,提升了微服务的高可用性和可靠性。Nacos 的核心功能还包括事件监听,支持配置变更的实时推送。

长轮询 (Long Polling) 讲解

  • 概念:长轮询是一种介于推送和轮询之间的机制。客户端发起请求后,服务器不会立即返回结果,而是“hold”住请求,直到有数据更新或超时再返回。如果有数据更新,服务器立即返回响应;如果没有更新,服务器则等待一段时间后返回,再由客户端重新发起下一次请求。
  • 优点
    • 实时性强:一旦有配置或数据变更,客户端可以快速感知到更新。
    • 资源消耗较低:相比于传统的短轮询,长轮询减少了不必要的频繁请求,降低了服务器压力。
  • Nacos 的使用
    • Nacos 1.x 版本采用长轮询模式,客户端定期发起请求,服务器保持连接直到有更新。
    • Nacos 2.x 则使用基于 gRPC 的长连接,进一步提高了实时性和性能。

Feign远程调用

我们在不同服务之前需要相互调用,在项目中,我们是使用Feign远程调用的。

Feign 是 Spring Cloud 提供的一种 声明式 HTTP 客户端,用于简化微服务之间的 远程调用。它允许开发者通过 接口 来调用远程服务,就像调用本地方法一样,无需编写大量的 HTTP 请求代码。

Feign 使用示例

定义 Feign 客户端接口

1
2
3
4
5
6
7
8
9
10
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "user-service") // 指定要调用的微服务名称
public interface UserClient {

@GetMapping("/user/{id}")
User getUserById(@PathVariable("id") Long id); // 声明远程调用的方法
}

使用 Feign 调用远程服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

@Autowired
private UserClient userClient; // 注入 Feign 客户端

@GetMapping("/order/{id}")
public String getOrder(@PathVariable("id") Long orderId) {
// 调用远程服务,获取用户信息
User user = userClient.getUserById(orderId);
return "Order placed for user: " + user.getName();
}
}

Feign 的优点

  1. 声明式调用:通过接口和注解的方式,简化了远程服务的调用过程。
  2. 简洁的代码:开发者不再需要手动编写 HTTP 请求代码,减少了重复代码。
  3. 与 Spring Cloud 生态的良好集成:支持与 Ribbon、Hystrix 等组件无缝结合,提供了负载均衡和容错机制。

还有哪些微服务之间调用方法呢?

调用方式 描述 优点 缺点 适用场景
Feign 声明式 HTTP 客户端,简化了微服务之间的 HTTP 调用,支持负载均衡和熔断。 简洁、直观,集成 Ribbon 和 Hystrix,支持负载均衡与容错。 仅支持 HTTP 协议,性能相比其他方式稍逊。 微服务之间通过 HTTP/REST 接口通信的场景,适用于 Spring Cloud 生态。
RestTemplate Spring 提供的同步 HTTP 客户端,用于调用 RESTful API,配置灵活。 使用灵活,可自定义请求头、参数、超时等。 需要手动处理请求构建、响应解析,代码较为冗长。 同样用于 HTTP 通信,适合需要高度自定义的 HTTP 请求场景。
WebClient Spring 5 中引入的异步非阻塞的 HTTP 客户端,支持响应式编程。 支持异步和响应式编程,性能优于 RestTemplate,适合高并发场景。 相比 RestTemplate 和 Feign,代码编写相对复杂。 适用于高并发、响应式编程场景,如对性能和资源利用率要求较高的系统。
gRPC 基于 HTTP/2 和 Protobuf 的高效 RPC 框架,支持多语言微服务之间的通信。 高效、轻量,支持双向流、负载均衡、服务发现和认证,跨语言支持良好。 需要学习和配置 Protobuf,HTTP/2 相比 HTTP/1.1 复杂度高,调试难度大。 对性能要求高,跨语言微服务调用场景,如音视频处理、实时通信等。
Dubbo 阿里巴巴开源的高性能 RPC 框架,支持多种协议与序列化方式,支持负载均衡和服务治理。 高性能,支持多种传输协议(如 Dubbo 协议、HTTP),提供丰富的服务治理功能,支持扩展性强。 生态体系主要集中在 Java,跨语言能力弱于 gRPC。 适用于对性能要求高的内部系统,尤其是需要服务治理、负载均衡等功能的场景。
Spring Cloud Gateway Spring Cloud 提供的 API 网关,支持路由、负载均衡、安全认证等功能,适合前端和后端服务的调用。 提供强大的路由功能,具有负载均衡、限流、熔断和安全认证等能力。 主要用于服务的路由和过滤,复杂业务逻辑不适合。 适用于前端请求统一网关调度后端服务的场景,尤其是需要请求路由、过滤、限流等能力的场景。
消息队列 通过中间件(如 Kafka、RabbitMQ、ActiveMQ 等)进行异步消息通信,实现微服务之间的松耦合。 实现异步通信,解耦服务,支持事件驱动架构,适合高并发和高可用场景。 增加了系统复杂性,消息的时效性和可靠性需要额外考虑。 适用于事件驱动架构、异步处理、跨服务事务管理等场景,尤其是需要解耦的场景。
HTTP 调用 使用标准的 HTTP 请求(如使用 OkHttp、Apache HttpClient 之类的库)进行服务直接调用。 灵活性高,适合定制化需求,几乎所有编程语言都支持 HTTP 调用。 需要手动处理请求和响应,缺乏自动化的负载均衡、容错等功能。 适合简单的服务间通信或者需要跨语言调用的场景。
Thrift Apache 开发的跨语言 RPC 框架,支持多种传输协议和序列化方式,性能较高。 序列化效率高,支持多语言,适合跨语言调用,性能优异。 需要学习和配置 Thrift IDL,调试较复杂,生态不如 gRPC 丰富。 适用于跨语言微服务调用且对性能要求较高的场景。

Gateway服务网关

Spring Cloud Gateway 是 Spring Cloud 生态系统中的一个 API 网关 框架,旨在为微服务架构中的请求提供统一的路由、过滤和管理功能。它是 Spring Cloud 的官方网关解决方案,替代了早期的 Zuul 网关。

功能 描述
请求路由 路由是网关的基本功能,用于将客户端的请求转发到不同的微服务或后端系统。支持根据路径、方法、头信息等条件进行路由。
过滤器 过滤器用于在请求被路由之前或之后进行处理。内置过滤器支持修改请求头、添加响应头、限流、重定向等操作,支持自定义过滤器以满足更复杂的需求。
负载均衡 与 Spring Cloud LoadBalancer 集成,实现对后端服务的负载均衡。在多个服务实例之间分发请求,提升系统的可用性和性能。
安全认证与授权 支持与 Spring Security 集成,实现身份认证和权限控制。可以通过 JWT 验证用户身份,并根据角色对请求进行授权。
限流和熔断 与 Resilience4j 或 Hystrix 集成,实现请求的熔断和限流功能,防止后端服务过载或故障影响系统的稳定性。
路径重写 支持请求路径重写,例如将 /api/service1/** 重写为 /service1/**,从而简化后端服务的路径管理。
WebSocket 支持 支持 WebSocket 通信,能够处理 WebSocket 请求并将其转发到后端服务,实现实时双向通信。
监控与可视化 可以与 Spring Boot Actuator 集成,提供路由、过滤器、限流等功能的监控数据,帮助管理员实时掌握网关的运行状态和性能。

核心功能:

  • 请求路由
  • 权限控制
  • 限流

Gateway快速入门

学成在线搭建网关工程

  1. 创建SpringBoot工程gateway,引入网关依赖
  2. 编写启动类
  3. 编写基础配置和路由规则
  4. 启动网关服务进行测试.

引入网关依赖

1
2
3
4
5
6
7
8
9
10
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

编写启动类

1
2
3
4
5
6
7
8
9
10
11
12
package cn.itcast.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayApplication {

public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}

编写基础配置和路由规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 63010 # 网关端口
spring:
cloud:
gateway:
routes: # 网关路由配置
- id: content-api # 路由id
uri: lb://content-api # 路由的目标地址,lb表示负载均衡,后面是Nacos中注册的服务名称
predicates: # 路由断言即判断请求是否符合路由规则的条件
- Path=/content/** # 匹配以/content/开头的请求
- id: system-api
uri: lb://system-api # 转发到Nacos中system-api服务对应的服务实例
predicates:
- Path=/system/**
- id: media-api
uri: lb://media-api # 转发到Nacos中media-api服务对应的服务实例
predicates:
- Path=/media/**

我们将符合Path 规则的一切请求,都代理到 uri参数指定的地址。

本例中,我们将 /user/**开头的请求,代理到lb://userservice,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡。

整个访问的流程如下:

image-20240930210044191

有意思的问题:网关如果挂了还能正常运行吗?

如果网关挂掉了,通常情况下系统**将无法正常运行。**原因如下:

网关是系统的“单点入口”

  • 在微服务架构中,网关通常是整个系统的唯一入口,所有请求都通过网关转发到后端服务。如果网关挂掉了,客户端的请求将无法到达后端服务。
  • 这意味着系统的所有服务对外部的暴露将被阻断,整个系统可能会变得不可用。

参考自:微服务Day3y