Skip to content

Spring Cloud

基础概念

什么是Spring Cloud?

答案: Spring Cloud是一套基于Spring Boot的微服务开发工具集,提供了服务注册发现、配置中心、消息总线、负载均衡、断路器、数据监控等功能。

核心组件

  • Eureka/Nacos:服务注册与发现
  • Ribbon/LoadBalancer:客户端负载均衡
  • Feign/OpenFeign:声明式HTTP客户端
  • Hystrix/Sentinel:熔断降级
  • Gateway:API网关
  • Config:配置中心
  • Sleuth + Zipkin:链路追踪

微服务架构的优缺点?

答案:

优点

  • 服务独立部署,灵活性高
  • 技术栈多样化
  • 故障隔离,不会全局崩溃
  • 易于扩展和维护

缺点

  • 系统复杂度增加
  • 分布式事务难处理
  • 服务间通信开销
  • 运维成本高

服务注册与发现

Eureka的工作原理?

答案:

架构

服务提供者 → 注册 → Eureka Server
服务消费者 → 拉取服务列表 → Eureka Server
服务消费者 → 调用 → 服务提供者

核心机制

1. 服务注册

java
@SpringBootApplication
@EnableEurekaClient
public class ServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceProviderApplication.class, args);
    }
}
yaml
# application.yml
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 30  # 心跳间隔
    lease-expiration-duration-in-seconds: 90  # 过期时间

2. 服务发现

java
@Autowired
private DiscoveryClient discoveryClient;

public List<ServiceInstance> getInstances(String serviceId) {
    return discoveryClient.getInstances(serviceId);
}

3. 心跳机制

  • 服务每30秒发送一次心跳
  • 90秒未收到心跳,Eureka剔除该实例
  • 服务消费者每30秒拉取一次服务列表

Eureka的自我保护机制?

答案:

触发条件: 15分钟内,心跳失败比例低于85%,Eureka进入自我保护模式。

保护措施

  • 不再剔除任何服务实例
  • 仍然接受新服务注册
  • 仍然提供服务查询

为什么需要? 防止网络分区导致大量服务被误剔除。

yaml
# 关闭自我保护(生产环境不推荐)
eureka:
  server:
    enable-self-preservation: false

Nacos和Eureka的区别?

答案:

特性EurekaNacos
CAPAP(可用性优先)CP+AP可切换
健康检查客户端心跳服务端主动探测
配置中心不支持支持
控制台简单功能丰富
社区Netflix停止维护阿里维护

Nacos使用

java
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {
}
yaml
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

负载均衡

Ribbon的负载均衡策略?

答案:

策略说明
RoundRobinRule轮询(默认)
RandomRule随机
RetryRule重试
WeightedResponseTimeRule响应时间加权
BestAvailableRule最小并发
AvailabilityFilteringRule可用性过滤

配置方式

1. 全局配置

java
@Configuration
public class RibbonConfig {
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();  // 随机策略
    }
}

2. 指定服务配置

yaml
service-provider:  # 服务名
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

LoadBalancer和Ribbon的区别?

答案:

Spring Cloud LoadBalancer是Ribbon的替代品(Ribbon已停止维护)。

使用LoadBalancer

java
@Configuration
@LoadBalancerClient(name = "service-provider", configuration = LoadBalancerConfig.class)
public class LoadBalancerConfig {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(
            loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
            name);
    }
}

服务调用

Feign的使用和原理?

**答案:gn是声明式HTTP客户端,简化服务间调用。

使用示例

java
// 1. 启用Feign
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {
}

// 2. 定义Feign接口
@FeignClient(name = "service-provider", fallback = UserServiceFallback.class)
public interface UserService {
    @GetMapping("/user/{id}")
    User getUser(@PathVariable("id") Long id);

    @PostMapping("/user")
    User createUser(@RequestBody User user);
}

// 3. 使用
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }
}

工作原理

1. @FeignClient注解被扫描
2. 为接口生成动态代理
3. 方法调用时,解析注解生成HTTP请求
4. 通过Ribbon负载均衡选择服务实例
5. 发送HTTP请求并解析响应

配置

yaml
feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
  compression:
    request:
      enabled: true
    response:
      enabled: true

Feign的超时和重试?

答案:

超时配置

yaml
feign:
  client:
    config:
      service-provider:  # 指定服务
        connectTimeout: 2000  # 连接超时
        readTimeout: 5000     # 读取超时

重试配置

