第二篇:注册中心篇 — Nacos 与 Eureka 服务注册发现

目标 :掌握服务注册与发现的原理和实践
学习时长:1~2 周


目录

  1. 服务注册发现原理
  2. [Eureka 详解](#Eureka 详解)
  3. [Eureka Server 搭建](#Eureka Server 搭建)
  4. [Eureka Client 注册](#Eureka Client 注册)
  5. [Nacos 详解](#Nacos 详解)
  6. [Nacos 集成](#Nacos 集成)
  7. [Eureka vs Nacos 对比](#Eureka vs Nacos 对比)
  8. 服务实例元数据
  9. 健康检查机制
  10. 负载均衡策略
  11. 面试高频题

1. 服务注册发现原理

复制代码
服务提供者启动
    ↓
向注册中心注册(服务名、IP、端口、健康状态)
    ↓
定期发送心跳(默认30秒)
    ↓
注册中心维护服务列表(健康检查,超时剔除)

服务消费者:
    ↓
从注册中心拉取服务列表(本地缓存)
    ↓
根据负载均衡策略选择实例
    ↓
发起 HTTP 调用

核心问题:为什么需要注册中心?

复制代码
❌ 硬编码方式(无注册中心):
   userService.call("http://192.168.1.100:9001/api/users")
   → 服务器 IP 变化或增减实例时,所有调用方都需要修改代码!

✅ 注册中心方式:
   userFeignClient.getUserById(id)  // 通过服务名调用
   → 注册中心动态维护实例列表,消费者无感知 IP 变化

2. Eureka 详解

核心架构

复制代码
┌─────────────────────────────────────┐
│           Eureka Server              │  ← 注册中心
│  Registry: {                         │
│    "user-service": [                 │
│      {ip:"192.168.1.1", port:9001}  │
│      {ip:"192.168.1.2", port:9001}  │  ← 两个实例(水平扩展)
│    ]                                 │
│  }                                   │
└─────────────────────────────────────┘
         ↑ 注册/心跳         ↓ 拉取列表
┌─────────────┐    ┌─────────────────────┐
│ user-service │    │    order-service     │
│ (提供者)     │    │  (消费者,Feign调用) │
└─────────────┘    └─────────────────────┘

自我保护机制

Eureka Server 收到的心跳数低于阈值(默认85%)时,进入自我保护模式

  • 不会剔除任何实例
  • 防止网络分区时误剔除健康实例
  • 生产环境应开启 ,开发环境建议关闭(快速感知实例下线)
yaml 复制代码
eureka:
  server:
    enable-self-preservation: false   # 开发环境关闭
    eviction-interval-timer-in-ms: 5000  # 剔除间隔缩短至5秒

AP 还是 CP?

Eureka 是 AP 系统

  • 优先保证可用性(即使注册信息不是最新的)
  • 牺牲强一致性(不同 Server 节点间的数据可能短暂不一致)
  • 适合:对最终一致性容忍,追求高可用

3. Eureka Server 搭建

xml 复制代码
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
java 复制代码
@SpringBootApplication
@EnableEurekaServer  // 核心注解,开启 Eureka 服务端
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
yaml 复制代码
server:
  port: 8761
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false  # 自身不注册
    fetch-registry: false        # 自身不拉取
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

Eureka Server 高可用(Peer to Peer)

yaml 复制代码
# eureka-server-1 (端口 8761)
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8762/eureka/  # 指向 Server-2

# eureka-server-2 (端口 8762)
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  # 指向 Server-1

# 客户端同时连接两个(任一宕机不影响)
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/

4. Eureka Client 注册

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Spring Cloud 2020 以后 :不再需要 @EnableDiscoveryClient@EnableEurekaClient,引入依赖后自动开启

yaml 复制代码
spring:
  application:
    name: user-service      # 必须设置:注册到 Eureka 的服务名

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    registry-fetch-interval-seconds: 5  # 拉取注册表间隔(默认30秒)
  instance:
    prefer-ip-address: true             # 注册 IP 而非主机名
    lease-renewal-interval-in-seconds: 5  # 心跳间隔(默认30秒)
    lease-expiration-duration-in-seconds: 15  # 超时剔除(默认90秒)
    instance-id: ${spring.application.name}:${server.port}  # 实例唯一ID

5. Nacos 详解

Nacos(Naming and Configuration Service)是阿里巴巴开源的注册中心 + 配置中心一体化组件。

Nacos 核心特性

特性 说明
服务注册/发现 支持 HTTP、DNS、gRPC
配置管理 动态配置,支持热更新
健康检查 主动(TCP/HTTP)+ 被动(心跳)
命名空间 隔离不同环境(dev/test/prod)
集群分组 同一服务按地域/机房分组
权重配置 控制流量比例(灰度发布)
保护阈值 类似 Eureka 自我保护

Nacos 健康检查模式

复制代码
临时实例(ephemeral=true,默认):
  - 客户端主动发心跳(15秒),5秒无心跳标记不健康,30秒剔除
  - 适合:微服务实例

永久实例(ephemeral=false):
  - Server 主动探测健康状态(TCP/HTTP)
  - 即使实例不健康,不会自动剔除(需手动删除)
  - 适合:物理服务器、数据库等基础设施

Nacos 支持 CP + AP 切换

bash 复制代码
# 切换为 CP(强一致):适合需要强一致的永久实例
curl -X PUT 'http://nacos:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'

# 切换为 AP(高可用):适合临时实例(默认)
curl -X PUT 'http://nacos:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=AP'

6. Nacos 集成

启动 Nacos Server

bash 复制代码
# 单机模式(开发/测试)
docker run -d -p 8848:8848 -p 9848:9848 \
  -e MODE=standalone \
  nacos/nacos-server:v2.3.0

# 访问控制台:http://localhost:8848/nacos
# 默认账号密码:nacos/nacos

引入依赖

xml 复制代码
<!-- 使用 Spring Cloud Alibaba BOM -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

服务配置

yaml 复制代码
spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848    # Nacos 地址
        namespace: dev-namespace-id   # 命名空间(环境隔离)
        group: DEFAULT_GROUP          # 服务分组
        cluster-name: SH              # 集群名(同城优先调用)
        # 权重(0~1,影响负载均衡流量比例)
        weight: 1.0
        # 元数据(可被其他服务读取)
        metadata:
          version: v1.0
          region: shanghai

7. Eureka vs Nacos 对比

维度 Eureka Nacos
语言 Java Java
CAP AP AP(临时)/ CP(永久)
配置中心 ❌(需单独部署 Config Server) ✅ 内置
控制台 简陋 功能丰富
主动健康检查 ❌ 仅被动心跳 ✅ TCP/HTTP/MySQL
命名空间
权重
社区活跃度 较低(Netflix 已停维护) 高(阿里持续维护)
国内使用 一般 主流

推荐 :新项目使用 Nacos;已有 Eureka 项目切换成本较低(配置相似)。


8. 服务实例元数据

yaml 复制代码
# 在 eureka.instance.metadata-map 或 nacos.discovery.metadata 中配置
eureka:
  instance:
    metadata-map:
      version: "v1.2"
      zone: "shanghai"
      weight: "100"
java 复制代码
// 读取其他服务的元数据
@Autowired
private DiscoveryClient discoveryClient;

public void printMetadata() {
    List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
    instances.forEach(inst ->
        System.out.println("元数据: " + inst.getMetadata()));
}

9. 健康检查机制

Spring Boot Actuator 集成

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yaml 复制代码
management:
  endpoints:
    web:
      exposure:
        include: health, info
  endpoint:
    health:
      show-details: always

自定义健康检查

java 复制代码
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
    @Override
    public Health health() {
        try {
            // 检查数据库连接
            if (canConnectToDatabase()) {
                return Health.up()
                    .withDetail("database", "连接正常")
                    .withDetail("activeConnections", getActiveConnections())
                    .build();
            } else {
                return Health.down().withDetail("error", "数据库连接失败").build();
            }
        } catch (Exception e) {
            return Health.down(e).build();
        }
    }
}

10. 负载均衡策略

Spring Cloud LoadBalancer(替代 Ribbon)默认提供两种策略:

java 复制代码
// 1. 轮询(Round Robin,默认)
// 请求按顺序轮流发给每个实例

// 2. 随机(Random)
@Bean
public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
        LoadBalancerClientFactory factory,
        @Value("${spring.application.name}") String name) {
    return new RandomLoadBalancer(
            factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}

// 3. 自定义策略(权重)
@Bean
public ReactorLoadBalancer<ServiceInstance> weightedLoadBalancer(...) {
    // 根据元数据中的 weight 字段分配流量
}

11. 面试高频题

Q1:Eureka 的自我保护机制是什么?

当 Eureka Server 接收到的心跳数低于期望值的 85% 时,进入自我保护模式,停止剔除实例。这是为了防止网络故障导致大量实例被误剔除。生产应开启,开发可关闭以快速感知服务下线。

Q2:Eureka、Zookeeper、Nacos 的 CAP 模型分别是什么?

Eureka:AP(可用性优先,不保证强一致);Zookeeper:CP(一致性优先,Leader 选举期间不可用);Nacos:支持 AP + CP 切换(临时实例 AP,永久实例 CP)。

Q3:服务注册到 Eureka 后,消费者如何发现它?

消费者启动时向 Eureka Server 拉取服务列表并本地缓存(默认30秒刷新)。Feign + LoadBalancer 在调用时从本地缓存中根据负载均衡策略选择实例。

Q4:Nacos 和 Eureka 的心跳机制有什么区别?

Eureka 仅支持客户端主动心跳(被动检测);Nacos 除客户端心跳外,还支持 Server 主动探测(TCP/HTTP),且对临时实例和永久实例有不同的处理策略。

Q5:如何实现服务的优雅下线?

①调用 /actuator/shutdown 端点;②发送 DELETE 请求到 Eureka 注销;③在 Kubernetes 中通过 PreStop Hook 延迟关闭;④Nacos 支持在控制台手动下线。


上一篇:01_基础篇 | 下一篇:03_通信篇


12. 专家级:Nacos 注册中心生产运维

知识点 1:服务注册失败排查清单

text 复制代码
症状:服务启动后 Nacos 控制台看不到实例

排查步骤:
  1. 检查 Nacos 地址是否正确(server-addr 格式:host:port,不加 http://)
  2. 检查网络连通性:curl http://nacos-host:8848/nacos/actuator/health
  3. 检查 Nacos 2.x 的 gRPC 端口 9848 是否开放(防火墙/安全组)
  4. 检查 namespace ID 是否使用了 UUID 格式(不是 namespace 名称)
  5. 检查日志:nacos.core.auth.enabled=true 时需要配置 username/password
  6. 开启 Nacos 客户端日志:logging.level.com.alibaba.nacos=DEBUG

知识点 2:Nacos 服务实例保护阈值

yaml 复制代码
# Nacos 控制台可设置服务保护阈值(0~1)
# 当健康实例比例低于此值时,即使实例不健康也对外提供服务
# 目的:防止过多不健康实例同时被摘除,导致健康实例压力爆炸
# 建议值:0.8(80%健康实例才正常摘除不健康的)

spring:
  cloud:
    nacos:
      discovery:
        # 在代码中注册时设置(或在控制台服务详情中设置)
        protected-threshold: 0.0  # 默认0,即不保护

与 Eureka 自我保护的区别

  • Eureka 自我保护是注册中心级别(整个 Eureka Server 停止剔除)
  • Nacos 保护阈值是服务级别(只针对某一个服务)

知识点 3:同城双活/异地多活部署

text 复制代码
单机房架构(有单点风险):
  上海 Nacos 集群 ← 所有服务

同城双机房(推荐):
  上海A机房:Nacos-1, Nacos-2 ← 上海A的服务
  上海B机房:Nacos-3           ← 上海B的服务
  三节点组成同一 Nacos 集群,Raft 保证一致性

跨城部署注意事项:
  - Raft 需要节点间低延迟通信,跨城延迟高不适合同一集群
  - 推荐:每个城市独立 Nacos 集群,通过服务同步插件同步数据
  - 或使用 Nacos 企业版的异地多活特性

13. 专家级:Spring Cloud LoadBalancer 源码级理解

知识点:本地缓存的刷新机制

Spring Cloud LoadBalancer 维护一份本地服务实例缓存,避免每次调用都查询注册中心。

text 复制代码
缓存刷新流程:
  1. 首次调用某服务时,从 Nacos/Eureka 拉取实例列表 → 写入本地缓存
  2. 后续调用直接读缓存(高性能)
  3. 缓存默认30秒TTL,到期后重新从注册中心拉取

配置调整:
yaml 复制代码
spring:
  cloud:
    loadbalancer:
      cache:
        enabled: true
        ttl: 30s           # 缓存TTL(默认35秒)
        capacity: 256      # 最大缓存服务数

生产注意事项

text 复制代码
问题:新实例注册后,最多30秒后才被 LoadBalancer 感知(缓存延迟)
      下线实例最多30秒内仍可能收到请求(导致调用失败)

缓解方案:
  1. 缩短缓存TTL(如10秒),但增加注册中心压力
  2. Nacos 推送 + 缓存失效联动(Nacos 2.x 通过 gRPC 推送变更)
  3. 结合 Feign Retry(调用失败时自动重试另一实例)

Feign 重试配置:
yaml 复制代码
spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            retryer: feign.Retryer.Default  # 默认重试(5次,最大1秒间隔)

14. Nacos 集群生产部署

知识点 1:Nacos 集群架构原理

text 复制代码
Nacos 集群(至少3节点,Raft 协议要求奇数):

                    ┌─────────────┐
                    │   Nginx     │  ← 负载均衡(VIP)
                    │ :80 / :443  │
                    └──────┬──────┘
              ┌────────────┼────────────┐
              ▼            ▼            ▼
     ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
     │  nacos-1     │ │  nacos-2     │ │  nacos-3     │
     │  :8848       │ │  :8848       │ │  :8848       │
     │  :9848(gRPC) │ │  :9848(gRPC) │ │  :9848(gRPC) │
     └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
            └────────────────┼────────────────┘
                             ▼
                    ┌──────────────┐
                    │    MySQL     │  ← 共享数据存储
                    │  nacos_db   │
                    └──────────────┘

Raft 协议保证:
  - 3节点最多容忍1个节点宕机
  - 5节点最多容忍2个节点宕机
  - Leader 处理写请求,Follower 可以处理读请求

知识点 2:Nacos 集群配置文件

properties 复制代码
# conf/cluster.conf(三台机器的 IP 和端口)
192.168.1.10:8848
192.168.1.11:8848
192.168.1.12:8848
properties 复制代码
# conf/application.properties(MySQL 持久化)
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://mysql:3306/nacos_config?characterEncoding=utf8&serverTimezone=UTC
db.user.0=nacos
db.password.0=nacos123

# 开启认证(生产必须!)
nacos.core.auth.enabled=true
nacos.core.auth.plugin.nacos.token.secret.key=VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkxMjM0NTY=
# 注意:secret.key 必须 Base64 编码,且原文长度 >= 32 字符
bash 复制代码
# Docker Compose 集群示例
version: '3.8'
services:
  nacos-1:
    image: nacos/nacos-server:v2.3.0
    environment:
      - NACOS_SERVERS=nacos-1:8848 nacos-2:8848 nacos-3:8848
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=mysql
      - MYSQL_SERVICE_DB_NAME=nacos_config
      - MYSQL_SERVICE_USER=nacos
      - MYSQL_SERVICE_PASSWORD=nacos123
      - NACOS_AUTH_ENABLE=true
    volumes:
      - ./logs/nacos-1:/home/nacos/logs

  nacos-2:
    image: nacos/nacos-server:v2.3.0
    environment:
      - NACOS_SERVERS=nacos-1:8848 nacos-2:8848 nacos-3:8848
      # ... 同 nacos-1

  nacos-3:
    image: nacos/nacos-server:v2.3.0
    environment:
      - NACOS_SERVERS=nacos-1:8848 nacos-2:8848 nacos-3:8848
      # ... 同 nacos-1

15. 同区域优先路由(Zone Affinity)

知识点 1:为什么需要同区域路由

text 复制代码
问题:多机房部署时,跨机房调用增加网络延迟
  上海A机房 user-service → 深圳B机房 order-service(高延迟)
  上海A机房 user-service → 上海A机房 order-service(低延迟)

解决:配置 zone,优先选择同 zone 的实例
  服务注册时标注自己所在的 zone
  LoadBalancer 优先选择与自己 zone 相同的实例
  同 zone 无实例时,再跨 zone 调用(降级)

知识点 2:Zone Affinity 完整配置

yaml 复制代码
# 每个服务配置自己的 zone(在对应机房的配置文件中)
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: shanghai-a   # Nacos 集群分组
        metadata:
          zone: shanghai-a         # 自定义 zone 标签(LoadBalancer 读取)

    loadbalancer:
      zone: ${spring.cloud.nacos.discovery.metadata.zone}  # 告诉 LB 自己的 zone
      configurations: zone-preference  # 启用 zone 感知路由
java 复制代码
// 自定义 Zone 感知负载均衡器(Spring Cloud LB 内置支持,也可自定义)
@Configuration
@LoadBalancerClients(defaultConfiguration = ZoneAwareConfig.class)
public class GlobalLoadBalancerConfig {}

@Configuration
public class ZoneAwareConfig {

    @Bean
    public ServiceInstanceListSupplier zonePreferenceServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
            .withDiscoveryClient()
            .withZonePreference()  // 启用 zone 优先
            .withHealthChecks()
            .build(context);
    }
}

16. 服务优雅下线

知识点:避免下线时请求失败

text 复制代码
问题:直接 kill 进程时
  1. 注册中心尚未感知实例下线(有缓存延迟)
  2. 正在处理的请求被强制中断
  → 客户端收到连接错误

正确的下线流程:
  1. 先从注册中心注销(主动下线)
  2. 等待 LoadBalancer 缓存刷新(等几秒)
  3. 再等待进行中的请求处理完成
  4. 最后停止进程
yaml 复制代码
# 开启优雅停机
server:
  shutdown: graceful
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s  # 最多等 30 秒
bash 复制代码
# Kubernetes 中配置 preStop Hook
lifecycle:
  preStop:
    exec:
      command:
        - /bin/sh
        - -c
        - |
          # 1. 调用 actuator 主动注销
          curl -X POST http://localhost:8080/actuator/service-registry?status=OUT_OF_SERVICE
          # 2. 等待 LB 缓存刷新
          sleep 10
          # 3. Spring Boot 优雅停机会等待进行中的请求完成

# 同时配置 terminationGracePeriodSeconds > preStop 等待时间 + 应用关闭时间
spec:
  terminationGracePeriodSeconds: 60

17. 自定义权重负载均衡器(完整实现)

知识点:基于 Nacos 权重的负载均衡

java 复制代码
/**
 * 基于 Nacos 元数据 weight 字段的加权随机负载均衡器
 * 实例 weight 越高,被选中的概率越大
 */
public class NacosWeightedLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private static final Log log = LogFactory.getLog(NacosWeightedLoadBalancer.class);

    private final String serviceId;
    private final ObjectProvider<ServiceInstanceListSupplier> supplierProvider;

    public NacosWeightedLoadBalancer(String serviceId,
            ObjectProvider<ServiceInstanceListSupplier> supplierProvider) {
        this.serviceId = serviceId;
        this.supplierProvider = supplierProvider;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = supplierProvider
            .getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map(this::selectByWeight);
    }

    private Response<ServiceInstance> selectByWeight(List<ServiceInstance> instances) {
        if (instances.isEmpty()) return new EmptyResponse();

        // 计算总权重
        int totalWeight = instances.stream()
            .mapToInt(i -> {
                String w = i.getMetadata().getOrDefault("weight", "1");
                return Math.max(1, Integer.parseInt(w));
            })
            .sum();

        // 加权随机
        int random = ThreadLocalRandom.current().nextInt(totalWeight);
        int cumulative = 0;
        for (ServiceInstance instance : instances) {
            int weight = Integer.parseInt(
                instance.getMetadata().getOrDefault("weight", "1"));
            cumulative += weight;
            if (random < cumulative) {
                log.debug("选中实例: " + instance.getHost() + ":" + instance.getPort()
                    + " (weight=" + weight + ")");
                return new DefaultResponse(instance);
            }
        }
        return new DefaultResponse(instances.get(0)); // 兜底
    }
}

// 注册为默认负载均衡器
@Configuration
@LoadBalancerClients(defaultConfiguration = WeightedLBConfig.class)
public class WeightedLBAutoConfig {}

@Configuration
public class WeightedLBConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> nacosWeightedLoadBalancer(
            LoadBalancerClientFactory factory,
            Environment env) {
        String name = env.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new NacosWeightedLoadBalancer(name,
            factory.getLazyProvider(name, ServiceInstanceListSupplier.class));
    }
}

Nacos 控制台设置实例权重(不修改代码,直接在控制台调整):

  • 灰度:新版本实例权重设为 5,旧版本 95(流量 5:95)
  • 扩容:新加入的实例权重从 10 慢慢调到 100(预热)
相关推荐
直奔標竿2 小时前
SpringAI + RAG + MCP + Agent 零基础全栈实战(完结篇)| 27课完整汇总,Java开发者AI转型必看
java·开发语言·人工智能·spring boot·后端·spring
逍遥德2 小时前
SpringBoot数据库连接池HikariCP,Druid,Tomcat JDBC,DBCP2,c3p0配置使用
数据库·spring boot·tomcat
学术阿凡提2 小时前
Spring Boot 集成 Fastjson2 完整教程:从入门到避坑
spring boot·安全·json
007张三丰3 小时前
系统架构设计师范文4:论微服务架构及其应用
微服务·云原生·架构·软考·系统架构设计师
AI攻城狮3 小时前
Human-in-the-Loop 是生产环境不可妥协的环节
云原生
也许明天y4 小时前
LangChain4j + Spring Boot 多智能体协调架构原理深度解析
spring boot·后端·agent
长安链开源社区4 小时前
动手开发 | 如何通过k8s部署长安链
云原生·容器·kubernetes·区块链
Dontla5 小时前
kubectl命令介绍(K8s命令行客户端)
云原生·容器·kubernetes
阿丰资源5 小时前
基于Spring Boot的新闻推荐系统(源码+数据库+文档)
数据库·spring boot·后端