Spring Cloud从零开始:微服务入门指南

Vue快乐水
2025-12-15 00:53
阅读 541

上周五晚上十点半,我还在公司改婚庆系统的支付回调接口。项目经理在群里@我说:“这个月必须上线,不然双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……名字比喜糖口味还多。但实际搭起来发现,核心就三件事:

  1. 服务注册与发现(谁在哪)
  2. 服务调用(怎么找人办事)
  3. 熔断限流(别让一个坑货拖垮全家)

咱们用最简配置跑通流程,再逐步加料。


实战: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%

生产环境踩过的坑

  1. 服务名大小写问题
    Linux服务器上 user-serviceUser-Service 是两个服务!统一用小写+中划线。

  2. 配置中心没配好
    别把数据库密码写死在 application.yml 里!赶紧上 Nacos Config

    spring:
      cloud:
        nacos:
          config:
            server-addr: localhost:8848
            file-extension: yaml
    
  3. 链路追踪救我狗命
    加上 SkyWalking 后,终于能定位到是哪个服务拖慢了婚礼预约流程:

    [TRACE] order-service → payment-service → sms-service (耗时2.3s!)
    

给新人的建议

  1. 别追求一步到位
    先拆出2-3个核心服务(比如订单、用户),跑通后再拆其他。我司第一版只拆了支付模块,稳了三个月才继续拆。

  2. 日志必须带TraceID
    用MDC把请求ID透传到所有服务,排查问题时能串起完整链路:

    // Feign拦截器自动传递TraceID
    @Bean
    public RequestInterceptor requestInterceptor() {
        return template -> template.header("X-Trace-ID", MDC.get("traceId"));
    }
    
  3. 接口设计提前对齐
    和前端、测试约好Swagger文档规范。别等联调时才发现对方要的是 user_name 你给的是 userName —— 这种事我在婚礼筹备群吵过三次!


写在最后

现在婚庆系统稳定支撑每天5000+订单,上周还扛住了老板临时加的“七夕特惠”活动。虽然每天通勤1小时累成狗,但看到监控大盘上平稳的曲线,摸摸无名指上的戒指——值了!

微服务不是银弹,但绝对是应对业务增长的利器。如果你也在被单体应用折磨,或者正为面试突击Spring Cloud,不妨从今天开始拆第一个服务。记住:

“先跑起来,再优化。就像选婚纱——先穿上身,再改腰围。”

(P.S. 下期预告:《Spring Cloud Gateway实战:如何用JWT保护你的婚礼预约接口》——毕竟安全不能只靠新郎挡酒啊!)

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