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: falseNacos和Eureka的区别?
答案:
| 特性 | Eureka | Nacos |
|---|---|---|
| CAP | AP(可用性优先) | 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.RandomRuleLoadBalancer和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: trueFeign的超时和重试?
答案:
超时配置:
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)状态转换:
- 关闭→打开:错误率超过阈值(默认50%)
- 打开→半开:等待一段时间(默认5秒)
- 半开→关闭:请求成功
- 半开→打开:请求失败
使用示例:
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的区别?
答案:
| 特性 | Hystrix | Sentinel |
|---|---|---|
| 隔离策略 | 线程池/信号量 | 信号量 |
| 熔断降级 | 基于异常比例 | 支持多种策略 |
| 实时监控 | 弱 | 强 |
| 控制台 | 简单 | 功能丰富 |
| 规则配置 | 代码/配置文件 | 动态配置 |
| 维护状态 | 停止维护 | 活跃维护 |
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, GatewayGateway的常用过滤器?
答案:
内置过滤器:
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 ClientConfig Server配置:
yaml
spring:
cloud:
config:
server:
git:
uri: https://github.com/xxx/config-repo
search-paths: config
username: xxx
password: xxxConfig 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/refreshNacos Config的优势?
答案:
相比Spring Cloud Config,Nacos Config提供:
- 动态配置推送(无需手动刷新)
- 配置版本管理
- 灰度发布
- 可视化管理界面
yaml
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yaml
namespace: dev
group: DEFAULT_GROUPjava
@RestController
@RefreshScope
public class ConfigController {
@NacosValue(value = "${config.value}", autoRefreshed = true)
private String configValue;
}练习题
- 如何实现服务的优雅下线?
- 如何解决Feign首次调用超时问题?
- Gateway如何实现限流?
- 如何实现配置的灰度发布?
- 微服务如何实现统一认证鉴权?