Spring Cloud从零开始:微服务入门指南
开篇:我们的项目背景与为何选择Spring Cloud

去年年初,我加入了一个新的项目组,负责开发一个面向金融行业的风控决策平台。这个系统需要支持多种数据源接入、规则引擎运行、模型调用和审批流程自动化,功能模块复杂度高,并且对性能、扩展性和稳定性都有较高要求。
我们当时的架构是典型的单体应用,代码已经臃肿不堪,部署周期长、更新困难。每次上线都需要整包打包部署,风险很高。再加上业务发展迅速,各种新需求频繁变更,旧架构逐渐难以支撑。
为了应对这些问题,项目组决定将系统拆分为多个独立的微服务,以提高可维护性和扩展性。在技术选型阶段,我们调研了Dubbo + Zookeeper、Kubernetes原生方案以及Spring Cloud生态,最终选择了Spring Cloud Alibaba + Nacos作为核心微服务解决方案。
为什么?不是因为赶时髦,而是因为我们希望有一套成熟、文档丰富、社区活跃又能快速上手的技术栈,而Spring Cloud刚好满足我们的需求。
这篇文章就想结合我们整个团队从零开始搭建微服务架构的过程,分享一下我们在使用Spring Cloud过程中的一些经验教训,希望能给刚起步的朋友一些启发。
问题描述:最初的困境

刚开始,我们遇到的问题并不少。
- 服务发现机制不熟悉,不知道怎么配置注册中心。
- 服务之间如何通信?RestTemplate vs Feign?有什么区别?
- 配置管理混乱,不同环境(开发、测试、生产)的配置该如何统一管理?
- 没有熔断机制,某个服务故障导致连锁反应。
- 网关路由配置不清楚,权限控制怎么加?
这些问题看似简单,但组合在一起后,就变得异常棘手。而且当时团队成员中,真正接触过Spring Cloud的人不多,基本都是边学边干。
最严重的一次事故发生在灰度发布时:A服务调用B服务失败,由于未配置熔断降级,A服务不断重试,导致线程池满,最终整个链路的服务都不可用。那一次直接让线上交易停摆了十几分钟,教训极其深刻。
解决方案:技术选型与架构设计

我们最终确定的技术栈如下:
- Nacos:作为服务注册与配置中心
- OpenFeign + Ribbon:服务间通信
- Sentinel:熔断限流
- Gateway:统一 API 网关,鉴权、限流等
- SkyWalking:服务监控与链路追踪(后来接入)
- RocketMQ:异步通信队列(后续加入)
微服务划分原则
在微服务拆分上,我们坚持“按业务边界来分”的原则。比如:
- 用户服务:处理用户信息相关逻辑
- 决策服务:负责规则引擎执行
- 数据采集服务:处理数据来源的对接
- 模型服务:封装算法模型调用
- 审批服务:流程编排与人工审核
每个服务各自拥有独立数据库,杜绝共享数据库的设计方式,这样可以最大限度减少服务间的耦合。
代码实践:从0到1的搭建过程
下面通过实际示例展示我们是如何一步一步搭建起这套体系的。
Step 1:Nacos 注册中心部署
首先我们部署了 Nacos 服务(建议采用集群部署,这里演示单机版):
wget https://github.com/alibaba/nacos/releases/download/v2.2.3/nacos-server-2.2.3.zip
unzip nacos-server-2.2.3.zip
cd nacos/bin
sh startup.sh -m standalone
启动完成后,访问 http://localhost:8848/nacos,默认账号密码是nacos/nacos。
Step 2:创建两个基础服务(user-service 和 order-service)
user-service 的 POM 配置(简化):
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
application.yml 配置:
server:
port: 8081
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
入口类加上注解:
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
同理创建order-service,并引入相同依赖。
Step 3:Feign 远程调用
定义 OrderFeignClient 接口:
@FeignClient(name = "user-service")
public interface UserFeignClient {
@GetMapping("/users/{id}")
ResponseEntity<User> getUserById(@PathVariable("id") Long id);
}
OrderController 调用:
@RestController
@RequestMapping("/orders")
public class OrderController {
private final UserFeignClient userFeignClient;
public OrderController(UserFeignClient userFeignClient) {
this.userFeignClient = userFeignClient;
}
@GetMapping("/{id}")
public ResponseEntity<OrderDTO> getOrderWithUser(@PathVariable String id) {
var userResponse = userFeignClient.getUserById(1L);
return ResponseEntity.ok(new OrderDTO(id, userResponse.getBody()));
}
}
看起来很简单,但这一步背后其实有负载均衡(Ribbon)和客户端容错机制(Sentinel/Hystrix),后面会讲踩坑点。
踩坑经验:那些让我们彻夜难眠的Bug
坑点一:Feign 默认不开启日志输出
调试服务调用的时候,我们一度很困惑,为什么请求就是走不到目标服务?
最后发现,原来 Feign 默认的日志级别很低,连错误信息都不打出来。
解决方法:
在application.yml中增加:
logging:
level:
com.example.client.UserFeignClient: DEBUG
或者启用 OpenFeign 日志拦截器:
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
这个小细节耽误了不少排查时间,提醒大家别忽略了日志配置的重要性。
坑点二:Feign调用找不到实例,报 LoadBalancerException
有时候我们本地启动服务后,Feign却始终无法找到目标服务,出现类似以下错误:
LoadBalancerException: No instances available for service
检查发现,原来是某些机器或环境中,host解析出了多个IP地址,导致Nacos获取的IP和服务注册的不一样。
解决办法:
强制指定服务注册使用的 IP 地址:
spring.cloud.nacos.discovery.ip: 192.168.1.100
spring.cloud.nacos.discovery.port: 8081
或者设置为本机 IP,确保注册的IP和服务访问的IP一致。
坑点三:Hystrix/Sentinel 熔断配置不合理
上线前做压力测试时,我们模拟了一波流量高峰,结果部分服务响应变慢,Feign调用超时堆积,最终导致雪崩效应。
我们紧急启用了 Sentinel 的熔断限流策略,在Feign调用中增加了 fallback 机制:
@FeignClient(name = "user-service", fallback = UserFeignClientFallback.class)
public interface UserFeignClient {}
fallback实现:
@Component
public class UserFeignClientFallback implements UserFeignClient {
@Override
public ResponseEntity<User> getUserById(Long id) {
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
}
}

