Spring Cloud - 注册中心、中央配置、网关

| 笔记 | 6061 | 16分钟 | 实习,SpringCloud,微服务

本文属于学习笔记,内容可能有误、可能不全面,仅代表个人在学习这一特性时的理解和总结

实习第一天,主要目的是学习云原生架构。今天先从 Spring Cloud 开始。

31722821596_.pic

总的来说,Spring Boot 提供构建应用的基础,Spring Cloud 在此基础上提供了分布式系统和微服务架构所需的工具和支持。

1 注册中心(Eureka)

1.1 Eureka 名字由来

“Eureka”是希腊语,意思是“我发现了!”

源自经典的 阿基米德洗澡时发现浮力原理 小故事。

阿基米德在洗澡时发现了证明王冠是否纯金的方法(黄金密度),他激动地一边大喊“Eureka!”一边跳出澡盆奔去王宫,连衣服都忘了穿。后来人们用Eureka这个词来形容洞察浮现的瞬间。

1.2 网络架构

一个最简单的示例如下:

image-20240805104516240

要记住这个架构是一个微服务架构,将各个功能的实现分布式地部署在多个服务器中。每一个微服务都是独立的Springboot App,分为以下三类:

  1. Eureka Server(注册中心)
  2. Eureka Client(服务提供者)
  3. Eureka Client(服务消费者)

1.2.1 注册中心

注册中心是一个中央服务器,其他微服务都知道注册中心的Url。

只需要增加配置,并在入口处增加 @EnableEurekaServer 注解。

server:
    port: 8761

eureka:
    client:
        register-with-eureka: false
        fetch-registry: false
    server:
        enable-self-preservation: false
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}

1.2.2 服务提供者

服务提供者实现了一部分的 REST 接口,即实现 Controller。在启动时会连接上注册中心,将他提供的接口注册到Eureka Server。可以有多个提供者提供相同的接口。

服务提供者在配置文件中设置实例名称,以及注册中心的Url

server:
  port: 8081

spring:
  application:
    name: provider-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

1.2.3 服务消费者

服务消费者的工作流程:

  • 消费者发送请求 http://provider-service/hello。(这里的 provider-service 就是服务提供者设置的实例名称,hello 是提供者已经实现的一个接口。)
  • RestTemplate 查询 Eureka 注册中心,获取 provider-service 的所有实例地址。
  • 负载均衡器选择一个实例,将请求路由到该实例。

代码实现是:

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/invoke")
    public String invokeProviderService() {
        return restTemplate.getForObject("http://provider-service/hello", String.class);
    }
}

在配置中设置 RestTemplate ,增加 @loadBalanced 负载均衡注解:

@Configuration
public class AppConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

RestTemplate的简化

RestTemplate 是 Spring 提供的一个同步 HTTP 客户端,用于简化与 RESTful 服务的通信。它提供了多种便捷的方法,可以轻松地执行各种 HTTP 请求(如 GET、POST、PUT、DELETE 等)并处理响应。RestTemplate 可以自动处理请求和响应的序列化和反序列化,使得与 REST API 的交互变得更加简洁和直观。

@LoadBalanced 注解是 Spring Cloud 实现的,会自动完成以下步骤:

  1. 服务发现:从 Eureka 注册中心获取指定服务的所有可用实例。
  2. 负载均衡:根据负载均衡策略(默认是轮询)选择一个实例。
  3. 请求转发:将请求转发到选择的实例。

如果不使用 @LoadBalance 注解,完整的 invoke 接口实现如下:

import cn.hutool.http.HttpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Random;

@RestController
public class ConsumerController {

    @Autowired
    private DiscoveryClient discoveryClient;

    private final Random random = new Random();