java
@Configuration
public class FeignConfig {
    @Bean
    public Retryer feignRetryer() {
        // 最大重试3次,初始间隔100ms,最大间隔1s
        return new Retryer.Default(100, 1000, 3);
    }
}

熔断降级

Hystrix的工作原理?

答案:

Hystrix通过断路器模式实现服务熔断和降级。

三种状态

关闭(Closed) → 打开(Open) → 半开(Half-Open)

状态转换

  1. 关闭→打开:错误率超过阈值(默认50%)
  2. 打开→半开:等待一段时间(默认5秒)
  3. 半开→关闭:请求成功
  4. 半开→打开:请求失败

使用示例

java
@Service
public class UserService {

    @HystrixCommand(
        fallbackMethod = "getUserFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
        }
    )
    public User getUser(Long id) {
        // 调用远程服务
        return restTemplate.getForObject("http://service-provider/user/" + id, User.class);
    }

    // 降级方法
    public User getUserFallback(Long id) {
        return new User(id, "默认用户", "服务降级");
    }
}

Sentinel和Hystrix的区别?

答案:

特性HystrixSentinel
隔离策略线程池/信号量信号量
熔断降级基于异常比例支持多种策略
实时监控
控制台简单功能丰富
规则配置代码/配置文件动态配置
维护状态停止维护活跃维护

Sentinel使用

java
@RestController
public class UserController {

    @GetMapping("/user/{id}")
    @SentinelResource(
        value = "getUser",
        blockHandler = "handleBlock",
        fallback = "handleFallback"
    )
    public User getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }

    // 限流/熔断处理
    public User handleBlock(Long id, BlockException ex) {
        return new User(id, "限流", "系统繁忙");
    }

    // 异常降级
    public User handleFallback(Long id, Throwable ex) {
        return new User(id, "降级", "服务异常");
    }
}

流控规则

java
FlowRule rule = new FlowRule();
rule.setResource("getUser");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(10);  // QPS阈值
FlowRuleManager.loadRules(Collections.singletonList(rule));

API网关

Gateway的核心概念?

答案:

三大核心

  • Route(路由):网关的基本单元
  • Predicate(断言):匹配HTTP请求
  • Filter(过滤器):修改请求和响应

工作流程

客户端请求 → Gateway

Predicate匹配路由

Pre Filter(前置过滤)

转发到目标服务

Post Filter(后置过滤)

返回响应

配置示例

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://service-provider  # lb表示负载均衡
          predicates:
            - Path=/user/**
            - Method=GET,POST
          filters:
            - StripPrefix=1  # 去掉路径前缀
            - AddRequestHeader=X-Request-Source, Gateway

Gateway的常用过滤器?

答案:

内置过滤器

yaml
filters:
  - AddRequestHeader=X-Request-Id, 123
  - AddResponseHeader=X-Response-Time, 100ms
  - StripPrefix=1  # 去掉1层路径前缀
  - PrefixPath=/api  # 添加路径前缀
  - RewritePath=/old/(?<segment>.*), /new/${segment}
  - SetStatus=401
  - Retry=3  # 重试3次

自定义全局过滤器

java
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");

        if (token == null || !validateToken(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -100;  // 优先级
    }
}

配置中心

Config的工作原理?

答案:

架构

Git仓库 ← Config Server ← Config Client

Config Server配置

yaml
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/xxx/config-repo
          search-paths: config
          username: xxx
          password: xxx

Config Client配置

yaml
# bootstrap.yml
spring:
  cloud:
    config:
      uri: http://localhost:8888
      name: application
      profile: dev
      label: master

配置刷新

java
@RestController
@RefreshScope  # 支持动态刷新
public class ConfigController {

    @Value("${config.value}")
    private String configValue;

    @GetMapping("/config")
    public String getConfig() {
        return configValue;
    }
}

手动刷新

bash
curl -X POST http://localhost:8080/actuator/refresh

Nacos Config的优势?

答案:

相比Spring Cloud Config,Nacos Config提供:

  • 动态配置推送(无需手动刷新)
  • 配置版本管理
  • 灰度发布
  • 可视化管理界面
yaml
spring:
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml
        namespace: dev
        group: DEFAULT_GROUP
java
@RestController
@RefreshScope
public class ConfigController {

    @NacosValue(value = "${config.value}", autoRefreshed = true)
    private String configValue;
}

练习题

  1. 如何实现服务的优雅下线?
  2. 如何解决Feign首次调用超时问题?
  3. Gateway如何实现限流?
  4. 如何实现配置的灰度发布?
  5. 微服务如何实现统一认证鉴权?

Released under the MIT License.