同时,在 Gateway 层做了全局限流保护,防止突发流量击穿下游服务。
效果总结:我们收获了什么?
整个微服务改造完成后,我们对比了一下前后差异:
| 维度 | 单体时代 | 微服务改造后 |
|---|---|---|
| 部署效率 | 打包时间长,部署全量 | 各自独立部署,互不干扰 |
| 故障隔离能力 | 一挂全挂 | 单个服务出问题影响有限 |
| 技术演进灵活性 | 牵一发而动全身 | 各服务可灵活升级、替换语言 |
| 团队协作效率 | 多人改同一份代码冲突频发 | 各司其职,代码冲突大大减少 |
| 新需求响应速度 | 上线周期长达一周以上 | 一般3天内完成验证并发布 |
更重要的是,我们逐步建立了完善的 DevOps 流程,包括 CI/CD 自动化部署、服务健康监测、异常告警机制,提升了整体运维效率。
经验分享:送给正在入坑Spring Cloud的你
如果你刚接触微服务,想从Spring Cloud入手,这里是我总结的几点建议:
1. 先搞清楚概念,不要上来就写代码
Spring Cloud 生态非常庞大,里面涉及的概念很多:服务注册、服务发现、负载均衡、熔断器、API网关、分布式事务等等。如果不了解这些组件之间的关系,很容易迷失方向。
我的建议是先花一两天时间把整个技术栈的关系图理清楚,再从最小可用单元开始搭建,比如先跑通两个服务+注册中心,再逐步加上限流、熔断、网关等模块。
2. 尽早引入监控与日志聚合工具
微服务带来的最大的挑战之一就是运维成本上升。以前单体程序一个日志文件就能看懂;现在几十个服务,上百个实例,日志分散在各个机器上,查问题难度骤增。
我们后来接入了 SkyWalking 做链路追踪,ELK 做日志收集,Prometheus + Grafana 做指标监控,极大提升了问题排查效率。
3. 不要忽视接口设计和数据库设计
很多人只关注服务拆分,却不注意接口设计和数据库隔离。我们早期就犯过这种错误,导致后期服务间调用频繁、接口反复修改。
建议:
- 接口尽量保持稳定,对外提供版本化接口;
- 每个服务必须拥有自己的数据库;
- 服务间调用避免深层嵌套,可以通过事件驱动解耦(如 RocketMQ);
- 异常情况下要有 fallback 机制,避免服务雪崩。
4. 别忘了团队的沟通与协作
微服务不仅是技术上的事,更是组织结构、工作流程的调整。我们最初也是“各扫门前雪”,后来发现问题都在边界地带。
于是我们建立了“接口契约制”:服务间接口由双方共同评审,定期举行跨服务会议,确保接口一致性。
结语:成长是最好的礼物
回望这一年多的微服务之路,跌跌撞撞也走了过来。虽然一开始踩了很多坑,但正是这些挫折让我们更深入地理解了微服务的本质。
如果你也在微服务的路上前行,请记住一句话:
“不是所有的项目都适合微服务,但一旦决定出发,就要全力以赴。”
愿你的每一次服务拆分,都能带来更大的自由和更强的生命力。

评论 0