    @GetMapping("/invoke")
    public String invokeProviderService() {
        // 获取 provider-service 的所有实例
        List<ServiceInstance> instances = discoveryClient.getInstances("provider-service");

        if (instances == null || instances.isEmpty()) {
            throw new IllegalStateException("No instances available for provider-service");
        }

        // 随机选择一个实例(简单的负载均衡策略)
        ServiceInstance selectedInstance = instances.get(random.nextInt(instances.size()));

        // 构造服务URL
        String url = selectedInstance.getUri().toString() + "/hello";

        // 使用 Hutool 发送 HTTP 请求
        return HttpUtil.get(url);
    }
}

2 中央配置(Spring Cloud Config)

原理差不多。中央配置与服务注册的逻辑是独立的,他们互不相关。

也分为 config-clientconfig-server.

配置文件参考网上其他教程。


我测试过程中遇到一个问题,client一直没有向 server 发送获取配置的请求。

原因:

pom.xml 中必须有以下配置(开始运行时获取配置)

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

并且不能有 server 的依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

我就是在client的 pom.xml 里不小心赋值进去了 config-server 的依赖,导致一直没有获取配置。


另外,有两个设计思路:

  1. config-client 连接 config-server,自动获取 config-server 的注册中心
  2. 设置注册中心,获取注册中心里的 config-server

总之目的就是有一个统一的配置文件管理仓库,所有微服务启动时都能获取到最新的配置。

3 网关(Spring Cloud Gateway)

也是一个单独的应用。通过集成 Spring Cloud Gateway,可以在微服务架构中实现集中路由和过滤功能。

贴一下GPT的回答。

Spring Cloud Gateway 简介

Spring Cloud Gateway 是一种基于 Spring Framework 5、Spring Boot 2 和 Project Reactor 的 API 网关,旨在为微服务架构提供路由、过滤、监控和安全功能。与 Zuul 不同,Spring Cloud Gateway 使用非阻塞的 WebFlux 框架,这使得它在处理高并发请求时更加高效。

集成 Spring Cloud Gateway

1. 创建 Spring Cloud Gateway 项目

  1. 创建一个新的 Spring Boot 项目
  2. 添加依赖

pom.xml 中添加 Spring Cloud Gateway 和 Eureka Client 的依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <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-actuator</artifactId>
    </dependency>
</dependencies>

2. 配置 Gateway

src/main/resources/application.yml 中配置 Gateway:

server:
  port: 8080

spring:
  application:
    name: gateway

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

spring:
  cloud:
    gateway:
      routes:
        - id: provider-service
          uri: lb://provider-service
          predicates:
            - Path=/provider/**
          filters:
            - StripPrefix=1
        - id: consumer-service
          uri: lb://consumer-service
          predicates:
            - Path=/consumer/**
          filters:
            - StripPrefix=1

以上配置定义了两个路由:

  • /provider/** 路径的请求将被转发到 provider-service
  • /consumer/** 路径的请求将被转发到 consumer-service

StripPrefix=1 表示在转发请求之前,将 URL 路径前缀 /provider/consumer 去掉。

3. 启动类

在主类中添加 @SpringBootApplication@EnableEurekaClient 注解:

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

启动和测试

  1. 启动 Eureka Server
  2. 启动 Config Server
  3. 启动多个服务提供者实例
  4. 启动服务消费者
  5. 启动 Gateway

测试 Gateway 路由

访问 Gateway 路由以测试:

  1. 测试服务提供者:

    curl http://localhost:8080/provider/hello

    或在浏览器中访问:

    http://localhost:8080/provider/hello
  2. 测试服务消费者:

    curl http://localhost:8080/consumer/invoke

    或在浏览器中访问:

    http://localhost:8080/consumer/invoke

总结

通过集成 Spring Cloud Gateway,您可以在微服务架构中实现集中路由和过滤功能。它提供了强大的功能和灵活性,可以根据需要进行自定义和扩展。在上述配置中,我们实现了基本的服务路由,实际项目中可以根据需求增加更多的路由规则和过滤器。

总结

终于接触了微服务架构。初步了解了Spring Cloud的框架。总之就是进一步的分布,进一步的解耦。