Spring Cloud从零开始:微服务入门指南
上周五晚上十点半,我还在公司改婚庆系统的支付回调接口。项目经理在群里@我说:“这个月必须上线,不然双11前我们连婚纱照都拍不完了。”我一边啃着冷掉的煎饼果子,一边盯着VSCode里那坨祖传单体应用代码——Controller层2000行、Service层嵌套七层if-else、数据库连接池快被压爆……那一刻我真的想砸电脑。
但转念一想,咱可是备婚中的程序媛啊!白天跟婚庆公司battle场地布置,晚上还得给系统做“心脏搭桥手术”。为了保住头发(和婚假),我咬牙决定:把这坨单体应用拆成微服务!
为什么非得上Spring Cloud?
其实去年双11就埋过雷。当时促销活动一开,订单服务直接拖垮整个系统。运维小哥半夜打电话吼我:“你们Java服务又OOM了!K8s节点都给你干冒烟了!”后来复盘发现,所有业务模块挤在一个JVM里,一个慢查询就能让整个应用雪崩。
领导拍板要重构时,我偷偷翻了猎聘——果然,JD里清一色写着“精通Spring Cloud”。得,为了跳槽简历好看,也为了不让婚礼当天系统崩掉,Spring Cloud必须安排!
第一步:别被概念劝退
刚接触微服务时我也懵。Eureka、Nacos、Ribbon、Feign、Hystrix……名字比喜糖口味还多。但实际搭起来发现,核心就三件事:
- 服务注册与发现(谁在哪)
- 服务调用(怎么找人办事)
- 熔断限流(别让一个坑货拖垮全家)
咱们用最简配置跑通流程,再逐步加料。
实战:5分钟跑通服务注册
1. 搭建注册中心(Eureka Server)
// EurekaServerApplication.java
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
application.yml 配置:
server:
port: 8761 # 注册中心端口
eureka:
client:
register-with-eureka: false # 不注册自己
fetch-registry: false # 不拉取服务列表
💡 血泪教训:测试环境千万别开
register-with-eureka=true,否则注册中心会把自己注册进去形成闭环,CPU直接飙到100%!
2. 订单服务注册(Eureka Client)
// OrderServiceApplication.java
@EnableEurekaClient // 关键注解!
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
application.yml:
spring:
application:
name: order-service # 服务名,其他服务靠它找你
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/ # 注册中心地址
启动后访问 http://localhost:8761,看到ORDER-SERVICE亮绿灯那一刻,我激动得差点把咖啡洒在婚纱设计稿上!
服务调用:告别RestTemplate手写URL
以前调用户服务是这样的:
// 祖传代码警告!
String url = "http://192.168.1.100:8082/user/" + userId;
User user = restTemplate.getForObject(url, User.class);
IP写死、端口变更、负载均衡全靠运维改Nginx……直到用了 OpenFeign:
// 声明式调用,像调本地方法一样
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id") Long id);
}
// 在OrderService里直接注入
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public Order createOrder(Long userId) {
User user = userClient.getUserById(userId); // 看!没有URL!
// ...业务逻辑
}
}
面试题预警:
Q:Feign底层怎么实现的?
A:动态代理 + Ribbon负载均衡(后面会讲)
熔断降级:别让一个服务崩掉全家
有次用户服务慢查询,导致订单服务线程池耗尽,整个婚庆系统瘫痪。现在加上 Sentinel(比Hystrix更香):
@SentinelResource(
value = "createOrder",
fallback = "createOrderFallback" // 降级方法
)
public Order createOrder(Long userId) {
// 调用可能失败的远程服务
}
// 降级方法:参数和返回值要匹配
public Order createOrderFallback(Long userId, Throwable e) {
log.error("创建订单失败", e);
return Order.builder().status("FAILED").build(); // 返回兜底数据
}
在Sentinel控制台还能实时调整阈值:
| 资源名 | QPS阈值 | 降级策略 |
|---|---|---|
| createOrder | 100 | 异常比例 > 50% |
生产环境踩过的坑
服务名大小写问题
Linux服务器上user-service和User-Service是两个服务!统一用小写+中划线。配置中心没配好
别把数据库密码写死在application.yml里!赶紧上 Nacos Config:spring: cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml链路追踪救我狗命
加上 SkyWalking 后,终于能定位到是哪个服务拖慢了婚礼预约流程:[TRACE] order-service → payment-service → sms-service (耗时2.3s!)
给新人的建议
别追求一步到位
先拆出2-3个核心服务(比如订单、用户),跑通后再拆其他。我司第一版只拆了支付模块,稳了三个月才继续拆。日志必须带TraceID
用MDC把请求ID透传到所有服务,排查问题时能串起完整链路:// Feign拦截器自动传递TraceID @Bean public RequestInterceptor requestInterceptor() { return template -> template.header("X-Trace-ID", MDC.get("traceId")); }接口设计提前对齐
和前端、测试约好Swagger文档规范。别等联调时才发现对方要的是user_name你给的是userName—— 这种事我在婚礼筹备群吵过三次!
写在最后
现在婚庆系统稳定支撑每天5000+订单,上周还扛住了老板临时加的“七夕特惠”活动。虽然每天通勤1小时累成狗,但看到监控大盘上平稳的曲线,摸摸无名指上的戒指——值了!
微服务不是银弹,但绝对是应对业务增长的利器。如果你也在被单体应用折磨,或者正为面试突击Spring Cloud,不妨从今天开始拆第一个服务。记住:
“先跑起来,再优化。就像选婚纱——先穿上身,再改腰围。”
(P.S. 下期预告:《Spring Cloud Gateway实战:如何用JWT保护你的婚礼预约接口》——毕竟安全不能只靠新郎挡酒啊!)

评论 0