从天气项目看Spring Cloud微服务治理---xingkeit.top/7724/
微服务治理是架构师面试的深水区,也是项目从“能跑”到“健壮”的分水岭。很多开发者对“熔断降级”、“服务雪崩”、“流量染色”等概念耳熟能详,但一上手写代码就发懵。
理论总是抽象的,但场景是具体的。本文将通过构建一个 “智能天气查询系统” ,带你深入实战 Spring Cloud Alibaba 的三大治理利器:Nacos(配置中心与注册中心) 、Sentinel(熔断与限流) 、以及 Feign(服务调用与容错) 。
一、 项目背景与架构设计
假设我们需要开发一个面向全国用户的天气 App,包含两个核心微服务:
- 城市服务:提供城市 ID、名称查询,数据更新不频繁。
- 天气服务:调用第三方 API 获取实时天气,高并发,依赖网络 IO。
治理痛点预演:
- 配置管理:第三方天气 API Key 经常变,如何做到不重启服务就热更新?
- 服务雪崩:第三方天气接口挂了或者响应超时,是否会拖垮整个系统?
- 流量突增:突发热点城市(如举办奥运会)查询量激增,如何保护服务不被打死?
二、 动态配置治理:Nacos 配置中心实战
传统方式是将 Key 写在 application.yml 里,改一次 Key 需要重启所有天气服务实例。利用 Nacos Config,我们可以实现配置的热更新。
1. 引入依赖
2. Bootstrap 配置
yaml
复制
# bootstrap.yml (优先级高于 application.yml)
spring:
application:
name: weather-service
cloud:
nacos:
server-addr: 127.0.0.1:8848
config:
file-extension: yaml
shared-configs:
- data-id: common-config.yaml # 公共配置,如数据库连接
refresh: true
3. 动态刷新代码
在 Nacos 控制台新建 weather-service.yaml,内容如下:
yaml
复制
weather:
api:
key: "old_api_key_123" # 模拟第三方 Key
url: "http://api.weather.com/v1"
代码中如何实现热更新?使用 @RefreshScope。
java
复制
@RestController
@RefreshScope // <--- 核心注解:标记该 Bean 的配置可以在运行时刷新
@RequestMapping("/weather")
public class WeatherController {
@Value("${weather.api.key}")
private String apiKey; // 这个字段会被 Nacos 动态修改
@Value("${weather.api.url}")
private String apiUrl;
@GetMapping("/now")
public String getWeather(String city) {
// 模拟调用第三方 API
System.out.println("当前使用的 Key: " + apiKey);
return String.format("城市: %s, 天气: 晴, 使用Key: %s", city, apiKey);
}
}
实战效果:当你在 Nacos 控制台修改 weather.api.key 并发布后,控制台会收到刷新事件,apiKey 变量立即更新,无需重启服务!
三、 稳定性治理:Sentinel 熔断与限流
天气服务依赖外部网络,极其不稳定。如果外部接口响应超过 1 秒,我们希望快速失败,告诉用户“稍后再试”,而不是让线程一直卡死。
1. 引入依赖
2. 配置 Sentinel 控制台
yaml
复制
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel 控制台地址
port: 8719 # 微服务与控制台通讯端口
3. 定义资源与降级逻辑
Sentinel 提供了 @SentinelResource 注解来精细化控制资源。
java
复制
@Service
public class WeatherService {
// 模拟第三方天气 API 调用
public String callThirdPartyApi(String city) {
// 模拟偶尔的慢响应
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(200, 1500));
} catch (InterruptedException e) {
e.printStackTrace();
}
return city + "多云";
}
/**
* 查询天气的主入口
* @SentinelResource:
* value: 资源名称,用于在控制台展示
* blockHandler: 触发限流或规则失败时的本地降级方法
* fallback: 调用本身抛出异常(如 RpcException)时的降级方法
*/
@SentinelResource(value = "getWeatherDetail",
blockHandler = "handleBlock",
fallback = "handleFallback")
public String getWeatherDetail(String city) {
// 这里可能抛出异常,或者响应很慢触发 Sentinel 的熔断规则
if (city.equals("ErrorCity")) {
throw new RuntimeException("模拟第三方 API 报错");
}
return callThirdPartyApi(city);
}
// 降级方法:签名必须和原方法一致,最后多加一个 BlockException 参数
public String handleBlock(String city, BlockException ex) {
return "系统繁忙(触发限流/降级),请稍后再试:" + city;
}
// 异常Fallback
public String handleFallback(String city, Throwable ex) {
return "服务异常(内部报错),正在疯狂修复中:" + city;
}
}
实战规则配置(在 Sentinel 控制台操作) :
- 流控规则:QPS 阈值设为 2。一秒内超过 2 次请求,直接返回
handleBlock的内容。 - 熔断降级:选择慢调用比例策略。最大 RT 设为 500ms,比例阈值 0.5,最小请求数 5。意味着:如果 5 个请求里有 50% 响应超过 0.5 秒,熔断器打开,后续请求直接拒绝,进入“半开/开启”状态保护服务。
四、 调用链治理:OpenFeign 整合 Sentinel
微服务之间会有调用。假设 “推荐服务” 需要调用 “天气服务” 。如果“天气服务”挂了,“推荐服务”不能跟着挂。
1. Feign Client 开启 Sentinel 支持
yaml
复制
feign:
sentinel:
enabled: true # 开启 Feign 对 Sentinel 的支持
2. 定义 Feign 接口与降级类
java
复制
// Feign 接口
@FeignClient(value = "weather-service", fallback = WeatherFeignFallback.class)
public interface WeatherFeignClient {
@GetMapping("/weather/now")
String getWeather(@RequestParam("city") String city);
}
// 降级实现类:当 weather-service 不可用时,会调用此类中的方法
@Component
public class WeatherFeignFallback implements WeatherFeignClient {
@Override
public String getWeather(String city) {
// 返回兜底数据,保证主流程不断
return "【默认天气】数据加载中,暂无法获取" + city + "的实时信息";
}
}
3. 业务调用
java
复制
@Service
public class RecommendService {
@Autowired
private WeatherFeignClient weatherFeignClient;
public String getTravelRecommend(String city) {
// 即使天气服务挂了,这里也能拿到兜底值,不影响推荐逻辑的后续执行
String weather = weatherFeignClient.getWeather(city);
return "今日推荐游览" + city + "," + weather;
}
}
五、 总结:微服务治理的思维跃迁
通过这个天气项目,我们将微服务治理从抽象概念落实到了代码层面:
- 配置治理:利用 Nacos
@RefreshScope实现了配置的热更新,解决了“改配置重启服务”的痛点。 - 稳定性治理:利用 Sentinel
@SentinelResource实现了资源的精细化控制,针对慢调用和异常进行自动熔断,防止服务雪崩。 - 容错治理:利用 Feign 的
fallback机制,实现了服务调用的优雅降级,保证了系统的最终可用性。
微服务治理的核心不在于引入多少组件,而在于如何通过规则和代码,让系统在不可靠的网络环境中,提供尽可能可靠的服务。这就是架构师的价值所在。